mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-19 21:10:12 +02:00
Merge remote-tracking branch 'upstream/develop' into develop
This commit is contained in:
commit
61fba1fedd
1
.github/workflows/github.yml
vendored
1
.github/workflows/github.yml
vendored
@ -17,6 +17,7 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- platform: linux-qt6
|
- platform: linux-qt6
|
||||||
|
@ -864,7 +864,7 @@ void AIGateway::makeTurn()
|
|||||||
|
|
||||||
void AIGateway::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
|
void AIGateway::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
|
||||||
{
|
{
|
||||||
LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->getNameTranslated() % obj->getObjectName() % obj->pos.toString());
|
LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->getNameTranslated() % obj->getObjectName() % obj->anchorPos().toString());
|
||||||
switch(obj->ID)
|
switch(obj->ID)
|
||||||
{
|
{
|
||||||
case Obj::TOWN:
|
case Obj::TOWN:
|
||||||
@ -1454,8 +1454,8 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
|
|||||||
|
|
||||||
void AIGateway::buildStructure(const CGTownInstance * t, BuildingID building)
|
void AIGateway::buildStructure(const CGTownInstance * t, BuildingID building)
|
||||||
{
|
{
|
||||||
auto name = t->town->buildings.at(building)->getNameTranslated();
|
auto name = t->getTown()->buildings.at(building)->getNameTranslated();
|
||||||
logAi->debug("Player %d will build %s in town of %s at %s", ai->playerID, name, t->getNameTranslated(), t->pos.toString());
|
logAi->debug("Player %d will build %s in town of %s at %s", ai->playerID, name, t->getNameTranslated(), t->anchorPos().toString());
|
||||||
cb->buildBuilding(t, building); //just do this;
|
cb->buildBuilding(t, building); //just do this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ std::vector<SlotInfo> ArmyManager::getBestArmy(const IBonusBearer * armyCarrier,
|
|||||||
|
|
||||||
for(auto & slot : sortedSlots)
|
for(auto & slot : sortedSlots)
|
||||||
{
|
{
|
||||||
alignmentMap[slot.creature->getFaction()] += slot.power;
|
alignmentMap[slot.creature->getFactionID()] += slot.power;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<FactionID> allowedFactions;
|
std::set<FactionID> allowedFactions;
|
||||||
@ -168,7 +168,7 @@ std::vector<SlotInfo> ArmyManager::getBestArmy(const IBonusBearer * armyCarrier,
|
|||||||
|
|
||||||
for(auto & slot : sortedSlots)
|
for(auto & slot : sortedSlots)
|
||||||
{
|
{
|
||||||
if(vstd::contains(allowedFactions, slot.creature->getFaction()))
|
if(vstd::contains(allowedFactions, slot.creature->getFactionID()))
|
||||||
{
|
{
|
||||||
auto slotID = newArmyInstance.getSlotFor(slot.creature->getId());
|
auto slotID = newArmyInstance.getSlotFor(slot.creature->getId());
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ namespace NKAI
|
|||||||
|
|
||||||
void BuildAnalyzer::updateTownDwellings(TownDevelopmentInfo & developmentInfo)
|
void BuildAnalyzer::updateTownDwellings(TownDevelopmentInfo & developmentInfo)
|
||||||
{
|
{
|
||||||
auto townInfo = developmentInfo.town->town;
|
auto townInfo = developmentInfo.town->getTown();
|
||||||
auto creatures = townInfo->creatures;
|
auto creatures = townInfo->creatures;
|
||||||
auto buildings = townInfo->getAllBuildings();
|
auto buildings = townInfo->getAllBuildings();
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ void BuildAnalyzer::updateTownDwellings(TownDevelopmentInfo & developmentInfo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int level = 0; level < developmentInfo.town->town->creatures.size(); level++)
|
for(int level = 0; level < developmentInfo.town->getTown()->creatures.size(); level++)
|
||||||
{
|
{
|
||||||
logAi->trace("Checking dwelling level %d", level);
|
logAi->trace("Checking dwelling level %d", level);
|
||||||
BuildingInfo nextToBuild = BuildingInfo();
|
BuildingInfo nextToBuild = BuildingInfo();
|
||||||
@ -88,7 +88,7 @@ void BuildAnalyzer::updateOtherBuildings(TownDevelopmentInfo & developmentInfo)
|
|||||||
{
|
{
|
||||||
for(auto & buildingID : buildingSet)
|
for(auto & buildingID : buildingSet)
|
||||||
{
|
{
|
||||||
if(!developmentInfo.town->hasBuilt(buildingID) && developmentInfo.town->town->buildings.count(buildingID))
|
if(!developmentInfo.town->hasBuilt(buildingID) && developmentInfo.town->getTown()->buildings.count(buildingID))
|
||||||
{
|
{
|
||||||
developmentInfo.addBuildingToBuild(getBuildingOrPrerequisite(developmentInfo.town, buildingID));
|
developmentInfo.addBuildingToBuild(getBuildingOrPrerequisite(developmentInfo.town, buildingID));
|
||||||
|
|
||||||
@ -203,7 +203,7 @@ BuildingInfo BuildAnalyzer::getBuildingOrPrerequisite(
|
|||||||
bool excludeDwellingDependencies) const
|
bool excludeDwellingDependencies) const
|
||||||
{
|
{
|
||||||
BuildingID building = toBuild;
|
BuildingID building = toBuild;
|
||||||
auto townInfo = town->town;
|
auto townInfo = town->getTown();
|
||||||
|
|
||||||
const CBuilding * buildPtr = townInfo->buildings.at(building);
|
const CBuilding * buildPtr = townInfo->buildings.at(building);
|
||||||
const CCreature * creature = nullptr;
|
const CCreature * creature = nullptr;
|
||||||
@ -346,7 +346,7 @@ bool BuildAnalyzer::hasAnyBuilding(int32_t alignment, BuildingID bid) const
|
|||||||
{
|
{
|
||||||
for(auto tdi : developmentInfos)
|
for(auto tdi : developmentInfos)
|
||||||
{
|
{
|
||||||
if(tdi.town->getFaction() == alignment && tdi.town->hasBuilt(bid))
|
if(tdi.town->getFactionID() == alignment && tdi.town->hasBuilt(bid))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ float HeroManager::evaluateSecSkill(SecondarySkill skill, const CGHeroInstance *
|
|||||||
|
|
||||||
float HeroManager::evaluateSpeciality(const CGHeroInstance * hero) const
|
float HeroManager::evaluateSpeciality(const CGHeroInstance * hero) const
|
||||||
{
|
{
|
||||||
auto heroSpecial = Selector::source(BonusSource::HERO_SPECIAL, BonusSourceID(hero->type->getId()));
|
auto heroSpecial = Selector::source(BonusSource::HERO_SPECIAL, BonusSourceID(hero->getHeroTypeID()));
|
||||||
auto secondarySkillBonus = Selector::targetSourceType()(BonusSource::SECONDARY_SKILL);
|
auto secondarySkillBonus = Selector::targetSourceType()(BonusSource::SECONDARY_SKILL);
|
||||||
auto specialSecondarySkillBonuses = hero->getBonuses(heroSpecial.And(secondarySkillBonus));
|
auto specialSecondarySkillBonuses = hero->getBonuses(heroSpecial.And(secondarySkillBonus));
|
||||||
auto secondarySkillBonuses = hero->getBonuses(Selector::sourceTypeSel(BonusSource::SECONDARY_SKILL));
|
auto secondarySkillBonuses = hero->getBonuses(Selector::sourceTypeSel(BonusSource::SECONDARY_SKILL));
|
||||||
|
@ -1244,7 +1244,7 @@ public:
|
|||||||
|
|
||||||
uint64_t RewardEvaluator::getUpgradeArmyReward(const CGTownInstance * town, const BuildingInfo & bi) const
|
uint64_t RewardEvaluator::getUpgradeArmyReward(const CGTownInstance * town, const BuildingInfo & bi) const
|
||||||
{
|
{
|
||||||
if(ai->buildAnalyzer->hasAnyBuilding(town->getFaction(), bi.id))
|
if(ai->buildAnalyzer->hasAnyBuilding(town->getFactionID(), bi.id))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
auto creaturesToUpgrade = ai->armyManager->getTotalCreaturesAvailable(bi.baseCreatureID);
|
auto creaturesToUpgrade = ai->armyManager->getTotalCreaturesAvailable(bi.baseCreatureID);
|
||||||
|
@ -23,7 +23,7 @@ BuildThis::BuildThis(BuildingID Bid, const CGTownInstance * tid)
|
|||||||
: ElementarGoal(Goals::BUILD_STRUCTURE)
|
: ElementarGoal(Goals::BUILD_STRUCTURE)
|
||||||
{
|
{
|
||||||
buildingInfo = BuildingInfo(
|
buildingInfo = BuildingInfo(
|
||||||
tid->town->buildings.at(Bid),
|
tid->getTown()->buildings.at(Bid),
|
||||||
nullptr,
|
nullptr,
|
||||||
CreatureID::NONE,
|
CreatureID::NONE,
|
||||||
tid,
|
tid,
|
||||||
@ -52,7 +52,7 @@ void BuildThis::accept(AIGateway * ai)
|
|||||||
if(cb->canBuildStructure(town, b) == EBuildingState::ALLOWED)
|
if(cb->canBuildStructure(town, b) == EBuildingState::ALLOWED)
|
||||||
{
|
{
|
||||||
logAi->debug("Player %d will build %s in town of %s at %s",
|
logAi->debug("Player %d will build %s in town of %s at %s",
|
||||||
ai->playerID, town->town->buildings.at(b)->getNameTranslated(), town->getNameTranslated(), town->pos.toString());
|
ai->playerID, town->getTown()->buildings.at(b)->getNameTranslated(), town->getNameTranslated(), town->anchorPos().toString());
|
||||||
cb->buildBuilding(town, b);
|
cb->buildBuilding(town, b);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -23,13 +23,13 @@ bool BuildingManager::tryBuildThisStructure(const CGTownInstance * t, BuildingID
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vstd::contains(t->town->buildings, building))
|
if (!vstd::contains(t->getTown()->buildings, building))
|
||||||
return false; // no such building in town
|
return false; // no such building in town
|
||||||
|
|
||||||
if (t->hasBuilt(building)) //Already built? Shouldn't happen in general
|
if (t->hasBuilt(building)) //Already built? Shouldn't happen in general
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const CBuilding * buildPtr = t->town->buildings.at(building);
|
const CBuilding * buildPtr = t->getTown()->buildings.at(building);
|
||||||
|
|
||||||
auto toBuild = buildPtr->requirements.getFulfillmentCandidates([&](const BuildingID & buildID)
|
auto toBuild = buildPtr->requirements.getFulfillmentCandidates([&](const BuildingID & buildID)
|
||||||
{
|
{
|
||||||
@ -51,7 +51,7 @@ bool BuildingManager::tryBuildThisStructure(const CGTownInstance * t, BuildingID
|
|||||||
|
|
||||||
for (const auto & buildID : toBuild)
|
for (const auto & buildID : toBuild)
|
||||||
{
|
{
|
||||||
const CBuilding * b = t->town->buildings.at(buildID);
|
const CBuilding * b = t->getTown()->buildings.at(buildID);
|
||||||
|
|
||||||
EBuildingState canBuild = cb->canBuildStructure(t, buildID);
|
EBuildingState canBuild = cb->canBuildStructure(t, buildID);
|
||||||
if (canBuild == EBuildingState::ALLOWED)
|
if (canBuild == EBuildingState::ALLOWED)
|
||||||
@ -220,7 +220,7 @@ bool BuildingManager::getBuildingOptions(const CGTownInstance * t)
|
|||||||
|
|
||||||
//at the end, try to get and build any extra buildings with nonstandard slots (for example HotA 3rd level dwelling)
|
//at the end, try to get and build any extra buildings with nonstandard slots (for example HotA 3rd level dwelling)
|
||||||
std::vector<BuildingID> extraBuildings;
|
std::vector<BuildingID> extraBuildings;
|
||||||
for (auto buildingInfo : t->town->buildings)
|
for (auto buildingInfo : t->getTown()->buildings)
|
||||||
{
|
{
|
||||||
if (buildingInfo.first > BuildingID::DWELL_UP2_FIRST)
|
if (buildingInfo.first > BuildingID::DWELL_UP2_FIRST)
|
||||||
extraBuildings.push_back(buildingInfo.first);
|
extraBuildings.push_back(buildingInfo.first);
|
||||||
|
@ -56,7 +56,7 @@ TSubgoal BuildThis::whatToDoToAchieve()
|
|||||||
case EBuildingState::ALLOWED:
|
case EBuildingState::ALLOWED:
|
||||||
case EBuildingState::NO_RESOURCES:
|
case EBuildingState::NO_RESOURCES:
|
||||||
{
|
{
|
||||||
auto res = town->town->buildings.at(BuildingID(bid))->resources;
|
auto res = town->getTown()->buildings.at(BuildingID(bid))->resources;
|
||||||
return ai->ah->whatToDo(res, iAmElementar()); //realize immediately or gather resources
|
return ai->ah->whatToDo(res, iAmElementar()); //realize immediately or gather resources
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -46,7 +46,7 @@ TSubgoal FindObj::whatToDoToAchieve()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(o && ai->isAccessible(o->pos)) //we don't use isAccessibleForHero as we don't know which hero it is
|
if(o && ai->isAccessible(o->visitablePos())) //we don't use isAccessibleForHero as we don't know which hero it is
|
||||||
return sptr(VisitObj(o->id.getNum()));
|
return sptr(VisitObj(o->id.getNum()));
|
||||||
else
|
else
|
||||||
return sptr(Explore());
|
return sptr(Explore());
|
||||||
|
@ -88,13 +88,13 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto creature = VLC->creatures()->getByIndex(objid);
|
auto creature = VLC->creatures()->getByIndex(objid);
|
||||||
if(t->getFaction() == creature->getFaction()) //TODO: how to force AI to build unupgraded creatures? :O
|
if(t->getFactionID() == creature->getFactionID()) //TODO: how to force AI to build unupgraded creatures? :O
|
||||||
{
|
{
|
||||||
auto tryFindCreature = [&]() -> std::optional<std::vector<CreatureID>>
|
auto tryFindCreature = [&]() -> std::optional<std::vector<CreatureID>>
|
||||||
{
|
{
|
||||||
if(vstd::isValidIndex(t->town->creatures, creature->getLevel() - 1))
|
if(vstd::isValidIndex(t->getTown()->creatures, creature->getLevel() - 1))
|
||||||
{
|
{
|
||||||
auto itr = t->town->creatures.begin();
|
auto itr = t->getTown()->creatures.begin();
|
||||||
std::advance(itr, creature->getLevel() - 1);
|
std::advance(itr, creature->getLevel() - 1);
|
||||||
return make_optional(*itr);
|
return make_optional(*itr);
|
||||||
}
|
}
|
||||||
@ -109,7 +109,7 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
|
|||||||
if(upgradeNumber < 0)
|
if(upgradeNumber < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
BuildingID bid(BuildingID::DWELL_FIRST + creature->getLevel() - 1 + upgradeNumber * t->town->creatures.size());
|
BuildingID bid(BuildingID::DWELL_FIRST + creature->getLevel() - 1 + upgradeNumber * t->getTown()->creatures.size());
|
||||||
if(t->hasBuilt(bid) && ai->ah->freeResources().canAfford(creature->getFullRecruitCost())) //this assumes only creatures with dwellings are assigned to faction
|
if(t->hasBuilt(bid) && ai->ah->freeResources().canAfford(creature->getFullRecruitCost())) //this assumes only creatures with dwellings are assigned to faction
|
||||||
{
|
{
|
||||||
solutions.push_back(sptr(BuyArmy(t, creature->getAIValue() * this->value).setobjid(objid)));
|
solutions.push_back(sptr(BuyArmy(t, creature->getAIValue() * this->value).setobjid(objid)));
|
||||||
|
@ -69,7 +69,7 @@ std::optional<int> MapObjectsEvaluator::getObjectValue(const CGObjectInstance *
|
|||||||
{
|
{
|
||||||
//special case handling: in-game heroes have hero ID as object subID, but when reading configs available hero object subID's are hero classes
|
//special case handling: in-game heroes have hero ID as object subID, but when reading configs available hero object subID's are hero classes
|
||||||
auto hero = dynamic_cast<const CGHeroInstance*>(obj);
|
auto hero = dynamic_cast<const CGHeroInstance*>(obj);
|
||||||
return getObjectValue(obj->ID, hero->type->heroClass->getIndex());
|
return getObjectValue(obj->ID, hero->getHeroClassID());
|
||||||
}
|
}
|
||||||
else if(obj->ID == Obj::PRISON)
|
else if(obj->ID == Obj::PRISON)
|
||||||
{
|
{
|
||||||
|
@ -1032,7 +1032,7 @@ void VCAI::mainLoop()
|
|||||||
|
|
||||||
void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
|
void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
|
||||||
{
|
{
|
||||||
LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->getNameTranslated() % obj->getObjectName() % obj->pos.toString());
|
LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->getNameTranslated() % obj->getObjectName() % obj->anchorPos().toString());
|
||||||
switch(obj->ID)
|
switch(obj->ID)
|
||||||
{
|
{
|
||||||
case Obj::TOWN:
|
case Obj::TOWN:
|
||||||
@ -1417,11 +1417,11 @@ void VCAI::wander(HeroPtr h)
|
|||||||
//TODO pick the truly best
|
//TODO pick the truly best
|
||||||
const CGTownInstance * t = *boost::max_element(townsNotReachable, compareReinforcements);
|
const CGTownInstance * t = *boost::max_element(townsNotReachable, compareReinforcements);
|
||||||
logAi->debug("%s can't reach any town, we'll try to make our way to %s at %s", h->getNameTranslated(), t->getNameTranslated(), t->visitablePos().toString());
|
logAi->debug("%s can't reach any town, we'll try to make our way to %s at %s", h->getNameTranslated(), t->getNameTranslated(), t->visitablePos().toString());
|
||||||
int3 pos1 = h->pos;
|
int3 posBefore = h->visitablePos();
|
||||||
striveToGoal(sptr(Goals::ClearWayTo(t->visitablePos()).sethero(h))); //TODO: drop "strive", add to mainLoop
|
striveToGoal(sptr(Goals::ClearWayTo(t->visitablePos()).sethero(h))); //TODO: drop "strive", add to mainLoop
|
||||||
//if out hero is stuck, we may need to request another hero to clear the way we see
|
//if out hero is stuck, we may need to request another hero to clear the way we see
|
||||||
|
|
||||||
if(pos1 == h->pos && h == primaryHero()) //hero can't move
|
if(posBefore == h->visitablePos() && h == primaryHero()) //hero can't move
|
||||||
{
|
{
|
||||||
if(canRecruitAnyHero(t))
|
if(canRecruitAnyHero(t))
|
||||||
recruitHero(t);
|
recruitHero(t);
|
||||||
@ -1471,7 +1471,7 @@ void VCAI::wander(HeroPtr h)
|
|||||||
{
|
{
|
||||||
auto chosenObject = cb->getObjInstance(ObjectInstanceID(bestObjectGoal->objid));
|
auto chosenObject = cb->getObjInstance(ObjectInstanceID(bestObjectGoal->objid));
|
||||||
if(chosenObject != nullptr)
|
if(chosenObject != nullptr)
|
||||||
logAi->debug("Of all %d destinations, object %s at pos=%s seems nice", dests.size(), chosenObject->getObjectName(), chosenObject->pos.toString());
|
logAi->debug("Of all %d destinations, object %s at pos=%s seems nice", dests.size(), chosenObject->getObjectName(), chosenObject->anchorPos().toString());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
logAi->debug("Trying to realize goal of type %s as part of wandering.", bestObjectGoal->name());
|
logAi->debug("Trying to realize goal of type %s as part of wandering.", bestObjectGoal->name());
|
||||||
@ -1994,8 +1994,8 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
|||||||
|
|
||||||
void VCAI::buildStructure(const CGTownInstance * t, BuildingID building)
|
void VCAI::buildStructure(const CGTownInstance * t, BuildingID building)
|
||||||
{
|
{
|
||||||
auto name = t->town->buildings.at(building)->getNameTranslated();
|
auto name = t->getTown()->buildings.at(building)->getNameTranslated();
|
||||||
logAi->debug("Player %d will build %s in town of %s at %s", ai->playerID, name, t->getNameTranslated(), t->pos.toString());
|
logAi->debug("Player %d will build %s in town of %s at %s", ai->playerID, name, t->getNameTranslated(), t->anchorPos().toString());
|
||||||
cb->buildBuilding(t, building); //just do this;
|
cb->buildBuilding(t, building); //just do this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2081,7 +2081,7 @@ void VCAI::tryRealize(Goals::BuildThis & g)
|
|||||||
if (cb->canBuildStructure(t, b) == EBuildingState::ALLOWED)
|
if (cb->canBuildStructure(t, b) == EBuildingState::ALLOWED)
|
||||||
{
|
{
|
||||||
logAi->debug("Player %d will build %s in town of %s at %s",
|
logAi->debug("Player %d will build %s in town of %s at %s",
|
||||||
playerID, t->town->buildings.at(b)->getNameTranslated(), t->getNameTranslated(), t->pos.toString());
|
playerID, t->getTown()->buildings.at(b)->getNameTranslated(), t->getNameTranslated(), t->anchorPos().toString());
|
||||||
cb->buildBuilding(t, b);
|
cb->buildBuilding(t, b);
|
||||||
throw goalFulfilledException(sptr(g));
|
throw goalFulfilledException(sptr(g));
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "lib/UnlockGuard.h"
|
#include "lib/UnlockGuard.h"
|
||||||
#include "lib/battle/BattleInfo.h"
|
#include "lib/battle/BattleInfo.h"
|
||||||
#include "lib/networkPacks/PacksForServer.h"
|
#include "lib/networkPacks/PacksForServer.h"
|
||||||
|
#include "lib/networkPacks/SaveLocalState.h"
|
||||||
|
|
||||||
bool CCallback::teleportHero(const CGHeroInstance *who, const CGTownInstance *where)
|
bool CCallback::teleportHero(const CGHeroInstance *who, const CGTownInstance *where)
|
||||||
{
|
{
|
||||||
@ -318,11 +319,20 @@ void CCallback::recruitHero(const CGObjectInstance *townOrTavern, const CGHeroIn
|
|||||||
assert(townOrTavern);
|
assert(townOrTavern);
|
||||||
assert(hero);
|
assert(hero);
|
||||||
|
|
||||||
HireHero pack(hero->getHeroType(), townOrTavern->id, nextHero);
|
HireHero pack(hero->getHeroTypeID(), townOrTavern->id, nextHero);
|
||||||
pack.player = *player;
|
pack.player = *player;
|
||||||
sendRequest(pack);
|
sendRequest(pack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CCallback::saveLocalState(const JsonNode & data)
|
||||||
|
{
|
||||||
|
SaveLocalState state;
|
||||||
|
state.data = data;
|
||||||
|
state.player = *player;
|
||||||
|
|
||||||
|
sendRequest(state);
|
||||||
|
}
|
||||||
|
|
||||||
void CCallback::save( const std::string &fname )
|
void CCallback::save( const std::string &fname )
|
||||||
{
|
{
|
||||||
cl->save(fname);
|
cl->save(fname);
|
||||||
|
@ -100,6 +100,7 @@ public:
|
|||||||
virtual void assembleArtifacts(const ObjectInstanceID & heroID, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo)=0;
|
virtual void assembleArtifacts(const ObjectInstanceID & heroID, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo)=0;
|
||||||
virtual void eraseArtifactByClient(const ArtifactLocation & al)=0;
|
virtual void eraseArtifactByClient(const ArtifactLocation & al)=0;
|
||||||
virtual bool dismissCreature(const CArmedInstance *obj, SlotID stackPos)=0;
|
virtual bool dismissCreature(const CArmedInstance *obj, SlotID stackPos)=0;
|
||||||
|
virtual void saveLocalState(const JsonNode & data)=0;
|
||||||
virtual void endTurn()=0;
|
virtual void endTurn()=0;
|
||||||
virtual void buyArtifact(const CGHeroInstance *hero, ArtifactID aid)=0; //used to buy artifacts in towns (including spell book in the guild and war machines in blacksmith)
|
virtual void buyArtifact(const CGHeroInstance *hero, ArtifactID aid)=0; //used to buy artifacts in towns (including spell book in the guild and war machines in blacksmith)
|
||||||
virtual void setFormation(const CGHeroInstance * hero, EArmyFormation mode)=0;
|
virtual void setFormation(const CGHeroInstance * hero, EArmyFormation mode)=0;
|
||||||
@ -193,6 +194,7 @@ public:
|
|||||||
void recruitCreatures(const CGDwelling * obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level=-1) override;
|
void recruitCreatures(const CGDwelling * obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level=-1) override;
|
||||||
bool dismissCreature(const CArmedInstance *obj, SlotID stackPos) override;
|
bool dismissCreature(const CArmedInstance *obj, SlotID stackPos) override;
|
||||||
bool upgradeCreature(const CArmedInstance *obj, SlotID stackPos, CreatureID newID=CreatureID::NONE) override;
|
bool upgradeCreature(const CArmedInstance *obj, SlotID stackPos, CreatureID newID=CreatureID::NONE) override;
|
||||||
|
void saveLocalState(const JsonNode & data) override;
|
||||||
void endTurn() override;
|
void endTurn() override;
|
||||||
void spellResearch(const CGTownInstance *town, SpellID spellAtSlot, bool accepted) override;
|
void spellResearch(const CGTownInstance *town, SpellID spellAtSlot, bool accepted) override;
|
||||||
void swapGarrisonHero(const CGTownInstance *town) override;
|
void swapGarrisonHero(const CGTownInstance *town) override;
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
"vcmi.adventureMap.monsterThreat.levels.10" : "Dödlig",
|
"vcmi.adventureMap.monsterThreat.levels.10" : "Dödlig",
|
||||||
"vcmi.adventureMap.monsterThreat.levels.11" : "Omöjlig",
|
"vcmi.adventureMap.monsterThreat.levels.11" : "Omöjlig",
|
||||||
"vcmi.adventureMap.monsterLevel" : "\n\nNivå: %LEVEL - Faktion: %TOWN",
|
"vcmi.adventureMap.monsterLevel" : "\n\nNivå: %LEVEL - Faktion: %TOWN",
|
||||||
|
"vcmi.adventureMap.monsterMeleeType" : "närstrid",
|
||||||
|
"vcmi.adventureMap.monsterRangedType" : "fjärrstrid",
|
||||||
|
|
||||||
"vcmi.adventureMap.confirmRestartGame" : "Är du säker på att du vill starta om spelet?",
|
"vcmi.adventureMap.confirmRestartGame" : "Är du säker på att du vill starta om spelet?",
|
||||||
"vcmi.adventureMap.noTownWithMarket" : "Det finns inga tillgängliga marknadsplatser!",
|
"vcmi.adventureMap.noTownWithMarket" : "Det finns inga tillgängliga marknadsplatser!",
|
||||||
@ -21,7 +23,7 @@
|
|||||||
"vcmi.adventureMap.playerAttacked" : "Spelare har blivit attackerad: %s",
|
"vcmi.adventureMap.playerAttacked" : "Spelare har blivit attackerad: %s",
|
||||||
"vcmi.adventureMap.moveCostDetails" : "Förflyttningspoängs-kostnad: %TURNS tur(er) + %POINTS poäng - Återstående poäng: %REMAINING",
|
"vcmi.adventureMap.moveCostDetails" : "Förflyttningspoängs-kostnad: %TURNS tur(er) + %POINTS poäng - Återstående poäng: %REMAINING",
|
||||||
"vcmi.adventureMap.moveCostDetailsNoTurns" : "Förflyttningspoängs-kostnad: %POINTS poäng - Återstående poäng: %REMAINING",
|
"vcmi.adventureMap.moveCostDetailsNoTurns" : "Förflyttningspoängs-kostnad: %POINTS poäng - Återstående poäng: %REMAINING",
|
||||||
"vcmi.adventureMap.movementPointsHeroInfo" : "(Förflyttningspoäng: %REMAINING / %POINTS)",
|
"vcmi.adventureMap.movementPointsHeroInfo" : "(Förflyttningspoäng: %REMAINING / %POINTS)",
|
||||||
"vcmi.adventureMap.replayOpponentTurnNotImplemented" : "Tyvärr, att spela om motståndarens tur är inte implementerat ännu!",
|
"vcmi.adventureMap.replayOpponentTurnNotImplemented" : "Tyvärr, att spela om motståndarens tur är inte implementerat ännu!",
|
||||||
|
|
||||||
"vcmi.capitalColors.0" : "Röd",
|
"vcmi.capitalColors.0" : "Röd",
|
||||||
@ -135,14 +137,15 @@
|
|||||||
"vcmi.lobby.pvp.coin.hover" : "Mynt",
|
"vcmi.lobby.pvp.coin.hover" : "Mynt",
|
||||||
"vcmi.lobby.pvp.coin.help" : "Singla slant",
|
"vcmi.lobby.pvp.coin.help" : "Singla slant",
|
||||||
"vcmi.lobby.pvp.randomTown.hover" : "Slumpmässig stad",
|
"vcmi.lobby.pvp.randomTown.hover" : "Slumpmässig stad",
|
||||||
"vcmi.lobby.pvp.randomTown.help" : "Skriv en slumpmässig stad i chatten",
|
"vcmi.lobby.pvp.randomTown.help" : "Skriv en slumpad stad i chatten",
|
||||||
"vcmi.lobby.pvp.randomTownVs.hover" : "Slumpmässig stad vs.",
|
"vcmi.lobby.pvp.randomTownVs.hover" : "Slumpad stad vs.",
|
||||||
"vcmi.lobby.pvp.randomTownVs.help" : "Skriv två slumpmässiga städer i chatten",
|
"vcmi.lobby.pvp.randomTownVs.help" : "Skriv två slumpade städer i chatten",
|
||||||
"vcmi.lobby.pvp.versus" : "vs.",
|
"vcmi.lobby.pvp.versus" : "vs.",
|
||||||
|
|
||||||
"vcmi.client.errors.invalidMap" : "{Ogiltig karta eller kampanj}\n\nStartade inte spelet! Vald karta eller kampanj kan vara ogiltig eller skadad. Orsak:\n%s",
|
"vcmi.client.errors.invalidMap" : "{Ogiltig karta eller kampanj}\n\nStartade inte spelet! Vald karta eller kampanj kan vara ogiltig eller skadad. Orsak:\n%s",
|
||||||
"vcmi.client.errors.missingCampaigns" : "{Saknade datafiler}\n\nKampanjernas datafiler hittades inte! Du kanske använder ofullständiga eller skadade Heroes 3-datafiler. Vänligen installera om speldata.",
|
"vcmi.client.errors.missingCampaigns" : "{Saknade datafiler}\n\nKampanjernas datafiler hittades inte! Du kanske använder ofullständiga eller skadade Heroes 3-datafiler. Vänligen installera om speldata.",
|
||||||
"vcmi.server.errors.disconnected" : "{Nätverksfel}\n\nAnslutningen till spelservern har förlorats!",
|
"vcmi.server.errors.disconnected" : "{Nätverksfel}\n\nAnslutningen till spelservern har förlorats!",
|
||||||
|
"vcmi.server.errors.playerLeft" : "{Spelare har lämnat}\n\n%s spelaren har kopplat bort sig från spelet!", //%s -> spelarens färg
|
||||||
"vcmi.server.errors.existingProcess" : "En annan VCMI-serverprocess är igång. Vänligen avsluta den innan du startar ett nytt spel.",
|
"vcmi.server.errors.existingProcess" : "En annan VCMI-serverprocess är igång. Vänligen avsluta den innan du startar ett nytt spel.",
|
||||||
"vcmi.server.errors.modsToEnable" : "{Följande modd(ar) krävs}",
|
"vcmi.server.errors.modsToEnable" : "{Följande modd(ar) krävs}",
|
||||||
"vcmi.server.errors.modsToDisable" : "{Följande modd(ar) måste inaktiveras}",
|
"vcmi.server.errors.modsToDisable" : "{Följande modd(ar) måste inaktiveras}",
|
||||||
@ -221,8 +224,8 @@
|
|||||||
"vcmi.systemOptions.enableUiEnhancementsButton.help" : "{Gränssnittsförbättringar}\n\nVälj mellan olika förbättringar av användargränssnittet. Till exempel en lättåtkomlig ryggsäcksknapp med mera. Avaktivera för att få en mer klassisk spelupplevelse.",
|
"vcmi.systemOptions.enableUiEnhancementsButton.help" : "{Gränssnittsförbättringar}\n\nVälj mellan olika förbättringar av användargränssnittet. Till exempel en lättåtkomlig ryggsäcksknapp med mera. Avaktivera för att få en mer klassisk spelupplevelse.",
|
||||||
"vcmi.systemOptions.enableLargeSpellbookButton.hover" : "Stor trollformelsbok",
|
"vcmi.systemOptions.enableLargeSpellbookButton.hover" : "Stor trollformelsbok",
|
||||||
"vcmi.systemOptions.enableLargeSpellbookButton.help" : "{Stor trollformelsbok}\n\nAktiverar en större trollformelsbok som rymmer fler trollformler per sida (animeringen av sidbyte i den större trollformelsboken fungerar inte).",
|
"vcmi.systemOptions.enableLargeSpellbookButton.help" : "{Stor trollformelsbok}\n\nAktiverar en större trollformelsbok som rymmer fler trollformler per sida (animeringen av sidbyte i den större trollformelsboken fungerar inte).",
|
||||||
"vcmi.systemOptions.audioMuteFocus.hover" : "Stänger av ljudet vid inaktivitet",
|
"vcmi.systemOptions.audioMuteFocus.hover" : "Tyst vid inaktivitet",
|
||||||
"vcmi.systemOptions.audioMuteFocus.help" : "{Stäng av ljud vid inaktivitet}\n\nStänger av ljudet i spelet vid inaktivitet. Undantag är meddelanden i spelet och ljudet för ny tur/omgång.",
|
"vcmi.systemOptions.audioMuteFocus.help" : "{Tyst vid inaktivitet}\n\nStänger av ljudet i spelet vid inaktivitet. Undantag är meddelanden i spelet och ljudet för ny turomgång.",
|
||||||
|
|
||||||
"vcmi.adventureOptions.infoBarPick.hover" : "Visar textmeddelanden i infopanelen",
|
"vcmi.adventureOptions.infoBarPick.hover" : "Visar textmeddelanden i infopanelen",
|
||||||
"vcmi.adventureOptions.infoBarPick.help" : "{Infopanelsmeddelanden}\n\nNär det är möjligt kommer spelmeddelanden från besökande kartobjekt att visas i infopanelen istället för att dyka upp i ett separat fönster.",
|
"vcmi.adventureOptions.infoBarPick.help" : "{Infopanelsmeddelanden}\n\nNär det är möjligt kommer spelmeddelanden från besökande kartobjekt att visas i infopanelen istället för att dyka upp i ett separat fönster.",
|
||||||
@ -234,11 +237,11 @@
|
|||||||
"vcmi.adventureOptions.showGrid.help" : "{Visa rutnät}\n\nVisa rutnätsöverlägget som markerar gränserna mellan äventyrskartans brickor/rutor.",
|
"vcmi.adventureOptions.showGrid.help" : "{Visa rutnät}\n\nVisa rutnätsöverlägget som markerar gränserna mellan äventyrskartans brickor/rutor.",
|
||||||
"vcmi.adventureOptions.borderScroll.hover" : "Kantrullning",
|
"vcmi.adventureOptions.borderScroll.hover" : "Kantrullning",
|
||||||
"vcmi.adventureOptions.borderScroll.help" : "{Kantrullning}\n\nRullar äventyrskartan när markören är angränsande till fönsterkanten. Kan inaktiveras genom att hålla ned CTRL-tangenten.",
|
"vcmi.adventureOptions.borderScroll.help" : "{Kantrullning}\n\nRullar äventyrskartan när markören är angränsande till fönsterkanten. Kan inaktiveras genom att hålla ned CTRL-tangenten.",
|
||||||
"vcmi.adventureOptions.infoBarCreatureManagement.hover" : "Hantering av varelser i infopanelen i nedre högra hörnet",
|
"vcmi.adventureOptions.infoBarCreatureManagement.hover" : "Hantera armén i nedre högra hörnet",
|
||||||
"vcmi.adventureOptions.infoBarCreatureManagement.help" : "{Varelsehantering i infopanelen}\n\nTillåter omarrangering av varelser i infopanelen längst ner till höger på äventyrskartan istället för att bläddra mellan olika infopaneler.",
|
"vcmi.adventureOptions.infoBarCreatureManagement.help" : "{Varelsehantering i infopanelen}\n\nTillåter omarrangering av varelser i infopanelen längst ner till höger på äventyrskartan istället för att bläddra mellan olika infopaneler.",
|
||||||
"vcmi.adventureOptions.leftButtonDrag.hover" : "Dra kartan med vänster musknapp",
|
"vcmi.adventureOptions.leftButtonDrag.hover" : "V.klicksdragning",
|
||||||
"vcmi.adventureOptions.leftButtonDrag.help" : "{Vänsterklicksdragning}\n\nVid aktivering kan äventyrskartans kartvy dras genom att flytta musen med vänster musknapp nedtryckt.",
|
"vcmi.adventureOptions.leftButtonDrag.help" : "{Vänsterklicksdragning}\n\nVid aktivering kan äventyrskartans kartvy dras genom att flytta musen med vänster musknapp nedtryckt.",
|
||||||
"vcmi.adventureOptions.rightButtonDrag.hover" : "Dra kartan med höger musknapp",
|
"vcmi.adventureOptions.rightButtonDrag.hover" : "H.klicksdragning",
|
||||||
"vcmi.adventureOptions.rightButtonDrag.help" : "{Högerklicksdragning}\n\nVid aktivering kan äventyrskartans kartvy dras genom att flytta musen med höger musknapp nedtryckt.",
|
"vcmi.adventureOptions.rightButtonDrag.help" : "{Högerklicksdragning}\n\nVid aktivering kan äventyrskartans kartvy dras genom att flytta musen med höger musknapp nedtryckt.",
|
||||||
"vcmi.adventureOptions.smoothDragging.hover" : "Mjuk kartdragning",
|
"vcmi.adventureOptions.smoothDragging.hover" : "Mjuk kartdragning",
|
||||||
"vcmi.adventureOptions.smoothDragging.help" : "{Mjuk kartdragning}\n\nVid aktivering så har kartdragningen en modern rullningseffekt.",
|
"vcmi.adventureOptions.smoothDragging.help" : "{Mjuk kartdragning}\n\nVid aktivering så har kartdragningen en modern rullningseffekt.",
|
||||||
@ -268,16 +271,16 @@
|
|||||||
"vcmi.battleOptions.animationsSpeed1.help" : "Ställ in animationshastigheten till mycket långsam.",
|
"vcmi.battleOptions.animationsSpeed1.help" : "Ställ in animationshastigheten till mycket långsam.",
|
||||||
"vcmi.battleOptions.animationsSpeed5.help" : "Ställ in animationshastigheten till mycket snabb.",
|
"vcmi.battleOptions.animationsSpeed5.help" : "Ställ in animationshastigheten till mycket snabb.",
|
||||||
"vcmi.battleOptions.animationsSpeed6.help" : "Ställ in animationshastigheten till omedelbar.",
|
"vcmi.battleOptions.animationsSpeed6.help" : "Ställ in animationshastigheten till omedelbar.",
|
||||||
"vcmi.battleOptions.movementHighlightOnHover.hover" : "Muspeka (hovra) för att avslöja förflyttningsräckvidd",
|
"vcmi.battleOptions.movementHighlightOnHover.hover" : "Avslöja förflyttningsräckvidd",
|
||||||
"vcmi.battleOptions.movementHighlightOnHover.help" : "{Muspeka för att avslöja förflyttningsräckvidd}\n\nVisar enheters potentiella förflyttningsräckvidd över slagfältet när du håller muspekaren över dem.",
|
"vcmi.battleOptions.movementHighlightOnHover.help" : "{Muspeka (hovra) för att avslöja förflyttningsräckvidd}\n\nVisar enheters potentiella förflyttningsräckvidd över slagfältet när du håller muspekaren över dem.",
|
||||||
"vcmi.battleOptions.rangeLimitHighlightOnHover.hover": "Avslöja skyttars räckvidd",
|
"vcmi.battleOptions.rangeLimitHighlightOnHover.hover": "Avslöja skyttars räckvidd",
|
||||||
"vcmi.battleOptions.rangeLimitHighlightOnHover.help" : "{Muspeka för att avslöja skyttars räckvidd}\n\nVisar hur långt en enhets distansattack sträcker sig över slagfältet när du håller muspekaren över dem.",
|
"vcmi.battleOptions.rangeLimitHighlightOnHover.help" : "{Muspeka för att avslöja skyttars räckvidd}\n\nVisar hur långt en enhets distansattack sträcker sig över slagfältet när du håller muspekaren över dem.",
|
||||||
"vcmi.battleOptions.showStickyHeroInfoWindows.hover" : "Visa fönster med hjältars primärförmågor",
|
"vcmi.battleOptions.showStickyHeroInfoWindows.hover" : "Visa fönster med hjältars primärförmågor",
|
||||||
"vcmi.battleOptions.showStickyHeroInfoWindows.help" : "{Visa fönster med hjältars primärförmågor}\n\nKommer alltid att visa ett fönster där du kan se dina hjältars primärförmågor (anfall, försvar, trollkonst, kunskap och trollformelpoäng).",
|
"vcmi.battleOptions.showStickyHeroInfoWindows.help" : "{Visa fönster med hjältars primärförmågor}\n\nKommer alltid att visa ett fönster där du kan se dina hjältars primärförmågor (anfall, försvar, trollkonst, kunskap och trollformelpoäng).",
|
||||||
"vcmi.battleOptions.skipBattleIntroMusic.hover" : "Hoppa över intromusik",
|
"vcmi.battleOptions.skipBattleIntroMusic.hover" : "Hoppa över intromusik",
|
||||||
"vcmi.battleOptions.skipBattleIntroMusic.help" : "{Hoppa över intromusik}\n\nTillåt åtgärder under intromusiken som spelas i början av varje strid.",
|
"vcmi.battleOptions.skipBattleIntroMusic.help" : "{Hoppa över intromusik}\n\nTillåt åtgärder under intromusiken som spelas i början av varje strid.",
|
||||||
"vcmi.battleOptions.endWithAutocombat.hover" : "Slutför striden så fort som möjligt",
|
"vcmi.battleOptions.endWithAutocombat.hover" : "Snabbstrid (AI)",
|
||||||
"vcmi.battleOptions.endWithAutocombat.help" : "{Slutför strid}\n\nAuto-strid spelar striden åt dig för att striden ska slutföras så fort som möjligt.",
|
"vcmi.battleOptions.endWithAutocombat.help" : "{Slutför striden så fort som möjligt}\n\nAI för auto-strid spelar striden åt dig för att striden ska slutföras så fort som möjligt.",
|
||||||
"vcmi.battleOptions.showQuickSpell.hover" : "Snabb åtkomst till dina trollformler",
|
"vcmi.battleOptions.showQuickSpell.hover" : "Snabb åtkomst till dina trollformler",
|
||||||
"vcmi.battleOptions.showQuickSpell.help" : "{Visa snabbtrollformels-panelen}\n\nVisar en snabbvalspanel vid sidan av stridsfönstret där du har snabb åtkomst till några av dina trollformler",
|
"vcmi.battleOptions.showQuickSpell.help" : "{Visa snabbtrollformels-panelen}\n\nVisar en snabbvalspanel vid sidan av stridsfönstret där du har snabb åtkomst till några av dina trollformler",
|
||||||
|
|
||||||
@ -365,15 +368,15 @@
|
|||||||
"vcmi.optionsTab.turnOptions.help" : "Välj alternativ för turomgångs-timer och simultana turer",
|
"vcmi.optionsTab.turnOptions.help" : "Välj alternativ för turomgångs-timer och simultana turer",
|
||||||
|
|
||||||
"vcmi.optionsTab.chessFieldBase.hover" : "Bas-timern",
|
"vcmi.optionsTab.chessFieldBase.hover" : "Bas-timern",
|
||||||
"vcmi.optionsTab.chessFieldTurn.hover" : "Turomgångs-timern",
|
"vcmi.optionsTab.chessFieldTurn.hover" : "Tur-timern",
|
||||||
"vcmi.optionsTab.chessFieldBattle.hover" : "Strids-timern",
|
"vcmi.optionsTab.chessFieldBattle.hover" : "Strids-timern",
|
||||||
"vcmi.optionsTab.chessFieldUnit.hover" : "Enhets-timern",
|
"vcmi.optionsTab.chessFieldUnit.hover" : "Enhets-timern",
|
||||||
"vcmi.optionsTab.chessFieldBase.help" : "Används när {Turomgångs-timern} når '0'. Ställs in en gång i början av spelet. När den når '0' avslutas den aktuella turomgången (pågående strid avslutas med förlust).",
|
"vcmi.optionsTab.chessFieldBase.help" : "Används när {Tur-timern} når '0'. Ställs in en gång i början av spelet. När den når '0' avslutas den aktuella turomgången (pågående strid avslutas med förlust).",
|
||||||
"vcmi.optionsTab.chessFieldTurnAccumulate.help" : "Används utanför strid eller när {Strids-timern} tar slut. Återställs varje turomgång. Outnyttjad tid läggs till i {Bas-timern} till nästa turomgång.",
|
"vcmi.optionsTab.chessFieldTurnAccumulate.help" : "Används utanför strid eller när {Strids-timern} tar slut. Återställs varje turomgång. Outnyttjad tid läggs till i {Bas-timern} till nästa turomgång.",
|
||||||
"vcmi.optionsTab.chessFieldTurnDiscard.help" : "Används utanför strid eller när {Strids-timern} tar slut. Återställs varje turomgång. Outnyttjad tid går förlorad.",
|
"vcmi.optionsTab.chessFieldTurnDiscard.help" : "Används utanför strid eller när {Strids-timern} tar slut. Återställs varje turomgång. Outnyttjad tid går förlorad.",
|
||||||
"vcmi.optionsTab.chessFieldBattle.help" : "Används i strider med AI eller i PVP-strid när {Enhets-timern} tar slut. Återställs i början av varje strid.",
|
"vcmi.optionsTab.chessFieldBattle.help" : "Används i strider med AI eller i PvP-strid när {Enhets-timern} tar slut. Återställs i början av varje strid.",
|
||||||
"vcmi.optionsTab.chessFieldUnitAccumulate.help" : "Används när du styr din enhet i PVP-strid. Outnyttjad tid läggs till i {Strids-timern} när enheten har avslutat sin turomgång.",
|
"vcmi.optionsTab.chessFieldUnitAccumulate.help" : "Används när du styr din enhet i PvP-strid. Outnyttjad tid läggs till i {Strids-timern} när enheten har avslutat sin turomgång.",
|
||||||
"vcmi.optionsTab.chessFieldUnitDiscard.help" : "Används när du styr din enhet i PVP-strid. Återställs i början av varje enhets turomgång. Outnyttjad tid går förlorad.",
|
"vcmi.optionsTab.chessFieldUnitDiscard.help" : "Används när du styr din enhet i PvP-strid. Återställs i början av varje enhets turomgång. Outnyttjad tid går förlorad.",
|
||||||
|
|
||||||
"vcmi.optionsTab.accumulate" : "Ackumulera",
|
"vcmi.optionsTab.accumulate" : "Ackumulera",
|
||||||
|
|
||||||
@ -385,7 +388,7 @@
|
|||||||
"vcmi.optionsTab.simturnsMax.help" : "Spela samtidigt som andra spelare under ett angivet antal dagar eller tills en tillräckligt nära kontakt inträffar med en annan spelare",
|
"vcmi.optionsTab.simturnsMax.help" : "Spela samtidigt som andra spelare under ett angivet antal dagar eller tills en tillräckligt nära kontakt inträffar med en annan spelare",
|
||||||
"vcmi.optionsTab.simturnsAI.help" : "{Simultana AI-turomgångar}\nExperimentellt alternativ. Tillåter AI-spelare att agera samtidigt som den mänskliga spelaren när simultana turomgångar är aktiverade.",
|
"vcmi.optionsTab.simturnsAI.help" : "{Simultana AI-turomgångar}\nExperimentellt alternativ. Tillåter AI-spelare att agera samtidigt som den mänskliga spelaren när simultana turomgångar är aktiverade.",
|
||||||
|
|
||||||
"vcmi.optionsTab.turnTime.select" : "Turtids-förinställningar",
|
"vcmi.optionsTab.turnTime.select" : "Timer-inställningar för turomgångar",
|
||||||
"vcmi.optionsTab.turnTime.unlimited" : "Obegränsat med tid",
|
"vcmi.optionsTab.turnTime.unlimited" : "Obegränsat med tid",
|
||||||
"vcmi.optionsTab.turnTime.classic.1" : "Klassisk timer: 1 minut",
|
"vcmi.optionsTab.turnTime.classic.1" : "Klassisk timer: 1 minut",
|
||||||
"vcmi.optionsTab.turnTime.classic.2" : "Klassisk timer: 2 minuter",
|
"vcmi.optionsTab.turnTime.classic.2" : "Klassisk timer: 2 minuter",
|
||||||
@ -393,22 +396,22 @@
|
|||||||
"vcmi.optionsTab.turnTime.classic.10" : "Klassisk timer: 10 minuter",
|
"vcmi.optionsTab.turnTime.classic.10" : "Klassisk timer: 10 minuter",
|
||||||
"vcmi.optionsTab.turnTime.classic.20" : "Klassisk timer: 20 minuter",
|
"vcmi.optionsTab.turnTime.classic.20" : "Klassisk timer: 20 minuter",
|
||||||
"vcmi.optionsTab.turnTime.classic.30" : "Klassisk timer: 30 minuter",
|
"vcmi.optionsTab.turnTime.classic.30" : "Klassisk timer: 30 minuter",
|
||||||
"vcmi.optionsTab.turnTime.chess.20" : "Schack-timer: 20:00 + 10:00 + 02:00 + 00:00",
|
"vcmi.optionsTab.turnTime.chess.20" : "Schack: 20:00 + 10:00 + 02:00 + 00:00",
|
||||||
"vcmi.optionsTab.turnTime.chess.16" : "Schack-timer: 16:00 + 08:00 + 01:30 + 00:00",
|
"vcmi.optionsTab.turnTime.chess.16" : "Schack: 16:00 + 08:00 + 01:30 + 00:00",
|
||||||
"vcmi.optionsTab.turnTime.chess.8" : "Schack-timer: 08:00 + 04:00 + 01:00 + 00:00",
|
"vcmi.optionsTab.turnTime.chess.8" : "Schack: 08:00 + 04:00 + 01:00 + 00:00",
|
||||||
"vcmi.optionsTab.turnTime.chess.4" : "Schack-timer: 04:00 + 02:00 + 00:30 + 00:00",
|
"vcmi.optionsTab.turnTime.chess.4" : "Schack: 04:00 + 02:00 + 00:30 + 00:00",
|
||||||
"vcmi.optionsTab.turnTime.chess.2" : "Schack-timer: 02:00 + 01:00 + 00:15 + 00:00",
|
"vcmi.optionsTab.turnTime.chess.2" : "Schack: 02:00 + 01:00 + 00:15 + 00:00",
|
||||||
"vcmi.optionsTab.turnTime.chess.1" : "Schack-timer: 01:00 + 01:00 + 00:00 + 00:00",
|
"vcmi.optionsTab.turnTime.chess.1" : "Schack: 01:00 + 01:00 + 00:00 + 00:00",
|
||||||
|
|
||||||
"vcmi.optionsTab.simturns.select" : "Välj förinställning för simultana/samtidiga turer",
|
"vcmi.optionsTab.simturns.select" : "Simultana/samtidiga turomgångsinställningar",
|
||||||
"vcmi.optionsTab.simturns.none" : "Inga simultana/samtidiga turer",
|
"vcmi.optionsTab.simturns.none" : "Inga simultana/samtidiga turer",
|
||||||
"vcmi.optionsTab.simturns.tillContactMax" : "Simultantur: Fram till kontakt",
|
"vcmi.optionsTab.simturns.tillContactMax" : "Sam-tur: Fram till kontakt",
|
||||||
"vcmi.optionsTab.simturns.tillContact1" : "Simultantur: 1 vecka, bryt vid kontakt",
|
"vcmi.optionsTab.simturns.tillContact1" : "Sam-tur: 1 vecka, bryt vid kontakt",
|
||||||
"vcmi.optionsTab.simturns.tillContact2" : "Simultantur: 2 veckor, bryt vid kontakt",
|
"vcmi.optionsTab.simturns.tillContact2" : "Sam-tur: 2 veckor, bryt vid kontakt",
|
||||||
"vcmi.optionsTab.simturns.tillContact4" : "Simultantur: 1 månad, bryt vid kontakt",
|
"vcmi.optionsTab.simturns.tillContact4" : "Sam-tur: 1 månad, bryt vid kontakt",
|
||||||
"vcmi.optionsTab.simturns.blocked1" : "Simultantur: 1 vecka, kontakter blockerade",
|
"vcmi.optionsTab.simturns.blocked1" : "Sam-tur: 1 vecka, kontakter blockerade",
|
||||||
"vcmi.optionsTab.simturns.blocked2" : "Simultantur: 2 veckor, kontakter blockerade",
|
"vcmi.optionsTab.simturns.blocked2" : "Sam-tur: 2 veckor, kontakter blockerade",
|
||||||
"vcmi.optionsTab.simturns.blocked4" : "Simultantur: 1 månad, kontakter blockerade",
|
"vcmi.optionsTab.simturns.blocked4" : "Sam-tur: 1 månad, kontakter blockerade",
|
||||||
|
|
||||||
// Translation note: translate strings below using form that is correct for "0 days", "1 day" and "2 days" in your language
|
// Translation note: translate strings below using form that is correct for "0 days", "1 day" and "2 days" in your language
|
||||||
// Using this information, VCMI will automatically select correct plural form for every possible amount
|
// Using this information, VCMI will automatically select correct plural form for every possible amount
|
||||||
@ -525,10 +528,10 @@
|
|||||||
"core.bonus.AIR_IMMUNITY.description" : "Immun mot alla trollformler från skolan för luftmagi",
|
"core.bonus.AIR_IMMUNITY.description" : "Immun mot alla trollformler från skolan för luftmagi",
|
||||||
"core.bonus.ATTACKS_ALL_ADJACENT.name" : "Attackera runtomkring",
|
"core.bonus.ATTACKS_ALL_ADJACENT.name" : "Attackera runtomkring",
|
||||||
"core.bonus.ATTACKS_ALL_ADJACENT.description" : "Attackerar alla angränsande fiender",
|
"core.bonus.ATTACKS_ALL_ADJACENT.description" : "Attackerar alla angränsande fiender",
|
||||||
"core.bonus.BLOCKS_RETALIATION.name" : "Ingen motattack",
|
"core.bonus.BLOCKS_RETALIATION.name" : "Blockera närstrids-motattack",
|
||||||
"core.bonus.BLOCKS_RETALIATION.description" : "Fienden kan inte slå tillbaka/retaliera",
|
"core.bonus.BLOCKS_RETALIATION.description" : "Fienden kan inte slå tillbaka/retaliera",
|
||||||
"core.bonus.BLOCKS_RANGED_RETALIATION.name" : "Ingen motattack på avstånd",
|
"core.bonus.BLOCKS_RANGED_RETALIATION.name" : "Blockera fjärrstrids-motattack",
|
||||||
"core.bonus.BLOCKS_RANGED_RETALIATION.description" : "Fienden kan inte göra en motattack/retaliering på avstånd genom att använda en distansattack",
|
"core.bonus.BLOCKS_RANGED_RETALIATION.description" : "Fienden kan inte retaliera på avstånd genom att använda en distansattack",
|
||||||
"core.bonus.CATAPULT.name" : "Katapult",
|
"core.bonus.CATAPULT.name" : "Katapult",
|
||||||
"core.bonus.CATAPULT.description" : "Attackerar belägringsmurar",
|
"core.bonus.CATAPULT.description" : "Attackerar belägringsmurar",
|
||||||
"core.bonus.CHANGES_SPELL_COST_FOR_ALLY.name" : "Minska trollformelkostnaden (${val})",
|
"core.bonus.CHANGES_SPELL_COST_FOR_ALLY.name" : "Minska trollformelkostnaden (${val})",
|
||||||
@ -538,21 +541,21 @@
|
|||||||
"core.bonus.CHARGE_IMMUNITY.name" : "Galoppanfalls-immunitet",
|
"core.bonus.CHARGE_IMMUNITY.name" : "Galoppanfalls-immunitet",
|
||||||
"core.bonus.CHARGE_IMMUNITY.description" : "Immun mot ryttares och tornerares galopperande ridanfall",
|
"core.bonus.CHARGE_IMMUNITY.description" : "Immun mot ryttares och tornerares galopperande ridanfall",
|
||||||
"core.bonus.DARKNESS.name" : "I skydd av mörkret",
|
"core.bonus.DARKNESS.name" : "I skydd av mörkret",
|
||||||
"core.bonus.DARKNESS.description" : "Skapar ett hölje av mörker med en ${val}-rutorsradie",
|
"core.bonus.DARKNESS.description" : "Skapar ett mörkerhölje med en rut-radie på ${val} som gäckar dina fiender",
|
||||||
"core.bonus.DEATH_STARE.name" : "Dödsblick (${val}%)",
|
"core.bonus.DEATH_STARE.name" : "Dödsblick (${val}%)",
|
||||||
"core.bonus.DEATH_STARE.description" : "Varje förbandsenhet med 'Dödsblick' har ${val}% chans att döda den översta enheten i ett fiendeförband",
|
"core.bonus.DEATH_STARE.description" : "Varje 'Dödsblick' har ${val}% chans att döda den översta fiendeenheten",
|
||||||
"core.bonus.DEFENSIVE_STANCE.name" : "Försvarshållning",
|
"core.bonus.DEFENSIVE_STANCE.name" : "Försvarshållning",
|
||||||
"core.bonus.DEFENSIVE_STANCE.description" : "Ger ytterligare +${val} till enhetens försvarsförmåga när du väljer att försvarar dig",
|
"core.bonus.DEFENSIVE_STANCE.description" : "När du väljer att försvara en enhet så får den +${val} extra försvar",
|
||||||
"core.bonus.DESTRUCTION.name" : "Förintelse",
|
"core.bonus.DESTRUCTION.name" : "Förintelse",
|
||||||
"core.bonus.DESTRUCTION.description" : "Har ${val}% chans att döda extra enheter efter attack",
|
"core.bonus.DESTRUCTION.description" : "Har ${val}% chans att döda extra enheter efter attack",
|
||||||
"core.bonus.DOUBLE_DAMAGE_CHANCE.name" : "Dödsstöt",
|
"core.bonus.DOUBLE_DAMAGE_CHANCE.name" : "Dödsstöt",
|
||||||
"core.bonus.DOUBLE_DAMAGE_CHANCE.description" : "Har ${val}% chans att ge dubbel basskada vid attack",
|
"core.bonus.DOUBLE_DAMAGE_CHANCE.description" : "Har ${val}% chans att utdela dubbel basskada vid attack",
|
||||||
"core.bonus.DRAGON_NATURE.name" : "Drake",
|
"core.bonus.DRAGON_NATURE.name" : "Drake",
|
||||||
"core.bonus.DRAGON_NATURE.description" : "Varelsen har en draknatur",
|
"core.bonus.DRAGON_NATURE.description" : "Varelsen har en draknatur",
|
||||||
"core.bonus.EARTH_IMMUNITY.name" : "Jord-immunitet",
|
"core.bonus.EARTH_IMMUNITY.name" : "Jord-immunitet",
|
||||||
"core.bonus.EARTH_IMMUNITY.description" : "Immun mot alla trollformler från skolan för jordmagi",
|
"core.bonus.EARTH_IMMUNITY.description" : "Immun mot alla trollformler från skolan för jordmagi",
|
||||||
"core.bonus.ENCHANTER.name" : "Förtrollare",
|
"core.bonus.ENCHANTER.name" : "Förtrollare",
|
||||||
"core.bonus.ENCHANTER.description" : "Kan kasta ${subtyp.spell} på alla varje tur/omgång",
|
"core.bonus.ENCHANTER.description" : "Kan kasta ${subtyp.spell} på alla varje turomgång",
|
||||||
"core.bonus.ENCHANTED.name" : "Förtrollad",
|
"core.bonus.ENCHANTED.name" : "Förtrollad",
|
||||||
"core.bonus.ENCHANTED.description" : "Påverkas av permanent ${subtype.spell}",
|
"core.bonus.ENCHANTED.description" : "Påverkas av permanent ${subtype.spell}",
|
||||||
"core.bonus.ENEMY_ATTACK_REDUCTION.name" : "Avfärda attack (${val}%)",
|
"core.bonus.ENEMY_ATTACK_REDUCTION.name" : "Avfärda attack (${val}%)",
|
||||||
@ -578,15 +581,15 @@
|
|||||||
"core.bonus.GARGOYLE.name" : "Stenfigur",
|
"core.bonus.GARGOYLE.name" : "Stenfigur",
|
||||||
"core.bonus.GARGOYLE.description" : "Kan varken upplivas eller läkas",
|
"core.bonus.GARGOYLE.description" : "Kan varken upplivas eller läkas",
|
||||||
"core.bonus.GENERAL_DAMAGE_REDUCTION.name" : "Minska skada (${val}%)",
|
"core.bonus.GENERAL_DAMAGE_REDUCTION.name" : "Minska skada (${val}%)",
|
||||||
"core.bonus.GENERAL_DAMAGE_REDUCTION.description" : "Reducerar fysisk skada från både distans- och närstridsattacker",
|
"core.bonus.GENERAL_DAMAGE_REDUCTION.description" : "Reducerar skadan från distans- och närstrids-attacker",
|
||||||
"core.bonus.HATE.name" : "Hatar ${subtyp.varelse}",
|
"core.bonus.HATE.name" : "Hatar ${subtyp.varelse}",
|
||||||
"core.bonus.HATE.description" : "Gör ${val}% mer skada mot ${subtyp.varelse}",
|
"core.bonus.HATE.description" : "Gör ${val}% mer skada mot ${subtyp.varelse}",
|
||||||
"core.bonus.HEALER.name" : "Helare",
|
"core.bonus.HEALER.name" : "Helare",
|
||||||
"core.bonus.HEALER.description" : "Helar/läker allierade enheter",
|
"core.bonus.HEALER.description" : "Helar/läker allierade enheter",
|
||||||
"core.bonus.HP_REGENERATION.name" : "Självläkande",
|
"core.bonus.HP_REGENERATION.name" : "Självläkande",
|
||||||
"core.bonus.HP_REGENERATION.description" : "Får tillbaka ${val} träffpoäng (hälsa) varje runda",
|
"core.bonus.HP_REGENERATION.description" : "Får tillbaka ${val} hälsa (träffpoäng) varje runda",
|
||||||
"core.bonus.JOUSTING.name" : "Galopperande ridanfall",
|
"core.bonus.JOUSTING.name" : "Galopperande ridanfall",
|
||||||
"core.bonus.JOUSTING.description" : "Orsakar +${val}% extra skada för varje ruta som enheten förflyttas innan attack",
|
"core.bonus.JOUSTING.description" : "Orsakar +${val}% mer skada för varje ruta som förflyttas innan attack",
|
||||||
"core.bonus.KING.name" : "Kung",
|
"core.bonus.KING.name" : "Kung",
|
||||||
"core.bonus.KING.description" : "Sårbar för 'Dräpar'-nivå ${val} eller högre",
|
"core.bonus.KING.description" : "Sårbar för 'Dräpar'-nivå ${val} eller högre",
|
||||||
"core.bonus.LEVEL_SPELL_IMMUNITY.name" : "Förtrollningsimmunitet 1-${val}",
|
"core.bonus.LEVEL_SPELL_IMMUNITY.name" : "Förtrollningsimmunitet 1-${val}",
|
||||||
@ -594,13 +597,13 @@
|
|||||||
"core.bonus.LIMITED_SHOOTING_RANGE.name" : "Begränsad räckvidd för skjutning",
|
"core.bonus.LIMITED_SHOOTING_RANGE.name" : "Begränsad räckvidd för skjutning",
|
||||||
"core.bonus.LIMITED_SHOOTING_RANGE.description" : "Kan inte sikta på enheter längre bort än ${val} rutor",
|
"core.bonus.LIMITED_SHOOTING_RANGE.description" : "Kan inte sikta på enheter längre bort än ${val} rutor",
|
||||||
"core.bonus.LIFE_DRAIN.name" : "Dränerar livskraft (${val}%)",
|
"core.bonus.LIFE_DRAIN.name" : "Dränerar livskraft (${val}%)",
|
||||||
"core.bonus.LIFE_DRAIN.description" : "Dränerar ${val}% träffpoäng (hälsa) av utdelad skada",
|
"core.bonus.LIFE_DRAIN.description" : "Dränerar ${val}% hälsa (träffpoäng) av utdelad skada",
|
||||||
"core.bonus.MANA_CHANNELING.name" : "Kanalisera trollformelspoäng ${val}%",
|
"core.bonus.MANA_CHANNELING.name" : "Kanalisera trollformelspoäng ${val}%",
|
||||||
"core.bonus.MANA_CHANNELING.description" : "Ger din hjälte ${val}% av den mängd trollformelspoäng som fienden spenderar per trollformel i strid",
|
"core.bonus.MANA_CHANNELING.description" : "Ger din hjälte ${val}% av fiendens spenderade trollformelspoäng i strid",
|
||||||
"core.bonus.MANA_DRAIN.name" : "Dränera trollformelspoäng",
|
"core.bonus.MANA_DRAIN.name" : "Dränera trollformelspoäng",
|
||||||
"core.bonus.MANA_DRAIN.description" : "Dränerar ${val} trollformelspoäng varje tur",
|
"core.bonus.MANA_DRAIN.description" : "Dränerar ${val} trollformelspoäng varje tur",
|
||||||
"core.bonus.MAGIC_MIRROR.name" : "Magisk spegel (${val}%)",
|
"core.bonus.MAGIC_MIRROR.name" : "Magisk spegel (${val}%)",
|
||||||
"core.bonus.MAGIC_MIRROR.description" : "Har ${val}% chans att reflektera (omdirigera) en offensiv trollformel på en fiendeenhet",
|
"core.bonus.MAGIC_MIRROR.description" : "${val}% chans att reflektera en offensiv trollformel på en fiendeenhet",
|
||||||
"core.bonus.MAGIC_RESISTANCE.name" : "Magiskt motstånd (${val}%)",
|
"core.bonus.MAGIC_RESISTANCE.name" : "Magiskt motstånd (${val}%)",
|
||||||
"core.bonus.MAGIC_RESISTANCE.description" : "Har en ${val}% chans att motstå en skadlig trollformel",
|
"core.bonus.MAGIC_RESISTANCE.description" : "Har en ${val}% chans att motstå en skadlig trollformel",
|
||||||
"core.bonus.MIND_IMMUNITY.name" : "Immunitet mot sinnesförtrollningar",
|
"core.bonus.MIND_IMMUNITY.name" : "Immunitet mot sinnesförtrollningar",
|
||||||
@ -610,11 +613,11 @@
|
|||||||
"core.bonus.NO_MELEE_PENALTY.name" : "Ingen närstridsbestraffning",
|
"core.bonus.NO_MELEE_PENALTY.name" : "Ingen närstridsbestraffning",
|
||||||
"core.bonus.NO_MELEE_PENALTY.description" : "Varelsen har ingen närstridsbestraffning",
|
"core.bonus.NO_MELEE_PENALTY.description" : "Varelsen har ingen närstridsbestraffning",
|
||||||
"core.bonus.NO_MORALE.name" : "Ingen Moralpåverkan",
|
"core.bonus.NO_MORALE.name" : "Ingen Moralpåverkan",
|
||||||
"core.bonus.NO_MORALE.description" : "Varelsen är immun mot moraliska effekter och har alltid neutral moral",
|
"core.bonus.NO_MORALE.description" : "Är immun mot moraliska effekter och har alltid neutral moral",
|
||||||
"core.bonus.NO_WALL_PENALTY.name" : "Ingen murbestraffning",
|
"core.bonus.NO_WALL_PENALTY.name" : "Ingen murbestraffning",
|
||||||
"core.bonus.NO_WALL_PENALTY.description" : "Orsakar full skada mot fiender bakom en mur",
|
"core.bonus.NO_WALL_PENALTY.description" : "Orsakar full skada mot fiender bakom en mur",
|
||||||
"core.bonus.NON_LIVING.name" : "Icke levande",
|
"core.bonus.NON_LIVING.name" : "Icke levande",
|
||||||
"core.bonus.NON_LIVING.description" : "Immunitet mot många effekter som annars bara påverkar levande och odöda varelser",
|
"core.bonus.NON_LIVING.description" : "Påverkas inte av vissa effekter som levande/odöda gör",
|
||||||
"core.bonus.RANDOM_SPELLCASTER.name" : "Slumpmässig besvärjare",
|
"core.bonus.RANDOM_SPELLCASTER.name" : "Slumpmässig besvärjare",
|
||||||
"core.bonus.RANDOM_SPELLCASTER.description" : "Kan kasta trollformler som väljs slumpmässigt",
|
"core.bonus.RANDOM_SPELLCASTER.description" : "Kan kasta trollformler som väljs slumpmässigt",
|
||||||
"core.bonus.RANGED_RETALIATION.name" : "Motattacker på avstånd",
|
"core.bonus.RANGED_RETALIATION.name" : "Motattacker på avstånd",
|
||||||
@ -624,21 +627,21 @@
|
|||||||
"core.bonus.REBIRTH.name" : "Återfödelse (${val}%)",
|
"core.bonus.REBIRTH.name" : "Återfödelse (${val}%)",
|
||||||
"core.bonus.REBIRTH.description" : "${val}% av enheterna kommer att återuppväckas efter döden",
|
"core.bonus.REBIRTH.description" : "${val}% av enheterna kommer att återuppväckas efter döden",
|
||||||
"core.bonus.RETURN_AFTER_STRIKE.name" : "Återvänder efter närstrid",
|
"core.bonus.RETURN_AFTER_STRIKE.name" : "Återvänder efter närstrid",
|
||||||
"core.bonus.RETURN_AFTER_STRIKE.description" : "Efter att ha attackerat en fiendeenhet i närstrid återvänder enheten till rutan som den var placerad på innan den utförde sin närstridsattack",
|
"core.bonus.RETURN_AFTER_STRIKE.description" : "Efter närstridsattack återvänder den till sin ursprungliga ruta",
|
||||||
"core.bonus.REVENGE.name" : "Hämnd",
|
"core.bonus.REVENGE.name" : "Hämnd",
|
||||||
"core.bonus.REVENGE.description" : "Orsakar extra skada baserat på angriparens förlorade träffpoäng (hälsa) i strid",
|
"core.bonus.REVENGE.description" : "Orsakar mer skada om den själv blivit skadad",
|
||||||
"core.bonus.SHOOTER.name" : "Distans-attack",
|
"core.bonus.SHOOTER.name" : "Distans-attack",
|
||||||
"core.bonus.SHOOTER.description" : "Varelsen kan skjuta/attackera på avstånd",
|
"core.bonus.SHOOTER.description" : "Varelsen kan skjuta/attackera på avstånd",
|
||||||
"core.bonus.SHOOTS_ALL_ADJACENT.name" : "Skjuter alla i närheten",
|
"core.bonus.SHOOTS_ALL_ADJACENT.name" : "Skjuter alla i närheten",
|
||||||
"core.bonus.SHOOTS_ALL_ADJACENT.description" : "Denna varelses distans-attacker drabbar alla mål i ett litet område",
|
"core.bonus.SHOOTS_ALL_ADJACENT.description" : "Dess distans-attacker drabbar alla mål i ett litet område",
|
||||||
"core.bonus.SOUL_STEAL.name" : "Själtjuv",
|
"core.bonus.SOUL_STEAL.name" : "Själtjuv",
|
||||||
"core.bonus.SOUL_STEAL.description" : "Återuppväcker ${val} av sina egna enheter för varje dödad fiendeenhet",
|
"core.bonus.SOUL_STEAL.description" : "Återuppväcker ${val} av sina egna för varje dödad fiendeenhet",
|
||||||
"core.bonus.SPELLCASTER.name" : "Besvärjare",
|
"core.bonus.SPELLCASTER.name" : "Besvärjare",
|
||||||
"core.bonus.SPELLCASTER.description" : "Kan kasta ${subtype.spell}",
|
"core.bonus.SPELLCASTER.description" : "Kan kasta ${subtype.spell}",
|
||||||
"core.bonus.SPELL_AFTER_ATTACK.name" : "Besvärja efter attack",
|
"core.bonus.SPELL_AFTER_ATTACK.name" : "Besvärja efter attack",
|
||||||
"core.bonus.SPELL_AFTER_ATTACK.description" : "Har en ${val}% chans att kasta ${subtype.spell} efter att den har attackerat",
|
"core.bonus.SPELL_AFTER_ATTACK.description" : "Har ${val}% chans att kasta ${subtype.spell} efter anfall",
|
||||||
"core.bonus.SPELL_BEFORE_ATTACK.name" : "Besvärja före attack",
|
"core.bonus.SPELL_BEFORE_ATTACK.name" : "Besvärja före attack",
|
||||||
"core.bonus.SPELL_BEFORE_ATTACK.description" : "Har en ${val}% chans att kasta ${subtype.spell} innan den attackerar",
|
"core.bonus.SPELL_BEFORE_ATTACK.description" : "Har ${val}% chans att kasta ${subtype.spell} före anfall",
|
||||||
"core.bonus.SPELL_DAMAGE_REDUCTION.name" : "Trolldoms-resistens",
|
"core.bonus.SPELL_DAMAGE_REDUCTION.name" : "Trolldoms-resistens",
|
||||||
"core.bonus.SPELL_DAMAGE_REDUCTION.description" : "Skadan från trollformler är reducet med ${val}%.",
|
"core.bonus.SPELL_DAMAGE_REDUCTION.description" : "Skadan från trollformler är reducet med ${val}%.",
|
||||||
"core.bonus.SPELL_IMMUNITY.name" : "Trolldoms-immunitet",
|
"core.bonus.SPELL_IMMUNITY.name" : "Trolldoms-immunitet",
|
||||||
@ -659,14 +662,14 @@
|
|||||||
"core.bonus.TRANSMUTATION.description" : "${val}% chans att förvandla angripen enhet till en annan typ",
|
"core.bonus.TRANSMUTATION.description" : "${val}% chans att förvandla angripen enhet till en annan typ",
|
||||||
"core.bonus.UNDEAD.name" : "Odöd",
|
"core.bonus.UNDEAD.name" : "Odöd",
|
||||||
"core.bonus.UNDEAD.description" : "Varelsen är odöd",
|
"core.bonus.UNDEAD.description" : "Varelsen är odöd",
|
||||||
"core.bonus.UNLIMITED_RETALIATIONS.name" : "Obegränsat antal motattacker",
|
"core.bonus.UNLIMITED_RETALIATIONS.name" : "Slår tillbaka varje gång",
|
||||||
"core.bonus.UNLIMITED_RETALIATIONS.description" : "Kan slå tillbaka mot ett obegränsat antal attacker varje omgång",
|
"core.bonus.UNLIMITED_RETALIATIONS.description" : "Obegränsat antal motattacker",
|
||||||
"core.bonus.WATER_IMMUNITY.name" : "Vatten-immunitet",
|
"core.bonus.WATER_IMMUNITY.name" : "Vatten-immunitet",
|
||||||
"core.bonus.WATER_IMMUNITY.description" : "Immun mot alla trollformler från vattenmagi-skolan",
|
"core.bonus.WATER_IMMUNITY.description" : "Immun mot alla trollformler från vattenmagiskolan",
|
||||||
"core.bonus.WIDE_BREATH.name" : "Bred dödlig andedräkt",
|
"core.bonus.WIDE_BREATH.name" : "Bred dödlig andedräkt",
|
||||||
"core.bonus.WIDE_BREATH.description" : "Bred andningsattack (flera rutor)",
|
"core.bonus.WIDE_BREATH.description" : "Bred andningsattack (flera rutor)",
|
||||||
"core.bonus.DISINTEGRATE.name" : "Desintegrerar",
|
"core.bonus.DISINTEGRATE.name" : "Desintegrerar",
|
||||||
"core.bonus.DISINTEGRATE.description" : "Ingen fysisk kropp finns kvar efter att enheten blivit besegrad i strid",
|
"core.bonus.DISINTEGRATE.description" : "Ingen kropp lämnas kvar efter dödsögonblicket",
|
||||||
"core.bonus.INVINCIBLE.name" : "Oövervinnerlig",
|
"core.bonus.INVINCIBLE.name" : "Oövervinnerlig",
|
||||||
"core.bonus.INVINCIBLE.description" : "Kan inte påverkas av någonting"
|
"core.bonus.INVINCIBLE.description" : "Kan inte påverkas av någonting"
|
||||||
}
|
}
|
||||||
|
@ -1138,7 +1138,7 @@ void CPlayerInterface::showMapObjectSelectDialog(QueryID askID, const Component
|
|||||||
const CGTownInstance * t = dynamic_cast<const CGTownInstance *>(cb->getObj(obj));
|
const CGTownInstance * t = dynamic_cast<const CGTownInstance *>(cb->getObj(obj));
|
||||||
if(t)
|
if(t)
|
||||||
{
|
{
|
||||||
auto image = GH.renderHandler().loadImage(AnimationPath::builtin("ITPA"), t->town->clientInfo.icons[t->hasFort()][false] + 2, 0, EImageBlitMode::OPAQUE);
|
auto image = GH.renderHandler().loadImage(AnimationPath::builtin("ITPA"), t->getTown()->clientInfo.icons[t->hasFort()][false] + 2, 0, EImageBlitMode::OPAQUE);
|
||||||
image->scaleTo(Point(35, 23));
|
image->scaleTo(Point(35, 23));
|
||||||
images.push_back(image);
|
images.push_back(image);
|
||||||
}
|
}
|
||||||
@ -1333,6 +1333,8 @@ void CPlayerInterface::initializeHeroTownList()
|
|||||||
localState->addOwnedTown(town);
|
localState->addOwnedTown(town);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localState->deserialize(*cb->getPlayerState(playerID)->playerLocalSettings);
|
||||||
|
|
||||||
if(adventureInt)
|
if(adventureInt)
|
||||||
adventureInt->onHeroChanged(nullptr);
|
adventureInt->onHeroChanged(nullptr);
|
||||||
}
|
}
|
||||||
|
@ -453,7 +453,7 @@ void ClientCommandManager::handleTellCommand(std::istringstream& singleWordBuffe
|
|||||||
if(what == "hs")
|
if(what == "hs")
|
||||||
{
|
{
|
||||||
for(const CGHeroInstance* h : LOCPLINT->cb->getHeroesInfo())
|
for(const CGHeroInstance* h : LOCPLINT->cb->getHeroesInfo())
|
||||||
if(h->type->getIndex() == id1)
|
if(h->getHeroTypeID().getNum() == id1)
|
||||||
if(const CArtifactInstance* a = h->getArt(ArtifactPosition(id2)))
|
if(const CArtifactInstance* a = h->getArt(ArtifactPosition(id2)))
|
||||||
printCommandMessage(a->nodeName());
|
printCommandMessage(a->nodeName());
|
||||||
}
|
}
|
||||||
|
@ -375,7 +375,7 @@ void HeroMovementController::sendMovementRequest(const CGHeroInstance * h, const
|
|||||||
{
|
{
|
||||||
updateMovementSound(h, currNode.coord, nextNode.coord, nextNode.action);
|
updateMovementSound(h, currNode.coord, nextNode.coord, nextNode.action);
|
||||||
|
|
||||||
assert(h->pos.z == nextNode.coord.z); // Z should change only if it's movement via teleporter and in this case this code shouldn't be executed at all
|
assert(h->anchorPos().z == nextNode.coord.z); // Z should change only if it's movement via teleporter and in this case this code shouldn't be executed at all
|
||||||
|
|
||||||
logGlobal->trace("Requesting hero movement to %s", nextNode.coord.toString());
|
logGlobal->trace("Requesting hero movement to %s", nextNode.coord.toString());
|
||||||
|
|
||||||
|
@ -671,7 +671,7 @@ void ApplyClientNetPackVisitor::visitSetHeroesInTown(SetHeroesInTown & pack)
|
|||||||
void ApplyClientNetPackVisitor::visitHeroRecruited(HeroRecruited & pack)
|
void ApplyClientNetPackVisitor::visitHeroRecruited(HeroRecruited & pack)
|
||||||
{
|
{
|
||||||
CGHeroInstance *h = gs.map->heroesOnMap.back();
|
CGHeroInstance *h = gs.map->heroesOnMap.back();
|
||||||
if(h->getHeroType() != pack.hid)
|
if(h->getHeroTypeID() != pack.hid)
|
||||||
{
|
{
|
||||||
logNetwork->error("Something wrong with hero recruited!");
|
logNetwork->error("Something wrong with hero recruited!");
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "PlayerLocalState.h"
|
#include "PlayerLocalState.h"
|
||||||
|
|
||||||
#include "../CCallback.h"
|
#include "../CCallback.h"
|
||||||
|
#include "../lib/json/JsonNode.h"
|
||||||
#include "../lib/mapObjects/CGHeroInstance.h"
|
#include "../lib/mapObjects/CGHeroInstance.h"
|
||||||
#include "../lib/mapObjects/CGTownInstance.h"
|
#include "../lib/mapObjects/CGTownInstance.h"
|
||||||
#include "../lib/pathfinder/CGPathNode.h"
|
#include "../lib/pathfinder/CGPathNode.h"
|
||||||
@ -23,34 +24,20 @@ PlayerLocalState::PlayerLocalState(CPlayerInterface & owner)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerLocalState::saveHeroPaths(std::map<const CGHeroInstance *, int3> & pathsMap)
|
const PlayerSpellbookSetting & PlayerLocalState::getSpellbookSettings()
|
||||||
{
|
{
|
||||||
for(auto & p : paths)
|
return spellbookSettings;
|
||||||
{
|
|
||||||
if(p.second.nodes.size())
|
|
||||||
pathsMap[p.first] = p.second.endPos();
|
|
||||||
else
|
|
||||||
logGlobal->debug("%s has assigned an empty path! Ignoring it...", p.first->getNameTranslated());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerLocalState::loadHeroPaths(std::map<const CGHeroInstance *, int3> & pathsMap)
|
void PlayerLocalState::setSpellbookSettings(const PlayerSpellbookSetting & newSettings)
|
||||||
{
|
{
|
||||||
if(owner.cb)
|
spellbookSettings = newSettings;
|
||||||
{
|
|
||||||
for(auto & p : pathsMap)
|
|
||||||
{
|
|
||||||
CGPath path;
|
|
||||||
owner.cb->getPathsInfo(p.first)->getPath(path, p.second);
|
|
||||||
paths[p.first] = path;
|
|
||||||
logGlobal->trace("Restored path for hero %s leading to %s with %d nodes", p.first->nodeName(), p.second.toString(), path.nodes.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerLocalState::setPath(const CGHeroInstance * h, const CGPath & path)
|
void PlayerLocalState::setPath(const CGHeroInstance * h, const CGPath & path)
|
||||||
{
|
{
|
||||||
paths[h] = path;
|
paths[h] = path;
|
||||||
|
syncronizeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CGPath & PlayerLocalState::getPath(const CGHeroInstance * h) const
|
const CGPath & PlayerLocalState::getPath(const CGHeroInstance * h) const
|
||||||
@ -70,6 +57,7 @@ bool PlayerLocalState::setPath(const CGHeroInstance * h, const int3 & destinatio
|
|||||||
if(!owner.cb->getPathsInfo(h)->getPath(path, destination))
|
if(!owner.cb->getPathsInfo(h)->getPath(path, destination))
|
||||||
{
|
{
|
||||||
paths.erase(h); //invalidate previously possible path if selected (before other hero blocked only path / fly spell expired)
|
paths.erase(h); //invalidate previously possible path if selected (before other hero blocked only path / fly spell expired)
|
||||||
|
syncronizeState();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,6 +81,7 @@ void PlayerLocalState::erasePath(const CGHeroInstance * h)
|
|||||||
{
|
{
|
||||||
paths.erase(h);
|
paths.erase(h);
|
||||||
adventureInt->onHeroChanged(h);
|
adventureInt->onHeroChanged(h);
|
||||||
|
syncronizeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerLocalState::verifyPath(const CGHeroInstance * h)
|
void PlayerLocalState::verifyPath(const CGHeroInstance * h)
|
||||||
@ -170,6 +159,7 @@ void PlayerLocalState::setSelection(const CArmedInstance * selection)
|
|||||||
|
|
||||||
if (adventureInt && selection)
|
if (adventureInt && selection)
|
||||||
adventureInt->onSelectionChanged(selection);
|
adventureInt->onSelectionChanged(selection);
|
||||||
|
syncronizeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerLocalState::isHeroSleeping(const CGHeroInstance * hero) const
|
bool PlayerLocalState::isHeroSleeping(const CGHeroInstance * hero) const
|
||||||
@ -184,6 +174,7 @@ void PlayerLocalState::setHeroAsleep(const CGHeroInstance * hero)
|
|||||||
assert(!vstd::contains(sleepingHeroes, hero));
|
assert(!vstd::contains(sleepingHeroes, hero));
|
||||||
|
|
||||||
sleepingHeroes.push_back(hero);
|
sleepingHeroes.push_back(hero);
|
||||||
|
syncronizeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerLocalState::setHeroAwaken(const CGHeroInstance * hero)
|
void PlayerLocalState::setHeroAwaken(const CGHeroInstance * hero)
|
||||||
@ -193,6 +184,7 @@ void PlayerLocalState::setHeroAwaken(const CGHeroInstance * hero)
|
|||||||
assert(vstd::contains(sleepingHeroes, hero));
|
assert(vstd::contains(sleepingHeroes, hero));
|
||||||
|
|
||||||
vstd::erase(sleepingHeroes, hero);
|
vstd::erase(sleepingHeroes, hero);
|
||||||
|
syncronizeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<const CGHeroInstance *> & PlayerLocalState::getWanderingHeroes()
|
const std::vector<const CGHeroInstance *> & PlayerLocalState::getWanderingHeroes()
|
||||||
@ -215,6 +207,8 @@ void PlayerLocalState::addWanderingHero(const CGHeroInstance * hero)
|
|||||||
|
|
||||||
if (currentSelection == nullptr)
|
if (currentSelection == nullptr)
|
||||||
setSelection(hero);
|
setSelection(hero);
|
||||||
|
|
||||||
|
syncronizeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerLocalState::removeWanderingHero(const CGHeroInstance * hero)
|
void PlayerLocalState::removeWanderingHero(const CGHeroInstance * hero)
|
||||||
@ -236,6 +230,8 @@ void PlayerLocalState::removeWanderingHero(const CGHeroInstance * hero)
|
|||||||
|
|
||||||
if (currentSelection == nullptr && !ownedTowns.empty())
|
if (currentSelection == nullptr && !ownedTowns.empty())
|
||||||
setSelection(ownedTowns.front());
|
setSelection(ownedTowns.front());
|
||||||
|
|
||||||
|
syncronizeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerLocalState::swapWanderingHero(size_t pos1, size_t pos2)
|
void PlayerLocalState::swapWanderingHero(size_t pos1, size_t pos2)
|
||||||
@ -244,6 +240,8 @@ void PlayerLocalState::swapWanderingHero(size_t pos1, size_t pos2)
|
|||||||
std::swap(wanderingHeroes.at(pos1), wanderingHeroes.at(pos2));
|
std::swap(wanderingHeroes.at(pos1), wanderingHeroes.at(pos2));
|
||||||
|
|
||||||
adventureInt->onHeroOrderChanged();
|
adventureInt->onHeroOrderChanged();
|
||||||
|
|
||||||
|
syncronizeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<const CGTownInstance *> & PlayerLocalState::getOwnedTowns()
|
const std::vector<const CGTownInstance *> & PlayerLocalState::getOwnedTowns()
|
||||||
@ -266,6 +264,8 @@ void PlayerLocalState::addOwnedTown(const CGTownInstance * town)
|
|||||||
|
|
||||||
if (currentSelection == nullptr)
|
if (currentSelection == nullptr)
|
||||||
setSelection(town);
|
setSelection(town);
|
||||||
|
|
||||||
|
syncronizeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerLocalState::removeOwnedTown(const CGTownInstance * town)
|
void PlayerLocalState::removeOwnedTown(const CGTownInstance * town)
|
||||||
@ -282,6 +282,8 @@ void PlayerLocalState::removeOwnedTown(const CGTownInstance * town)
|
|||||||
|
|
||||||
if (currentSelection == nullptr && !ownedTowns.empty())
|
if (currentSelection == nullptr && !ownedTowns.empty())
|
||||||
setSelection(ownedTowns.front());
|
setSelection(ownedTowns.front());
|
||||||
|
|
||||||
|
syncronizeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerLocalState::swapOwnedTowns(size_t pos1, size_t pos2)
|
void PlayerLocalState::swapOwnedTowns(size_t pos1, size_t pos2)
|
||||||
@ -289,5 +291,119 @@ void PlayerLocalState::swapOwnedTowns(size_t pos1, size_t pos2)
|
|||||||
assert(ownedTowns[pos1] && ownedTowns[pos2]);
|
assert(ownedTowns[pos1] && ownedTowns[pos2]);
|
||||||
std::swap(ownedTowns.at(pos1), ownedTowns.at(pos2));
|
std::swap(ownedTowns.at(pos1), ownedTowns.at(pos2));
|
||||||
|
|
||||||
|
syncronizeState();
|
||||||
|
|
||||||
adventureInt->onTownOrderChanged();
|
adventureInt->onTownOrderChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlayerLocalState::syncronizeState()
|
||||||
|
{
|
||||||
|
JsonNode data;
|
||||||
|
serialize(data);
|
||||||
|
owner.cb->saveLocalState(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerLocalState::serialize(JsonNode & dest) const
|
||||||
|
{
|
||||||
|
dest.clear();
|
||||||
|
|
||||||
|
for (auto const * town : ownedTowns)
|
||||||
|
{
|
||||||
|
JsonNode record;
|
||||||
|
record["id"].Integer() = town->id;
|
||||||
|
dest["towns"].Vector().push_back(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const * hero : wanderingHeroes)
|
||||||
|
{
|
||||||
|
JsonNode record;
|
||||||
|
record["id"].Integer() = hero->id;
|
||||||
|
if (vstd::contains(sleepingHeroes, hero))
|
||||||
|
record["sleeping"].Bool() = true;
|
||||||
|
|
||||||
|
if (paths.count(hero))
|
||||||
|
{
|
||||||
|
record["path"]["x"].Integer() = paths.at(hero).lastNode().coord.x;
|
||||||
|
record["path"]["y"].Integer() = paths.at(hero).lastNode().coord.y;
|
||||||
|
record["path"]["z"].Integer() = paths.at(hero).lastNode().coord.z;
|
||||||
|
}
|
||||||
|
dest["heroes"].Vector().push_back(record);
|
||||||
|
}
|
||||||
|
dest["spellbook"]["pageBattle"].Integer() = spellbookSettings.spellbookLastPageBattle;
|
||||||
|
dest["spellbook"]["pageAdvmap"].Integer() = spellbookSettings.spellbookLastPageAdvmap;
|
||||||
|
dest["spellbook"]["tabBattle"].Integer() = spellbookSettings.spellbookLastTabBattle;
|
||||||
|
dest["spellbook"]["tabAdvmap"].Integer() = spellbookSettings.spellbookLastTabAdvmap;
|
||||||
|
|
||||||
|
dest["currentSelection"].Integer() = currentSelection->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerLocalState::deserialize(const JsonNode & source)
|
||||||
|
{
|
||||||
|
// this method must be called after player state has been initialized
|
||||||
|
assert(currentSelection != nullptr);
|
||||||
|
assert(!ownedTowns.empty() || wanderingHeroes.empty());
|
||||||
|
|
||||||
|
auto oldHeroes = wanderingHeroes;
|
||||||
|
auto oldTowns = ownedTowns;
|
||||||
|
|
||||||
|
paths.clear();
|
||||||
|
sleepingHeroes.clear();
|
||||||
|
wanderingHeroes.clear();
|
||||||
|
ownedTowns.clear();
|
||||||
|
|
||||||
|
for (auto const & town : source["towns"].Vector())
|
||||||
|
{
|
||||||
|
ObjectInstanceID objID(town["id"].Integer());
|
||||||
|
const CGTownInstance * townPtr = owner.cb->getTown(objID);
|
||||||
|
|
||||||
|
if (!townPtr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!vstd::contains(oldTowns, townPtr))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ownedTowns.push_back(townPtr);
|
||||||
|
vstd::erase(oldTowns, townPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const & hero : source["heroes"].Vector())
|
||||||
|
{
|
||||||
|
ObjectInstanceID objID(hero["id"].Integer());
|
||||||
|
const CGHeroInstance * heroPtr = owner.cb->getHero(objID);
|
||||||
|
|
||||||
|
if (!heroPtr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!vstd::contains(oldHeroes, heroPtr))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
wanderingHeroes.push_back(heroPtr);
|
||||||
|
vstd::erase(oldHeroes, heroPtr);
|
||||||
|
|
||||||
|
if (hero["sleeping"].Bool())
|
||||||
|
sleepingHeroes.push_back(heroPtr);
|
||||||
|
|
||||||
|
if (hero["path"]["x"].isNumber() && hero["path"]["y"].isNumber() && hero["path"]["z"].isNumber())
|
||||||
|
{
|
||||||
|
int3 pathTarget(hero["path"]["x"].Integer(), hero["path"]["y"].Integer(), hero["path"]["z"].Integer());
|
||||||
|
setPath(heroPtr, pathTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spellbookSettings.spellbookLastPageBattle = source["spellbook"]["pageBattle"].Integer();
|
||||||
|
spellbookSettings.spellbookLastPageAdvmap = source["spellbook"]["pageAdvmap"].Integer();
|
||||||
|
spellbookSettings.spellbookLastTabBattle = source["spellbook"]["tabBattle"].Integer();
|
||||||
|
spellbookSettings.spellbookLastTabAdvmap = source["spellbook"]["tabAdvmap"].Integer();
|
||||||
|
|
||||||
|
// append any owned heroes / towns that were not present in loaded state
|
||||||
|
wanderingHeroes.insert(wanderingHeroes.end(), oldHeroes.begin(), oldHeroes.end());
|
||||||
|
ownedTowns.insert(ownedTowns.end(), oldTowns.begin(), oldTowns.end());
|
||||||
|
|
||||||
|
//FIXME: broken, anything that is selected in here will be overwritten on NewTurn pack
|
||||||
|
// ObjectInstanceID selectedObjectID(source["currentSelection"].Integer());
|
||||||
|
// const CGObjectInstance * objectPtr = owner.cb->getObjInstance(selectedObjectID);
|
||||||
|
// const CArmedInstance * armyPtr = dynamic_cast<const CArmedInstance*>(objectPtr);
|
||||||
|
//
|
||||||
|
// if (armyPtr)
|
||||||
|
// setSelection(armyPtr);
|
||||||
|
}
|
||||||
|
@ -14,6 +14,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
|||||||
class CGHeroInstance;
|
class CGHeroInstance;
|
||||||
class CGTownInstance;
|
class CGTownInstance;
|
||||||
class CArmedInstance;
|
class CArmedInstance;
|
||||||
|
class JsonNode;
|
||||||
struct CGPath;
|
struct CGPath;
|
||||||
class int3;
|
class int3;
|
||||||
|
|
||||||
@ -21,6 +22,15 @@ VCMI_LIB_NAMESPACE_END
|
|||||||
|
|
||||||
class CPlayerInterface;
|
class CPlayerInterface;
|
||||||
|
|
||||||
|
struct PlayerSpellbookSetting
|
||||||
|
{
|
||||||
|
//on which page we left spellbook
|
||||||
|
int spellbookLastPageBattle = 0;
|
||||||
|
int spellbookLastPageAdvmap = 0;
|
||||||
|
int spellbookLastTabBattle = 4;
|
||||||
|
int spellbookLastTabAdvmap = 4;
|
||||||
|
};
|
||||||
|
|
||||||
/// Class that contains potentially serializeable state of a local player
|
/// Class that contains potentially serializeable state of a local player
|
||||||
class PlayerLocalState
|
class PlayerLocalState
|
||||||
{
|
{
|
||||||
@ -34,18 +44,10 @@ class PlayerLocalState
|
|||||||
std::vector<const CGHeroInstance *> wanderingHeroes; //our heroes on the adventure map (not the garrisoned ones)
|
std::vector<const CGHeroInstance *> wanderingHeroes; //our heroes on the adventure map (not the garrisoned ones)
|
||||||
std::vector<const CGTownInstance *> ownedTowns; //our towns on the adventure map
|
std::vector<const CGTownInstance *> ownedTowns; //our towns on the adventure map
|
||||||
|
|
||||||
void saveHeroPaths(std::map<const CGHeroInstance *, int3> & paths);
|
PlayerSpellbookSetting spellbookSettings;
|
||||||
void loadHeroPaths(std::map<const CGHeroInstance *, int3> & paths);
|
|
||||||
|
|
||||||
|
void syncronizeState();
|
||||||
public:
|
public:
|
||||||
struct SpellbookLastSetting
|
|
||||||
{
|
|
||||||
//on which page we left spellbook
|
|
||||||
int spellbookLastPageBattle = 0;
|
|
||||||
int spellbookLastPageAdvmap = 0;
|
|
||||||
int spellbookLastTabBattle = 4;
|
|
||||||
int spellbookLastTabAdvmap = 4;
|
|
||||||
} spellbookSettings;
|
|
||||||
|
|
||||||
explicit PlayerLocalState(CPlayerInterface & owner);
|
explicit PlayerLocalState(CPlayerInterface & owner);
|
||||||
|
|
||||||
@ -53,6 +55,9 @@ public:
|
|||||||
void setHeroAsleep(const CGHeroInstance * hero);
|
void setHeroAsleep(const CGHeroInstance * hero);
|
||||||
void setHeroAwaken(const CGHeroInstance * hero);
|
void setHeroAwaken(const CGHeroInstance * hero);
|
||||||
|
|
||||||
|
const PlayerSpellbookSetting & getSpellbookSettings();
|
||||||
|
void setSpellbookSettings(const PlayerSpellbookSetting & newSettings);
|
||||||
|
|
||||||
const std::vector<const CGTownInstance *> & getOwnedTowns();
|
const std::vector<const CGTownInstance *> & getOwnedTowns();
|
||||||
const CGTownInstance * getOwnedTown(size_t index);
|
const CGTownInstance * getOwnedTown(size_t index);
|
||||||
void addOwnedTown(const CGTownInstance * hero);
|
void addOwnedTown(const CGTownInstance * hero);
|
||||||
@ -81,6 +86,9 @@ public:
|
|||||||
const CGTownInstance * getCurrentTown() const;
|
const CGTownInstance * getCurrentTown() const;
|
||||||
const CArmedInstance * getCurrentArmy() const;
|
const CArmedInstance * getCurrentArmy() const;
|
||||||
|
|
||||||
|
void serialize(JsonNode & dest) const;
|
||||||
|
void deserialize(const JsonNode & source);
|
||||||
|
|
||||||
/// Changes currently selected object
|
/// Changes currently selected object
|
||||||
void setSelection(const CArmedInstance *sel);
|
void setSelection(const CArmedInstance *sel);
|
||||||
};
|
};
|
||||||
|
@ -432,7 +432,7 @@ std::shared_ptr<CIntObject> CTownList::CTownItem::genSelection()
|
|||||||
|
|
||||||
void CTownList::CTownItem::update()
|
void CTownList::CTownItem::update()
|
||||||
{
|
{
|
||||||
size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->built >= LOCPLINT->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
|
size_t iconIndex = town->getTown()->clientInfo.icons[town->hasFort()][town->built >= LOCPLINT->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
|
||||||
|
|
||||||
picture->setFrame(iconIndex + 2);
|
picture->setFrame(iconIndex + 2);
|
||||||
redraw();
|
redraw();
|
||||||
|
@ -81,9 +81,9 @@ void MapAudioPlayer::addObject(const CGObjectInstance * obj)
|
|||||||
{
|
{
|
||||||
for(int fy = 0; fy < obj->getHeight(); ++fy)
|
for(int fy = 0; fy < obj->getHeight(); ++fy)
|
||||||
{
|
{
|
||||||
int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z);
|
int3 currTile(obj->anchorPos().x - fx, obj->anchorPos().y - fy, obj->anchorPos().z);
|
||||||
|
|
||||||
if(LOCPLINT->cb->isInTheMap(currTile) && obj->coveringAt(currTile.x, currTile.y))
|
if(LOCPLINT->cb->isInTheMap(currTile) && obj->coveringAt(currTile))
|
||||||
objects[currTile.z][currTile.x][currTile.y].push_back(obj->id);
|
objects[currTile.z][currTile.x][currTile.y].push_back(obj->id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,7 +108,7 @@ void MapAudioPlayer::addObject(const CGObjectInstance * obj)
|
|||||||
|
|
||||||
for(const auto & tile : tiles)
|
for(const auto & tile : tiles)
|
||||||
{
|
{
|
||||||
int3 currTile = obj->pos + tile;
|
int3 currTile = obj->anchorPos() + tile;
|
||||||
|
|
||||||
if(LOCPLINT->cb->isInTheMap(currTile))
|
if(LOCPLINT->cb->isInTheMap(currTile))
|
||||||
objects[currTile.z][currTile.x][currTile.y].push_back(obj->id);
|
objects[currTile.z][currTile.x][currTile.y].push_back(obj->id);
|
||||||
|
@ -389,13 +389,13 @@ BattleHero::BattleHero(const BattleInterface & owner, const CGHeroInstance * her
|
|||||||
{
|
{
|
||||||
AnimationPath animationPath;
|
AnimationPath animationPath;
|
||||||
|
|
||||||
if(!hero->type->battleImage.empty())
|
if(!hero->getHeroType()->battleImage.empty())
|
||||||
animationPath = hero->type->battleImage;
|
animationPath = hero->getHeroType()->battleImage;
|
||||||
else
|
else
|
||||||
if(hero->gender == EHeroGender::FEMALE)
|
if(hero->gender == EHeroGender::FEMALE)
|
||||||
animationPath = hero->type->heroClass->imageBattleFemale;
|
animationPath = hero->getHeroClass()->imageBattleFemale;
|
||||||
else
|
else
|
||||||
animationPath = hero->type->heroClass->imageBattleMale;
|
animationPath = hero->getHeroClass()->imageBattleMale;
|
||||||
|
|
||||||
animation = GH.renderHandler().loadAnimation(animationPath, EImageBlitMode::ALPHA);
|
animation = GH.renderHandler().loadAnimation(animationPath, EImageBlitMode::ALPHA);
|
||||||
|
|
||||||
@ -1027,7 +1027,7 @@ void StackQueue::update()
|
|||||||
|
|
||||||
int32_t StackQueue::getSiegeShooterIconID()
|
int32_t StackQueue::getSiegeShooterIconID()
|
||||||
{
|
{
|
||||||
return owner.siegeController->getSiegedTown()->town->faction->getIndex();
|
return owner.siegeController->getSiegedTown()->getFactionID().getNum();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<uint32_t> StackQueue::getHoveredUnitIdIfAny() const
|
std::optional<uint32_t> StackQueue::getHoveredUnitIdIfAny() const
|
||||||
|
@ -58,14 +58,14 @@ ImagePath BattleSiegeController::getWallPieceImageName(EWallVisual::EWallVisual
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::string & prefix = town->town->clientInfo.siegePrefix;
|
const std::string & prefix = town->getTown()->clientInfo.siegePrefix;
|
||||||
std::string addit = std::to_string(getImageIndex());
|
std::string addit = std::to_string(getImageIndex());
|
||||||
|
|
||||||
switch(what)
|
switch(what)
|
||||||
{
|
{
|
||||||
case EWallVisual::BACKGROUND_WALL:
|
case EWallVisual::BACKGROUND_WALL:
|
||||||
{
|
{
|
||||||
auto faction = town->town->faction->getIndex();
|
auto faction = town->getFactionID();
|
||||||
|
|
||||||
if (faction == ETownType::RAMPART || faction == ETownType::NECROPOLIS || faction == ETownType::DUNGEON || faction == ETownType::STRONGHOLD)
|
if (faction == ETownType::RAMPART || faction == ETownType::NECROPOLIS || faction == ETownType::DUNGEON || faction == ETownType::STRONGHOLD)
|
||||||
return ImagePath::builtinTODO(prefix + "TPW1.BMP");
|
return ImagePath::builtinTODO(prefix + "TPW1.BMP");
|
||||||
@ -111,7 +111,7 @@ ImagePath BattleSiegeController::getWallPieceImageName(EWallVisual::EWallVisual
|
|||||||
|
|
||||||
void BattleSiegeController::showWallPiece(Canvas & canvas, EWallVisual::EWallVisual what)
|
void BattleSiegeController::showWallPiece(Canvas & canvas, EWallVisual::EWallVisual what)
|
||||||
{
|
{
|
||||||
auto & ci = town->town->clientInfo;
|
auto & ci = town->getTown()->clientInfo;
|
||||||
auto const & pos = ci.siegePositions[what];
|
auto const & pos = ci.siegePositions[what];
|
||||||
|
|
||||||
if ( wallPieceImages[what] && pos.isValid())
|
if ( wallPieceImages[what] && pos.isValid())
|
||||||
@ -120,7 +120,7 @@ void BattleSiegeController::showWallPiece(Canvas & canvas, EWallVisual::EWallVis
|
|||||||
|
|
||||||
ImagePath BattleSiegeController::getBattleBackgroundName() const
|
ImagePath BattleSiegeController::getBattleBackgroundName() const
|
||||||
{
|
{
|
||||||
const std::string & prefix = town->town->clientInfo.siegePrefix;
|
const std::string & prefix = town->getTown()->clientInfo.siegePrefix;
|
||||||
return ImagePath::builtinTODO(prefix + "BACK.BMP");
|
return ImagePath::builtinTODO(prefix + "BACK.BMP");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,8 +130,8 @@ bool BattleSiegeController::getWallPieceExistence(EWallVisual::EWallVisual what)
|
|||||||
|
|
||||||
switch (what)
|
switch (what)
|
||||||
{
|
{
|
||||||
case EWallVisual::MOAT: return fortifications.hasMoat && town->town->clientInfo.siegePositions.at(EWallVisual::MOAT).isValid();
|
case EWallVisual::MOAT: return fortifications.hasMoat && town->getTown()->clientInfo.siegePositions.at(EWallVisual::MOAT).isValid();
|
||||||
case EWallVisual::MOAT_BANK: return fortifications.hasMoat && town->town->clientInfo.siegePositions.at(EWallVisual::MOAT_BANK).isValid();
|
case EWallVisual::MOAT_BANK: return fortifications.hasMoat && town->getTown()->clientInfo.siegePositions.at(EWallVisual::MOAT_BANK).isValid();
|
||||||
case EWallVisual::KEEP_BATTLEMENT: return fortifications.citadelHealth > 0 && owner.getBattle()->battleGetWallState(EWallPart::KEEP) != EWallState::DESTROYED;
|
case EWallVisual::KEEP_BATTLEMENT: return fortifications.citadelHealth > 0 && owner.getBattle()->battleGetWallState(EWallPart::KEEP) != EWallState::DESTROYED;
|
||||||
case EWallVisual::UPPER_BATTLEMENT: return fortifications.upperTowerHealth > 0 && owner.getBattle()->battleGetWallState(EWallPart::UPPER_TOWER) != EWallState::DESTROYED;
|
case EWallVisual::UPPER_BATTLEMENT: return fortifications.upperTowerHealth > 0 && owner.getBattle()->battleGetWallState(EWallPart::UPPER_TOWER) != EWallState::DESTROYED;
|
||||||
case EWallVisual::BOTTOM_BATTLEMENT: return fortifications.lowerTowerHealth > 0 && owner.getBattle()->battleGetWallState(EWallPart::BOTTOM_TOWER) != EWallState::DESTROYED;
|
case EWallVisual::BOTTOM_BATTLEMENT: return fortifications.lowerTowerHealth > 0 && owner.getBattle()->battleGetWallState(EWallPart::BOTTOM_TOWER) != EWallState::DESTROYED;
|
||||||
@ -218,8 +218,8 @@ Point BattleSiegeController::getTurretCreaturePosition( BattleHex position ) con
|
|||||||
if (posID != 0)
|
if (posID != 0)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
town->town->clientInfo.siegePositions[posID].x,
|
town->getTown()->clientInfo.siegePositions[posID].x,
|
||||||
town->town->clientInfo.siegePositions[posID].y
|
town->getTown()->clientInfo.siegePositions[posID].y
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,8 +250,8 @@ void CGuiHandler::setStatusbar(std::shared_ptr<IStatusBar> newStatusBar)
|
|||||||
void CGuiHandler::onScreenResize(bool resolutionChanged)
|
void CGuiHandler::onScreenResize(bool resolutionChanged)
|
||||||
{
|
{
|
||||||
if(resolutionChanged)
|
if(resolutionChanged)
|
||||||
{
|
|
||||||
screenHandler().onScreenResize();
|
screenHandler().onScreenResize();
|
||||||
}
|
|
||||||
windows().onScreenResize();
|
windows().onScreenResize();
|
||||||
|
CCS->curh->onScreenResize();
|
||||||
}
|
}
|
||||||
|
@ -312,3 +312,8 @@ void CursorHandler::changeCursor(Cursor::ShowType newShowType)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CursorHandler::onScreenResize()
|
||||||
|
{
|
||||||
|
cursor->setImage(getCurrentImage(), getPivotOffset());
|
||||||
|
}
|
||||||
|
@ -182,6 +182,7 @@ public:
|
|||||||
|
|
||||||
void hide();
|
void hide();
|
||||||
void show();
|
void show();
|
||||||
|
void onScreenResize();
|
||||||
|
|
||||||
/// change cursor's positions to (x, y)
|
/// change cursor's positions to (x, y)
|
||||||
void cursorMove(const int & x, const int & y);
|
void cursorMove(const int & x, const int & y);
|
||||||
|
@ -480,11 +480,11 @@ void SelectionTab::filter(int size, bool selectFirst)
|
|||||||
if((elem->mapHeader && (!size || elem->mapHeader->width == size)) || tabType == ESelectionScreen::campaignList)
|
if((elem->mapHeader && (!size || elem->mapHeader->width == size)) || tabType == ESelectionScreen::campaignList)
|
||||||
{
|
{
|
||||||
if(showRandom)
|
if(showRandom)
|
||||||
curFolder = "RANDOMMAPS/";
|
curFolder = "RandomMaps/";
|
||||||
|
|
||||||
auto [folderName, baseFolder, parentExists, fileInFolder] = checkSubfolder(elem->originalFileURI);
|
auto [folderName, baseFolder, parentExists, fileInFolder] = checkSubfolder(elem->originalFileURI);
|
||||||
|
|
||||||
if((showRandom && baseFolder != "RANDOMMAPS") || (!showRandom && baseFolder == "RANDOMMAPS"))
|
if((showRandom && baseFolder != "RandomMaps") || (!showRandom && baseFolder == "RandomMaps"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(parentExists && !showRandom)
|
if(parentExists && !showRandom)
|
||||||
@ -715,7 +715,7 @@ void SelectionTab::selectFileName(std::string fname)
|
|||||||
selectAbs(-1);
|
selectAbs(-1);
|
||||||
|
|
||||||
if(tabType == ESelectionScreen::saveGame && inputName->getText().empty())
|
if(tabType == ESelectionScreen::saveGame && inputName->getText().empty())
|
||||||
inputName->setText("NEWGAME");
|
inputName->setText(CGI->generaltexth->translate("core.genrltxt.11"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectionTab::selectNewestFile()
|
void SelectionTab::selectNewestFile()
|
||||||
@ -808,7 +808,8 @@ void SelectionTab::parseMaps(const std::unordered_set<ResourcePath> & files)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto mapInfo = std::make_shared<ElementInfo>();
|
auto mapInfo = std::make_shared<ElementInfo>();
|
||||||
mapInfo->mapInit(file.getName());
|
mapInfo->mapInit(file.getOriginalName());
|
||||||
|
mapInfo->name = mapInfo->getNameForList();
|
||||||
|
|
||||||
if (isMapSupported(*mapInfo))
|
if (isMapSupported(*mapInfo))
|
||||||
allItems.push_back(mapInfo);
|
allItems.push_back(mapInfo);
|
||||||
@ -873,7 +874,7 @@ void SelectionTab::parseCampaigns(const std::unordered_set<ResourcePath> & files
|
|||||||
{
|
{
|
||||||
auto info = std::make_shared<ElementInfo>();
|
auto info = std::make_shared<ElementInfo>();
|
||||||
//allItems[i].date = std::asctime(std::localtime(&files[i].date));
|
//allItems[i].date = std::asctime(std::localtime(&files[i].date));
|
||||||
info->fileURI = file.getName();
|
info->fileURI = file.getOriginalName();
|
||||||
info->campaignInit();
|
info->campaignInit();
|
||||||
if(info->campaign)
|
if(info->campaign)
|
||||||
allItems.push_back(info);
|
allItems.push_back(info);
|
||||||
@ -988,6 +989,6 @@ void SelectionTab::ListItem::updateItem(std::shared_ptr<ElementInfo> info, bool
|
|||||||
iconLossCondition->setFrame(info->mapHeader->defeatIconIndex, 0);
|
iconLossCondition->setFrame(info->mapHeader->defeatIconIndex, 0);
|
||||||
labelName->setMaxWidth(185);
|
labelName->setMaxWidth(185);
|
||||||
}
|
}
|
||||||
labelName->setText(info->getNameForList());
|
labelName->setText(info->name);
|
||||||
labelName->setColor(color);
|
labelName->setColor(color);
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ public:
|
|||||||
ElementInfo() : CMapInfo() { }
|
ElementInfo() : CMapInfo() { }
|
||||||
~ElementInfo() { }
|
~ElementInfo() { }
|
||||||
std::string folderName = "";
|
std::string folderName = "";
|
||||||
|
std::string name = "";
|
||||||
bool isFolder = false;
|
bool isFolder = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -591,8 +591,8 @@ void MapRendererOverlay::renderTile(IMapRendererContext & context, Canvas & targ
|
|||||||
|
|
||||||
if(context.objectTransparency(objectID, coordinates) > 0 && !context.isActiveHero(object))
|
if(context.objectTransparency(objectID, coordinates) > 0 && !context.isActiveHero(object))
|
||||||
{
|
{
|
||||||
visitable |= object->visitableAt(coordinates.x, coordinates.y);
|
visitable |= object->visitableAt(coordinates);
|
||||||
blocking |= object->blockingAt(coordinates.x, coordinates.y);
|
blocking |= object->blockingAt(coordinates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ size_t MapRendererBaseContext::objectGroupIndex(ObjectInstanceID objectID) const
|
|||||||
Point MapRendererBaseContext::objectImageOffset(ObjectInstanceID objectID, const int3 & coordinates) const
|
Point MapRendererBaseContext::objectImageOffset(ObjectInstanceID objectID, const int3 & coordinates) const
|
||||||
{
|
{
|
||||||
const CGObjectInstance * object = getObject(objectID);
|
const CGObjectInstance * object = getObject(objectID);
|
||||||
int3 offsetTiles(object->getPosition() - coordinates);
|
int3 offsetTiles(object->anchorPos() - coordinates);
|
||||||
return Point(offsetTiles) * Point(32, 32);
|
return Point(offsetTiles) * Point(32, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,7 +498,7 @@ size_t MapRendererWorldViewContext::overlayImageIndex(const int3 & coordinates)
|
|||||||
{
|
{
|
||||||
const auto * object = getObject(objectID);
|
const auto * object = getObject(objectID);
|
||||||
|
|
||||||
if(!object->visitableAt(coordinates.x, coordinates.y))
|
if(!object->visitableAt(coordinates))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ObjectPosInfo info(object);
|
ObjectPosInfo info(object);
|
||||||
|
@ -49,9 +49,9 @@ void MapRendererContextState::addObject(const CGObjectInstance * obj)
|
|||||||
{
|
{
|
||||||
for(int fy = 0; fy < obj->getHeight(); ++fy)
|
for(int fy = 0; fy < obj->getHeight(); ++fy)
|
||||||
{
|
{
|
||||||
int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z);
|
int3 currTile(obj->anchorPos().x - fx, obj->anchorPos().y - fy, obj->anchorPos().z);
|
||||||
|
|
||||||
if(LOCPLINT->cb->isInTheMap(currTile) && obj->coveringAt(currTile.x, currTile.y))
|
if(LOCPLINT->cb->isInTheMap(currTile) && obj->coveringAt(currTile))
|
||||||
{
|
{
|
||||||
auto & container = objects[currTile.z][currTile.x][currTile.y];
|
auto & container = objects[currTile.z][currTile.x][currTile.y];
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ void MapRendererContextState::addMovingObject(const CGObjectInstance * object, c
|
|||||||
{
|
{
|
||||||
for(int y = yFrom; y <= yDest; ++y)
|
for(int y = yFrom; y <= yDest; ++y)
|
||||||
{
|
{
|
||||||
int3 currTile(x, y, object->pos.z);
|
int3 currTile(x, y, object->anchorPos().z);
|
||||||
|
|
||||||
if(LOCPLINT->cb->isInTheMap(currTile))
|
if(LOCPLINT->cb->isInTheMap(currTile))
|
||||||
{
|
{
|
||||||
|
@ -317,7 +317,7 @@ bool MapViewController::isEventVisible(const CGObjectInstance * obj, const Playe
|
|||||||
if(obj->isVisitable())
|
if(obj->isVisitable())
|
||||||
return context->isVisible(obj->visitablePos());
|
return context->isVisible(obj->visitablePos());
|
||||||
else
|
else
|
||||||
return context->isVisible(obj->pos);
|
return context->isVisible(obj->anchorPos());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MapViewController::isEventVisible(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
|
bool MapViewController::isEventVisible(const CGHeroInstance * obj, const int3 & from, const int3 & dest)
|
||||||
|
@ -59,7 +59,7 @@ std::string CMapHandler::getTerrainDescr(const int3 & pos, bool rightClick) cons
|
|||||||
|
|
||||||
for(const auto & object : map->objects)
|
for(const auto & object : map->objects)
|
||||||
{
|
{
|
||||||
if(object && object->coveringAt(pos.x, pos.y) && object->pos.z == pos.z && object->isTile2Terrain())
|
if(object && object->coveringAt(pos) && object->isTile2Terrain())
|
||||||
{
|
{
|
||||||
result = object->getObjectName();
|
result = object->getObjectName();
|
||||||
break;
|
break;
|
||||||
@ -103,15 +103,15 @@ bool CMapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObj
|
|||||||
|
|
||||||
for(const auto & aOffset : a->getBlockedOffsets())
|
for(const auto & aOffset : a->getBlockedOffsets())
|
||||||
{
|
{
|
||||||
int3 testTarget = a->pos + aOffset + int3(0, 1, 0);
|
int3 testTarget = a->anchorPos() + aOffset + int3(0, 1, 0);
|
||||||
if(b->blockingAt(testTarget.x, testTarget.y))
|
if(b->blockingAt(testTarget))
|
||||||
bBlocksA += 1;
|
bBlocksA += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const auto & bOffset : b->getBlockedOffsets())
|
for(const auto & bOffset : b->getBlockedOffsets())
|
||||||
{
|
{
|
||||||
int3 testTarget = b->pos + bOffset + int3(0, 1, 0);
|
int3 testTarget = b->anchorPos() + bOffset + int3(0, 1, 0);
|
||||||
if(a->blockingAt(testTarget.x, testTarget.y))
|
if(a->blockingAt(testTarget))
|
||||||
aBlocksB += 1;
|
aBlocksB += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,8 +126,8 @@ bool CMapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObj
|
|||||||
return aBlocksB < bBlocksA;
|
return aBlocksB < bBlocksA;
|
||||||
|
|
||||||
// object that don't have clear priority via tile blocking will appear based on their row
|
// object that don't have clear priority via tile blocking will appear based on their row
|
||||||
if(a->pos.y != b->pos.y)
|
if(a->anchorPos().y != b->anchorPos().y)
|
||||||
return a->pos.y < b->pos.y;
|
return a->anchorPos().y < b->anchorPos().y;
|
||||||
|
|
||||||
// heroes should appear on top of objects on the same tile
|
// heroes should appear on top of objects on the same tile
|
||||||
if(b->ID==Obj::HERO && a->ID!=Obj::HERO)
|
if(b->ID==Obj::HERO && a->ID!=Obj::HERO)
|
||||||
|
@ -608,9 +608,8 @@ std::pair<std::unique_ptr<ui8 []>, si64> CAudioInstance::extractAudio(const Vide
|
|||||||
bool CVideoPlayer::openAndPlayVideoImpl(const VideoPath & name, const Point & position, bool useOverlay, bool stopOnKey)
|
bool CVideoPlayer::openAndPlayVideoImpl(const VideoPath & name, const Point & position, bool useOverlay, bool stopOnKey)
|
||||||
{
|
{
|
||||||
CVideoInstance instance;
|
CVideoInstance instance;
|
||||||
CAudioInstance audio;
|
|
||||||
|
|
||||||
auto extractedAudio = audio.extractAudio(name);
|
auto extractedAudio = getAudio(name);
|
||||||
int audioHandle = CCS->soundh->playSound(extractedAudio);
|
int audioHandle = CCS->soundh->playSound(extractedAudio);
|
||||||
|
|
||||||
if (!instance.openInput(name))
|
if (!instance.openInput(name))
|
||||||
@ -684,6 +683,15 @@ std::unique_ptr<IVideoInstance> CVideoPlayer::open(const VideoPath & name, float
|
|||||||
|
|
||||||
std::pair<std::unique_ptr<ui8[]>, si64> CVideoPlayer::getAudio(const VideoPath & videoToOpen)
|
std::pair<std::unique_ptr<ui8[]>, si64> CVideoPlayer::getAudio(const VideoPath & videoToOpen)
|
||||||
{
|
{
|
||||||
|
AudioPath audioPath = videoToOpen.toType<EResType::SOUND>();
|
||||||
|
AudioPath audioPathVideoDir = audioPath.addPrefix("VIDEO/");
|
||||||
|
|
||||||
|
if(CResourceHandler::get()->existsResource(audioPath))
|
||||||
|
return CResourceHandler::get()->load(audioPath)->readAll();
|
||||||
|
|
||||||
|
if(CResourceHandler::get()->existsResource(audioPathVideoDir))
|
||||||
|
return CResourceHandler::get()->load(audioPathVideoDir)->readAll();
|
||||||
|
|
||||||
CAudioInstance audio;
|
CAudioInstance audio;
|
||||||
return audio.extractAudio(videoToOpen);
|
return audio.extractAudio(videoToOpen);
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,8 @@ public:
|
|||||||
/// Dimensions of logical output. Can be different if scaling is used
|
/// Dimensions of logical output. Can be different if scaling is used
|
||||||
virtual Point getLogicalResolution() const = 0;
|
virtual Point getLogicalResolution() const = 0;
|
||||||
|
|
||||||
|
virtual int getInterfaceScalingPercentage() const = 0;
|
||||||
|
|
||||||
virtual int getScalingFactor() const = 0;
|
virtual int getScalingFactor() const = 0;
|
||||||
|
|
||||||
/// Window has focus
|
/// Window has focus
|
||||||
|
@ -11,11 +11,14 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
#include "CursorHardware.h"
|
#include "CursorHardware.h"
|
||||||
|
|
||||||
|
#include "SDL_Extensions.h"
|
||||||
|
|
||||||
#include "../gui/CGuiHandler.h"
|
#include "../gui/CGuiHandler.h"
|
||||||
#include "../render/IScreenHandler.h"
|
#include "../render/IScreenHandler.h"
|
||||||
#include "../render/Colors.h"
|
#include "../render/Colors.h"
|
||||||
#include "../render/IImage.h"
|
#include "../render/IImage.h"
|
||||||
#include "SDL_Extensions.h"
|
|
||||||
|
#include "../../lib/CConfigHandler.h"
|
||||||
|
|
||||||
#include <SDL_render.h>
|
#include <SDL_render.h>
|
||||||
#include <SDL_events.h>
|
#include <SDL_events.h>
|
||||||
@ -45,19 +48,28 @@ void CursorHardware::setVisible(bool on)
|
|||||||
|
|
||||||
void CursorHardware::setImage(std::shared_ptr<IImage> image, const Point & pivotOffset)
|
void CursorHardware::setImage(std::shared_ptr<IImage> image, const Point & pivotOffset)
|
||||||
{
|
{
|
||||||
auto cursorSurface = CSDL_Ext::newSurface(image->dimensions() * GH.screenHandler().getScalingFactor());
|
int videoScalingSettings = GH.screenHandler().getInterfaceScalingPercentage();
|
||||||
|
float cursorScalingSettings = settings["video"]["cursorScalingFactor"].Float();
|
||||||
|
int cursorScalingPercent = videoScalingSettings * cursorScalingSettings;
|
||||||
|
Point cursorDimensions = image->dimensions() * GH.screenHandler().getScalingFactor();
|
||||||
|
Point cursorDimensionsScaled = image->dimensions() * cursorScalingPercent / 100;
|
||||||
|
Point pivotOffsetScaled = pivotOffset * cursorScalingPercent / 100 / GH.screenHandler().getScalingFactor();
|
||||||
|
|
||||||
|
auto cursorSurface = CSDL_Ext::newSurface(cursorDimensions);
|
||||||
|
|
||||||
CSDL_Ext::fillSurface(cursorSurface, CSDL_Ext::toSDL(Colors::TRANSPARENCY));
|
CSDL_Ext::fillSurface(cursorSurface, CSDL_Ext::toSDL(Colors::TRANSPARENCY));
|
||||||
|
|
||||||
image->draw(cursorSurface, Point(0,0));
|
image->draw(cursorSurface, Point(0,0));
|
||||||
|
auto cursorSurfaceScaled = CSDL_Ext::scaleSurface(cursorSurface, cursorDimensionsScaled.x, cursorDimensionsScaled.y );
|
||||||
|
|
||||||
auto oldCursor = cursor;
|
auto oldCursor = cursor;
|
||||||
cursor = SDL_CreateColorCursor(cursorSurface, pivotOffset.x, pivotOffset.y);
|
cursor = SDL_CreateColorCursor(cursorSurfaceScaled, pivotOffsetScaled.x, pivotOffsetScaled.y);
|
||||||
|
|
||||||
if (!cursor)
|
if (!cursor)
|
||||||
logGlobal->error("Failed to set cursor! SDL says %s", SDL_GetError());
|
logGlobal->error("Failed to set cursor! SDL says %s", SDL_GetError());
|
||||||
|
|
||||||
SDL_FreeSurface(cursorSurface);
|
SDL_FreeSurface(cursorSurface);
|
||||||
|
SDL_FreeSurface(cursorSurfaceScaled);
|
||||||
|
|
||||||
GH.dispatchMainThread([this, oldCursor](){
|
GH.dispatchMainThread([this, oldCursor](){
|
||||||
SDL_SetCursor(cursor);
|
SDL_SetCursor(cursor);
|
||||||
|
@ -84,19 +84,39 @@ Rect ScreenHandler::convertLogicalPointsToWindow(const Rect & input) const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ScreenHandler::getInterfaceScalingPercentage() const
|
||||||
|
{
|
||||||
|
auto [minimalScaling, maximalScaling] = getSupportedScalingRange();
|
||||||
|
|
||||||
|
int userScaling = settings["video"]["resolution"]["scaling"].Integer();
|
||||||
|
|
||||||
|
if (userScaling == 0) // autodetection
|
||||||
|
{
|
||||||
|
#ifdef VCMI_MOBILE
|
||||||
|
// for mobiles - stay at maximum scaling unless we have large screen
|
||||||
|
// might be better to check screen DPI / physical dimensions, but way more complex, and may result in different edge cases, e.g. chromebooks / tv's
|
||||||
|
int preferredMinimalScaling = 200;
|
||||||
|
#else
|
||||||
|
// for PC - avoid downscaling if possible
|
||||||
|
int preferredMinimalScaling = 100;
|
||||||
|
#endif
|
||||||
|
// prefer a little below maximum - to give space for extended UI
|
||||||
|
int preferredMaximalScaling = maximalScaling * 10 / 12;
|
||||||
|
userScaling = std::max(std::min(maximalScaling, preferredMinimalScaling), preferredMaximalScaling);
|
||||||
|
}
|
||||||
|
|
||||||
|
int scaling = std::clamp(userScaling, minimalScaling, maximalScaling);
|
||||||
|
return scaling;
|
||||||
|
}
|
||||||
|
|
||||||
Point ScreenHandler::getPreferredLogicalResolution() const
|
Point ScreenHandler::getPreferredLogicalResolution() const
|
||||||
{
|
{
|
||||||
Point renderResolution = getRenderResolution();
|
Point renderResolution = getRenderResolution();
|
||||||
double reservedAreaWidth = settings["video"]["reservedWidth"].Float();
|
double reservedAreaWidth = settings["video"]["reservedWidth"].Float();
|
||||||
|
|
||||||
|
int scaling = getInterfaceScalingPercentage();
|
||||||
Point availableResolution = Point(renderResolution.x * (1 - reservedAreaWidth), renderResolution.y);
|
Point availableResolution = Point(renderResolution.x * (1 - reservedAreaWidth), renderResolution.y);
|
||||||
|
|
||||||
auto [minimalScaling, maximalScaling] = getSupportedScalingRange();
|
|
||||||
|
|
||||||
int userScaling = settings["video"]["resolution"]["scaling"].Integer();
|
|
||||||
int scaling = std::clamp(userScaling, minimalScaling, maximalScaling);
|
|
||||||
|
|
||||||
Point logicalResolution = availableResolution * 100.0 / scaling;
|
Point logicalResolution = availableResolution * 100.0 / scaling;
|
||||||
|
|
||||||
return logicalResolution;
|
return logicalResolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,25 +355,22 @@ EUpscalingFilter ScreenHandler::loadUpscalingFilter() const
|
|||||||
if (filter != EUpscalingFilter::AUTO)
|
if (filter != EUpscalingFilter::AUTO)
|
||||||
return filter;
|
return filter;
|
||||||
|
|
||||||
// for now - always fallback to no filter
|
|
||||||
return EUpscalingFilter::NONE;
|
|
||||||
|
|
||||||
// else - autoselect
|
// else - autoselect
|
||||||
// Point outputResolution = getRenderResolution();
|
Point outputResolution = getRenderResolution();
|
||||||
// Point logicalResolution = getPreferredLogicalResolution();
|
Point logicalResolution = getPreferredLogicalResolution();
|
||||||
//
|
|
||||||
// float scaleX = static_cast<float>(outputResolution.x) / logicalResolution.x;
|
float scaleX = static_cast<float>(outputResolution.x) / logicalResolution.x;
|
||||||
// float scaleY = static_cast<float>(outputResolution.x) / logicalResolution.x;
|
float scaleY = static_cast<float>(outputResolution.x) / logicalResolution.x;
|
||||||
// float scaling = std::min(scaleX, scaleY);
|
float scaling = std::min(scaleX, scaleY);
|
||||||
//
|
|
||||||
// if (scaling <= 1.0f)
|
if (scaling <= 1.001f)
|
||||||
// return EUpscalingFilter::NONE;
|
return EUpscalingFilter::NONE; // running at original resolution or even lower than that - no need for xbrz
|
||||||
// if (scaling <= 2.0f)
|
if (scaling <= 2.001f)
|
||||||
// return EUpscalingFilter::XBRZ_2;
|
return EUpscalingFilter::XBRZ_2; // resolutions below 1200p (including 1080p / FullHD)
|
||||||
// if (scaling <= 3.0f)
|
if (scaling <= 3.001f)
|
||||||
// return EUpscalingFilter::XBRZ_3;
|
return EUpscalingFilter::XBRZ_3; // resolutions below 2400p (including 1440p and 2160p / 4K)
|
||||||
//
|
|
||||||
// return EUpscalingFilter::XBRZ_4;
|
return EUpscalingFilter::XBRZ_4; // Only for massive displays, e.g. 8K
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenHandler::selectUpscalingFilter()
|
void ScreenHandler::selectUpscalingFilter()
|
||||||
|
@ -112,6 +112,8 @@ public:
|
|||||||
|
|
||||||
int getScalingFactor() const final;
|
int getScalingFactor() const final;
|
||||||
|
|
||||||
|
int getInterfaceScalingPercentage() const final;
|
||||||
|
|
||||||
std::vector<Point> getSupportedResolutions() const final;
|
std::vector<Point> getSupportedResolutions() const final;
|
||||||
std::vector<Point> getSupportedResolutions(int displayIndex) const;
|
std::vector<Point> getSupportedResolutions(int displayIndex) const;
|
||||||
std::tuple<int, int> getSupportedScalingRange() const final;
|
std::tuple<int, int> getSupportedScalingRange() const final;
|
||||||
|
@ -468,8 +468,8 @@ void CInteractableTownTooltip::init(const CGTownInstance * town)
|
|||||||
LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
|
LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
|
||||||
}
|
}
|
||||||
}, [town]{
|
}, [town]{
|
||||||
if(!town->town->faction->getDescriptionTranslated().empty())
|
if(!town->getFaction()->getDescriptionTranslated().empty())
|
||||||
CRClickPopup::createAndPush(town->town->faction->getDescriptionTranslated());
|
CRClickPopup::createAndPush(town->getFaction()->getDescriptionTranslated());
|
||||||
});
|
});
|
||||||
fastMarket = std::make_shared<LRClickableArea>(Rect(143, 31, 30, 34), []()
|
fastMarket = std::make_shared<LRClickableArea>(Rect(143, 31, 30, 34), []()
|
||||||
{
|
{
|
||||||
@ -532,8 +532,7 @@ CreatureTooltip::CreatureTooltip(Point pos, const CGCreature * creature)
|
|||||||
{
|
{
|
||||||
OBJECT_CONSTRUCTION;
|
OBJECT_CONSTRUCTION;
|
||||||
|
|
||||||
auto creatureID = creature->getCreature();
|
int32_t creatureIconIndex = creature->getCreature()->getIconIndex();
|
||||||
int32_t creatureIconIndex = CGI->creatures()->getById(creatureID)->getIconIndex();
|
|
||||||
|
|
||||||
creatureImage = std::make_shared<CAnimImage>(AnimationPath::builtin("TWCRPORT"), creatureIconIndex);
|
creatureImage = std::make_shared<CAnimImage>(AnimationPath::builtin("TWCRPORT"), creatureIconIndex);
|
||||||
creatureImage->center(Point(parent->pos.x + parent->pos.w / 2, parent->pos.y + creatureImage->pos.h / 2 + 11));
|
creatureImage->center(Point(parent->pos.x + parent->pos.w / 2, parent->pos.y + creatureImage->pos.h / 2 + 11));
|
||||||
@ -633,7 +632,7 @@ CCreaturePic::CCreaturePic(int x, int y, const CCreature * cre, bool Big, bool A
|
|||||||
pos.x+=x;
|
pos.x+=x;
|
||||||
pos.y+=y;
|
pos.y+=y;
|
||||||
|
|
||||||
auto faction = cre->getFaction();
|
auto faction = cre->getFactionID();
|
||||||
|
|
||||||
assert(CGI->townh->size() > faction);
|
assert(CGI->townh->size() > faction);
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ CBuildingRect::CBuildingRect(CCastleBuildings * Par, const CGTownInstance * Town
|
|||||||
|
|
||||||
// special animation frame manipulation for castle shipyard with and without ship
|
// special animation frame manipulation for castle shipyard with and without ship
|
||||||
// done due to .def used in special way, not to animate building - first image is for shipyard without citadel moat, 2nd image is for including moat
|
// done due to .def used in special way, not to animate building - first image is for shipyard without citadel moat, 2nd image is for including moat
|
||||||
if(Town->town->faction->getId() == FactionID::CASTLE && Str->building &&
|
if(Town->getFactionID() == FactionID::CASTLE && Str->building &&
|
||||||
(Str->building->bid == BuildingID::SHIPYARD || Str->building->bid == BuildingID::SHIP))
|
(Str->building->bid == BuildingID::SHIPYARD || Str->building->bid == BuildingID::SHIP))
|
||||||
{
|
{
|
||||||
if(Town->hasBuilt(BuildingID::CITADEL))
|
if(Town->hasBuilt(BuildingID::CITADEL))
|
||||||
@ -107,7 +107,7 @@ const CBuilding * CBuildingRect::getBuilding()
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (str->hiddenUpgrade) // hidden upgrades, e.g. hordes - return base (dwelling for hordes)
|
if (str->hiddenUpgrade) // hidden upgrades, e.g. hordes - return base (dwelling for hordes)
|
||||||
return town->town->buildings.at(str->building->getBase());
|
return town->getTown()->buildings.at(str->building->getBase());
|
||||||
|
|
||||||
return str->building;
|
return str->building;
|
||||||
}
|
}
|
||||||
@ -156,7 +156,7 @@ void CBuildingRect::showPopupWindow(const Point & cursorPosition)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
BuildingID bid = getBuilding()->bid;
|
BuildingID bid = getBuilding()->bid;
|
||||||
const CBuilding *bld = town->town->buildings.at(bid);
|
const CBuilding *bld = town->getTown()->buildings.at(bid);
|
||||||
if (bid < BuildingID::DWELL_FIRST)
|
if (bid < BuildingID::DWELL_FIRST)
|
||||||
{
|
{
|
||||||
CRClickPopup::createAndPush(CInfoWindow::genText(bld->getNameTranslated(), bld->getDescriptionTranslated()),
|
CRClickPopup::createAndPush(CInfoWindow::genText(bld->getNameTranslated(), bld->getDescriptionTranslated()),
|
||||||
@ -235,10 +235,10 @@ std::string CBuildingRect::getSubtitle()//hover text for building
|
|||||||
int bid = getBuilding()->bid;
|
int bid = getBuilding()->bid;
|
||||||
|
|
||||||
if (bid<30)//non-dwellings - only building name
|
if (bid<30)//non-dwellings - only building name
|
||||||
return town->town->buildings.at(getBuilding()->bid)->getNameTranslated();
|
return town->getTown()->buildings.at(getBuilding()->bid)->getNameTranslated();
|
||||||
else//dwellings - recruit %creature%
|
else//dwellings - recruit %creature%
|
||||||
{
|
{
|
||||||
auto & availableCreatures = town->creatures[(bid-30)%town->town->creatures.size()].second;
|
auto & availableCreatures = town->creatures[(bid-30)%town->getTown()->creatures.size()].second;
|
||||||
if(availableCreatures.size())
|
if(availableCreatures.size())
|
||||||
{
|
{
|
||||||
int creaID = availableCreatures.back();//taking last of available creatures
|
int creaID = availableCreatures.back();//taking last of available creatures
|
||||||
@ -566,7 +566,7 @@ CCastleBuildings::CCastleBuildings(const CGTownInstance* Town):
|
|||||||
{
|
{
|
||||||
OBJECT_CONSTRUCTION;
|
OBJECT_CONSTRUCTION;
|
||||||
|
|
||||||
background = std::make_shared<CPicture>(town->town->clientInfo.townBackground);
|
background = std::make_shared<CPicture>(town->getTown()->clientInfo.townBackground);
|
||||||
background->needRefresh = true;
|
background->needRefresh = true;
|
||||||
background->getSurface()->setBlitMode(EImageBlitMode::OPAQUE);
|
background->getSurface()->setBlitMode(EImageBlitMode::OPAQUE);
|
||||||
pos.w = background->pos.w;
|
pos.w = background->pos.w;
|
||||||
@ -602,7 +602,7 @@ void CCastleBuildings::recreate()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const CStructure * structure : town->town->clientInfo.structures)
|
for(const CStructure * structure : town->getTown()->clientInfo.structures)
|
||||||
{
|
{
|
||||||
if(!structure->building)
|
if(!structure->building)
|
||||||
{
|
{
|
||||||
@ -617,7 +617,7 @@ void CCastleBuildings::recreate()
|
|||||||
|
|
||||||
for(auto & entry : groups)
|
for(auto & entry : groups)
|
||||||
{
|
{
|
||||||
const CBuilding * build = town->town->buildings.at(entry.first);
|
const CBuilding * build = town->getTown()->buildings.at(entry.first);
|
||||||
|
|
||||||
const CStructure * toAdd = *boost::max_element(entry.second, [=](const CStructure * a, const CStructure * b)
|
const CStructure * toAdd = *boost::max_element(entry.second, [=](const CStructure * a, const CStructure * b)
|
||||||
{
|
{
|
||||||
@ -648,7 +648,7 @@ void CCastleBuildings::recreate()
|
|||||||
void CCastleBuildings::addBuilding(BuildingID building)
|
void CCastleBuildings::addBuilding(BuildingID building)
|
||||||
{
|
{
|
||||||
//FIXME: implement faster method without complete recreation of town
|
//FIXME: implement faster method without complete recreation of town
|
||||||
BuildingID base = town->town->buildings.at(building)->getBase();
|
BuildingID base = town->getTown()->buildings.at(building)->getBase();
|
||||||
|
|
||||||
recreate();
|
recreate();
|
||||||
|
|
||||||
@ -687,7 +687,7 @@ void CCastleBuildings::buildingClicked(BuildingID building)
|
|||||||
BuildingID buildingToEnter = building;
|
BuildingID buildingToEnter = building;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
const CBuilding *b = town->town->buildings.find(buildingToEnter)->second;
|
const CBuilding *b = town->getTown()->buildings.find(buildingToEnter)->second;
|
||||||
|
|
||||||
if (buildingTryActivateCustomUI(buildingToEnter, building))
|
if (buildingTryActivateCustomUI(buildingToEnter, building))
|
||||||
return;
|
return;
|
||||||
@ -705,7 +705,7 @@ void CCastleBuildings::buildingClicked(BuildingID building)
|
|||||||
bool CCastleBuildings::buildingTryActivateCustomUI(BuildingID buildingToTest, BuildingID buildingTarget)
|
bool CCastleBuildings::buildingTryActivateCustomUI(BuildingID buildingToTest, BuildingID buildingTarget)
|
||||||
{
|
{
|
||||||
logGlobal->trace("You've clicked on %d", (int)buildingToTest.toEnum());
|
logGlobal->trace("You've clicked on %d", (int)buildingToTest.toEnum());
|
||||||
const CBuilding *b = town->town->buildings.at(buildingToTest);
|
const CBuilding *b = town->getTown()->buildings.at(buildingToTest);
|
||||||
|
|
||||||
if (town->getWarMachineInBuilding(buildingToTest).hasValue())
|
if (town->getWarMachineInBuilding(buildingToTest).hasValue())
|
||||||
{
|
{
|
||||||
@ -744,7 +744,7 @@ bool CCastleBuildings::buildingTryActivateCustomUI(BuildingID buildingToTest, Bu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (town->rewardableBuildings.count(buildingToTest) && town->town->buildings.at(buildingToTest)->manualHeroVisit)
|
if (town->rewardableBuildings.count(buildingToTest) && town->getTown()->buildings.at(buildingToTest)->manualHeroVisit)
|
||||||
{
|
{
|
||||||
enterRewardable(buildingToTest);
|
enterRewardable(buildingToTest);
|
||||||
return true;
|
return true;
|
||||||
@ -820,10 +820,10 @@ bool CCastleBuildings::buildingTryActivateCustomUI(BuildingID buildingToTest, Bu
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
case BuildingSubID::PORTAL_OF_SUMMONING:
|
case BuildingSubID::PORTAL_OF_SUMMONING:
|
||||||
if (town->creatures[town->town->creatures.size()].second.empty())//No creatures
|
if (town->creatures[town->getTown()->creatures.size()].second.empty())//No creatures
|
||||||
LOCPLINT->showInfoDialog(CGI->generaltexth->tcommands[30]);
|
LOCPLINT->showInfoDialog(CGI->generaltexth->tcommands[30]);
|
||||||
else
|
else
|
||||||
enterDwelling(town->town->creatures.size());
|
enterDwelling(town->getTown()->creatures.size());
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case BuildingSubID::BANK:
|
case BuildingSubID::BANK:
|
||||||
@ -850,7 +850,7 @@ void CCastleBuildings::enterRewardable(BuildingID building)
|
|||||||
{
|
{
|
||||||
MetaString message;
|
MetaString message;
|
||||||
message.appendTextID("core.genrltxt.273"); // only visiting heroes may visit %s
|
message.appendTextID("core.genrltxt.273"); // only visiting heroes may visit %s
|
||||||
message.replaceTextID(town->town->buildings.at(building)->getNameTextID());
|
message.replaceTextID(town->getTown()->buildings.at(building)->getNameTextID());
|
||||||
|
|
||||||
LOCPLINT->showInfoDialog(message.toString());
|
LOCPLINT->showInfoDialog(message.toString());
|
||||||
}
|
}
|
||||||
@ -868,7 +868,7 @@ void CCastleBuildings::enterBlacksmith(BuildingID building, ArtifactID artifactI
|
|||||||
const CGHeroInstance *hero = town->visitingHero;
|
const CGHeroInstance *hero = town->visitingHero;
|
||||||
if(!hero)
|
if(!hero)
|
||||||
{
|
{
|
||||||
LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[273]) % town->town->buildings.find(building)->second->getNameTranslated()));
|
LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[273]) % town->getTown()->buildings.find(building)->second->getNameTranslated()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto art = artifactID.toArtifact();
|
auto art = artifactID.toArtifact();
|
||||||
@ -897,8 +897,8 @@ void CCastleBuildings::enterBlacksmith(BuildingID building, ArtifactID artifactI
|
|||||||
|
|
||||||
void CCastleBuildings::enterBuilding(BuildingID building)
|
void CCastleBuildings::enterBuilding(BuildingID building)
|
||||||
{
|
{
|
||||||
std::vector<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(ComponentType::BUILDING, BuildingTypeUniqueID(town->getFaction(), building)));
|
std::vector<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(ComponentType::BUILDING, BuildingTypeUniqueID(town->getFactionID(), building)));
|
||||||
LOCPLINT->showInfoDialog( town->town->buildings.find(building)->second->getDescriptionTranslated(), comps);
|
LOCPLINT->showInfoDialog( town->getTown()->buildings.find(building)->second->getDescriptionTranslated(), comps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCastleBuildings::enterCastleGate()
|
void CCastleBuildings::enterCastleGate()
|
||||||
@ -915,20 +915,20 @@ void CCastleBuildings::enterCastleGate()
|
|||||||
{
|
{
|
||||||
const CGTownInstance *t = Town;
|
const CGTownInstance *t = Town;
|
||||||
if (t->id != this->town->id && t->visitingHero == nullptr && //another town, empty and this is
|
if (t->id != this->town->id && t->visitingHero == nullptr && //another town, empty and this is
|
||||||
t->town->faction->getId() == town->town->faction->getId() && //the town of the same faction
|
t->getFactionID() == town->getFactionID() && //the town of the same faction
|
||||||
t->hasBuilt(BuildingSubID::CASTLE_GATE)) //and the town has a castle gate
|
t->hasBuilt(BuildingSubID::CASTLE_GATE)) //and the town has a castle gate
|
||||||
{
|
{
|
||||||
availableTowns.push_back(t->id.getNum());//add to the list
|
availableTowns.push_back(t->id.getNum());//add to the list
|
||||||
if(settings["general"]["enableUiEnhancements"].Bool())
|
if(settings["general"]["enableUiEnhancements"].Bool())
|
||||||
{
|
{
|
||||||
auto image = GH.renderHandler().loadImage(AnimationPath::builtin("ITPA"), t->town->clientInfo.icons[t->hasFort()][false] + 2, 0, EImageBlitMode::OPAQUE);
|
auto image = GH.renderHandler().loadImage(AnimationPath::builtin("ITPA"), t->getTown()->clientInfo.icons[t->hasFort()][false] + 2, 0, EImageBlitMode::OPAQUE);
|
||||||
image->scaleTo(Point(35, 23));
|
image->scaleTo(Point(35, 23));
|
||||||
images.push_back(image);
|
images.push_back(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto gateIcon = std::make_shared<CAnimImage>(town->town->clientInfo.buildingsIcons, BuildingID::CASTLE_GATE);//will be deleted by selection window
|
auto gateIcon = std::make_shared<CAnimImage>(town->getTown()->clientInfo.buildingsIcons, BuildingID::CASTLE_GATE);//will be deleted by selection window
|
||||||
auto wnd = std::make_shared<CObjectListWindow>(availableTowns, gateIcon, CGI->generaltexth->jktexts[40],
|
auto wnd = std::make_shared<CObjectListWindow>(availableTowns, gateIcon, CGI->generaltexth->jktexts[40],
|
||||||
CGI->generaltexth->jktexts[41], std::bind (&CCastleInterface::castleTeleport, LOCPLINT->castleInt, _1), 0, images);
|
CGI->generaltexth->jktexts[41], std::bind (&CCastleInterface::castleTeleport, LOCPLINT->castleInt, _1), 0, images);
|
||||||
wnd->onPopup = [availableTowns](int index) { CRClickPopup::createAndPush(LOCPLINT->cb->getObjInstance(ObjectInstanceID(availableTowns[index])), GH.getCursorPosition()); };
|
wnd->onPopup = [availableTowns](int index) { CRClickPopup::createAndPush(LOCPLINT->cb->getObjInstance(ObjectInstanceID(availableTowns[index])), GH.getCursorPosition()); };
|
||||||
@ -940,7 +940,7 @@ void CCastleBuildings::enterDwelling(int level)
|
|||||||
if (level < 0 || level >= town->creatures.size() || town->creatures[level].second.empty())
|
if (level < 0 || level >= town->creatures.size() || town->creatures[level].second.empty())
|
||||||
{
|
{
|
||||||
assert(0);
|
assert(0);
|
||||||
logGlobal->error("Attempt to enter into invalid dwelling of level %d in town %s (%s)", level, town->getNameTranslated(), town->town->faction->getNameTranslated());
|
logGlobal->error("Attempt to enter into invalid dwelling of level %d in town %s (%s)", level, town->getNameTranslated(), town->getFaction()->getNameTranslated());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -954,8 +954,8 @@ void CCastleBuildings::enterDwelling(int level)
|
|||||||
void CCastleBuildings::enterToTheQuickRecruitmentWindow()
|
void CCastleBuildings::enterToTheQuickRecruitmentWindow()
|
||||||
{
|
{
|
||||||
const auto beginIt = town->creatures.cbegin();
|
const auto beginIt = town->creatures.cbegin();
|
||||||
const auto afterLastIt = town->creatures.size() > town->town->creatures.size()
|
const auto afterLastIt = town->creatures.size() > town->getTown()->creatures.size()
|
||||||
? std::next(beginIt, town->town->creatures.size())
|
? std::next(beginIt, town->getTown()->creatures.size())
|
||||||
: town->creatures.cend();
|
: town->creatures.cend();
|
||||||
const auto hasSomeoneToRecruit = std::any_of(beginIt, afterLastIt,
|
const auto hasSomeoneToRecruit = std::any_of(beginIt, afterLastIt,
|
||||||
[](const auto & creatureInfo) { return creatureInfo.first > 0; });
|
[](const auto & creatureInfo) { return creatureInfo.first > 0; });
|
||||||
@ -967,8 +967,8 @@ void CCastleBuildings::enterToTheQuickRecruitmentWindow()
|
|||||||
|
|
||||||
void CCastleBuildings::enterFountain(const BuildingID & building, BuildingSubID::EBuildingSubID subID, BuildingID upgrades)
|
void CCastleBuildings::enterFountain(const BuildingID & building, BuildingSubID::EBuildingSubID subID, BuildingID upgrades)
|
||||||
{
|
{
|
||||||
std::vector<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(ComponentType::BUILDING, BuildingTypeUniqueID(town->getFaction(), building)));
|
std::vector<std::shared_ptr<CComponent>> comps(1, std::make_shared<CComponent>(ComponentType::BUILDING, BuildingTypeUniqueID(town->getFactionID(), building)));
|
||||||
std::string descr = town->town->buildings.find(building)->second->getDescriptionTranslated();
|
std::string descr = town->getTown()->buildings.find(building)->second->getDescriptionTranslated();
|
||||||
std::string hasNotProduced;
|
std::string hasNotProduced;
|
||||||
std::string hasProduced;
|
std::string hasProduced;
|
||||||
|
|
||||||
@ -977,10 +977,10 @@ void CCastleBuildings::enterFountain(const BuildingID & building, BuildingSubID:
|
|||||||
|
|
||||||
bool isMysticPondOrItsUpgrade = subID == BuildingSubID::MYSTIC_POND
|
bool isMysticPondOrItsUpgrade = subID == BuildingSubID::MYSTIC_POND
|
||||||
|| (upgrades != BuildingID::NONE
|
|| (upgrades != BuildingID::NONE
|
||||||
&& town->town->buildings.find(BuildingID(upgrades))->second->subId == BuildingSubID::MYSTIC_POND);
|
&& town->getTown()->buildings.find(BuildingID(upgrades))->second->subId == BuildingSubID::MYSTIC_POND);
|
||||||
|
|
||||||
if(upgrades != BuildingID::NONE)
|
if(upgrades != BuildingID::NONE)
|
||||||
descr += "\n\n"+town->town->buildings.find(BuildingID(upgrades))->second->getDescriptionTranslated();
|
descr += "\n\n"+town->getTown()->buildings.find(BuildingID(upgrades))->second->getDescriptionTranslated();
|
||||||
|
|
||||||
if(isMysticPondOrItsUpgrade) //for vanila Rampart like towns
|
if(isMysticPondOrItsUpgrade) //for vanila Rampart like towns
|
||||||
{
|
{
|
||||||
@ -1056,7 +1056,7 @@ void CCastleBuildings::enterTownHall()
|
|||||||
|
|
||||||
void CCastleBuildings::openMagesGuild()
|
void CCastleBuildings::openMagesGuild()
|
||||||
{
|
{
|
||||||
auto mageGuildBackground = LOCPLINT->castleInt->town->town->clientInfo.guildBackground;
|
auto mageGuildBackground = LOCPLINT->castleInt->town->getTown()->clientInfo.guildBackground;
|
||||||
GH.windows().createAndPushWindow<CMageGuildScreen>(LOCPLINT->castleInt, mageGuildBackground);
|
GH.windows().createAndPushWindow<CMageGuildScreen>(LOCPLINT->castleInt, mageGuildBackground);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1247,7 +1247,7 @@ CTownInfo::CTownInfo(int posX, int posY, const CGTownInstance * Town, bool townH
|
|||||||
return;//FIXME: suspicious statement, fix or comment
|
return;//FIXME: suspicious statement, fix or comment
|
||||||
picture = std::make_shared<CAnimImage>(AnimationPath::builtin("ITMCL.DEF"), town->fortLevel()-1);
|
picture = std::make_shared<CAnimImage>(AnimationPath::builtin("ITMCL.DEF"), town->fortLevel()-1);
|
||||||
}
|
}
|
||||||
building = town->town->buildings.at(BuildingID(buildID));
|
building = town->getTown()->buildings.at(BuildingID(buildID));
|
||||||
pos = picture->pos;
|
pos = picture->pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1322,7 +1322,7 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
|
|||||||
recreateIcons();
|
recreateIcons();
|
||||||
if (!from)
|
if (!from)
|
||||||
adventureInt->onAudioPaused();
|
adventureInt->onAudioPaused();
|
||||||
CCS->musich->playMusicFromSet("faction", town->town->faction->getJsonKey(), true, false);
|
CCS->musich->playMusicFromSet("faction", town->getFaction()->getJsonKey(), true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
CCastleInterface::~CCastleInterface()
|
CCastleInterface::~CCastleInterface()
|
||||||
@ -1403,7 +1403,7 @@ void CCastleInterface::removeBuilding(BuildingID bid)
|
|||||||
void CCastleInterface::recreateIcons()
|
void CCastleInterface::recreateIcons()
|
||||||
{
|
{
|
||||||
OBJECT_CONSTRUCTION;
|
OBJECT_CONSTRUCTION;
|
||||||
size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->built >= LOCPLINT->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
|
size_t iconIndex = town->getTown()->clientInfo.icons[town->hasFort()][town->built >= LOCPLINT->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
|
||||||
|
|
||||||
icon->setFrame(iconIndex);
|
icon->setFrame(iconIndex);
|
||||||
TResources townIncome = town->dailyIncome();
|
TResources townIncome = town->dailyIncome();
|
||||||
@ -1425,8 +1425,8 @@ void CCastleInterface::recreateIcons()
|
|||||||
if(town->hasBuilt(BuildingID::TAVERN))
|
if(town->hasBuilt(BuildingID::TAVERN))
|
||||||
LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
|
LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
|
||||||
}, [this]{
|
}, [this]{
|
||||||
if(!town->town->faction->getDescriptionTranslated().empty())
|
if(!town->getFaction()->getDescriptionTranslated().empty())
|
||||||
CRClickPopup::createAndPush(town->town->faction->getDescriptionTranslated());
|
CRClickPopup::createAndPush(town->getFaction()->getDescriptionTranslated());
|
||||||
});
|
});
|
||||||
|
|
||||||
creainfo.clear();
|
creainfo.clear();
|
||||||
@ -1527,7 +1527,7 @@ CHallInterface::CBuildingBox::CBuildingBox(int x, int y, const CGTownInstance *
|
|||||||
-1, -1, -1, 0, 0, 1, 2, -1, 1, 1, -1, -1
|
-1, -1, -1, 0, 0, 1, 2, -1, 1, 1, -1, -1
|
||||||
};
|
};
|
||||||
|
|
||||||
icon = std::make_shared<CAnimImage>(town->town->clientInfo.buildingsIcons, building->bid, 0, 2, 2);
|
icon = std::make_shared<CAnimImage>(town->getTown()->clientInfo.buildingsIcons, building->bid, 0, 2, 2);
|
||||||
header = std::make_shared<CAnimImage>(AnimationPath::builtin("TPTHBAR"), panelIndex[static_cast<int>(state)], 0, 1, 73);
|
header = std::make_shared<CAnimImage>(AnimationPath::builtin("TPTHBAR"), panelIndex[static_cast<int>(state)], 0, 1, 73);
|
||||||
if(iconIndex[static_cast<int>(state)] >=0)
|
if(iconIndex[static_cast<int>(state)] >=0)
|
||||||
mark = std::make_shared<CAnimImage>(AnimationPath::builtin("TPTHCHK"), iconIndex[static_cast<int>(state)], 0, 136, 56);
|
mark = std::make_shared<CAnimImage>(AnimationPath::builtin("TPTHCHK"), iconIndex[static_cast<int>(state)], 0, 136, 56);
|
||||||
@ -1569,7 +1569,7 @@ void CHallInterface::CBuildingBox::showPopupWindow(const Point & cursorPosition)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CHallInterface::CHallInterface(const CGTownInstance * Town):
|
CHallInterface::CHallInterface(const CGTownInstance * Town):
|
||||||
CWindowObject(PLAYER_COLORED | BORDERED, Town->town->clientInfo.hallBackground),
|
CWindowObject(PLAYER_COLORED | BORDERED, Town->getTown()->clientInfo.hallBackground),
|
||||||
town(Town)
|
town(Town)
|
||||||
{
|
{
|
||||||
OBJECT_CONSTRUCTION;
|
OBJECT_CONSTRUCTION;
|
||||||
@ -1581,10 +1581,10 @@ CHallInterface::CHallInterface(const CGTownInstance * Town):
|
|||||||
auto statusbarBackground = std::make_shared<CPicture>(background->getSurface(), barRect, 5, 556);
|
auto statusbarBackground = std::make_shared<CPicture>(background->getSurface(), barRect, 5, 556);
|
||||||
statusbar = CGStatusBar::create(statusbarBackground);
|
statusbar = CGStatusBar::create(statusbarBackground);
|
||||||
|
|
||||||
title = std::make_shared<CLabel>(399, 12, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, town->town->buildings.at(BuildingID(town->hallLevel()+BuildingID::VILLAGE_HALL))->getNameTranslated());
|
title = std::make_shared<CLabel>(399, 12, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, town->getTown()->buildings.at(BuildingID(town->hallLevel()+BuildingID::VILLAGE_HALL))->getNameTranslated());
|
||||||
exit = std::make_shared<CButton>(Point(748, 556), AnimationPath::builtin("TPMAGE1.DEF"), CButton::tooltip(CGI->generaltexth->hcommands[8]), [&](){close();}, EShortcut::GLOBAL_RETURN);
|
exit = std::make_shared<CButton>(Point(748, 556), AnimationPath::builtin("TPMAGE1.DEF"), CButton::tooltip(CGI->generaltexth->hcommands[8]), [&](){close();}, EShortcut::GLOBAL_RETURN);
|
||||||
|
|
||||||
auto & boxList = town->town->clientInfo.hallSlots;
|
auto & boxList = town->getTown()->clientInfo.hallSlots;
|
||||||
boxes.resize(boxList.size());
|
boxes.resize(boxList.size());
|
||||||
for(size_t row=0; row<boxList.size(); row++) //for each row
|
for(size_t row=0; row<boxList.size(); row++) //for each row
|
||||||
{
|
{
|
||||||
@ -1595,11 +1595,11 @@ CHallInterface::CHallInterface(const CGTownInstance * Town):
|
|||||||
{
|
{
|
||||||
if (!buildingID.hasValue())
|
if (!buildingID.hasValue())
|
||||||
{
|
{
|
||||||
logMod->warn("Invalid building ID found in hallSlots of town '%s'", town->town->faction->getJsonKey() );
|
logMod->warn("Invalid building ID found in hallSlots of town '%s'", town->getFaction()->getJsonKey() );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CBuilding * current = town->town->buildings.at(buildingID);
|
const CBuilding * current = town->getTown()->buildings.at(buildingID);
|
||||||
if(town->hasBuilt(buildingID))
|
if(town->hasBuilt(buildingID))
|
||||||
{
|
{
|
||||||
building = current;
|
building = current;
|
||||||
@ -1629,7 +1629,7 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
|
|||||||
{
|
{
|
||||||
OBJECT_CONSTRUCTION;
|
OBJECT_CONSTRUCTION;
|
||||||
|
|
||||||
icon = std::make_shared<CAnimImage>(town->town->clientInfo.buildingsIcons, building->bid, 0, 125, 50);
|
icon = std::make_shared<CAnimImage>(town->getTown()->clientInfo.buildingsIcons, building->bid, 0, 125, 50);
|
||||||
auto statusbarBackground = std::make_shared<CPicture>(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26);
|
auto statusbarBackground = std::make_shared<CPicture>(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26);
|
||||||
statusbar = CGStatusBar::create(statusbarBackground);
|
statusbar = CGStatusBar::create(statusbarBackground);
|
||||||
|
|
||||||
@ -1711,7 +1711,7 @@ std::string CBuildWindow::getTextForState(EBuildingState state)
|
|||||||
{
|
{
|
||||||
auto toStr = [&](const BuildingID build) -> std::string
|
auto toStr = [&](const BuildingID build) -> std::string
|
||||||
{
|
{
|
||||||
return town->town->buildings.at(build)->getNameTranslated();
|
return town->getTown()->buildings.at(build)->getNameTranslated();
|
||||||
};
|
};
|
||||||
|
|
||||||
ret = CGI->generaltexth->allTexts[52];
|
ret = CGI->generaltexth->allTexts[52];
|
||||||
@ -1721,7 +1721,7 @@ std::string CBuildWindow::getTextForState(EBuildingState state)
|
|||||||
case EBuildingState::MISSING_BASE:
|
case EBuildingState::MISSING_BASE:
|
||||||
{
|
{
|
||||||
std::string msg = CGI->generaltexth->translate("vcmi.townHall.missingBase");
|
std::string msg = CGI->generaltexth->translate("vcmi.townHall.missingBase");
|
||||||
ret = boost::str(boost::format(msg) % town->town->buildings.at(building->upgrade)->getNameTranslated());
|
ret = boost::str(boost::format(msg) % town->getTown()->buildings.at(building->upgrade)->getNameTranslated());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1780,11 +1780,11 @@ CFortScreen::CFortScreen(const CGTownInstance * town):
|
|||||||
{
|
{
|
||||||
OBJECT_CONSTRUCTION;
|
OBJECT_CONSTRUCTION;
|
||||||
ui32 fortSize = static_cast<ui32>(town->creatures.size());
|
ui32 fortSize = static_cast<ui32>(town->creatures.size());
|
||||||
if(fortSize > town->town->creatures.size() && town->creatures.back().second.empty())
|
if(fortSize > town->getTown()->creatures.size() && town->creatures.back().second.empty())
|
||||||
fortSize--;
|
fortSize--;
|
||||||
fortSize = std::min(fortSize, static_cast<ui32>(GameConstants::CREATURES_PER_TOWN)); // for 8 creatures + portal of summoning
|
fortSize = std::min(fortSize, static_cast<ui32>(GameConstants::CREATURES_PER_TOWN)); // for 8 creatures + portal of summoning
|
||||||
|
|
||||||
const CBuilding * fortBuilding = town->town->buildings.at(BuildingID(town->fortLevel()+6));
|
const CBuilding * fortBuilding = town->getTown()->buildings.at(BuildingID(town->fortLevel()+6));
|
||||||
title = std::make_shared<CLabel>(400, 12, FONT_BIG, ETextAlignment::CENTER, Colors::WHITE, fortBuilding->getNameTranslated());
|
title = std::make_shared<CLabel>(400, 12, FONT_BIG, ETextAlignment::CENTER, Colors::WHITE, fortBuilding->getNameTranslated());
|
||||||
|
|
||||||
std::string text = boost::str(boost::format(CGI->generaltexth->fcommands[6]) % fortBuilding->getNameTranslated());
|
std::string text = boost::str(boost::format(CGI->generaltexth->fcommands[6]) % fortBuilding->getNameTranslated());
|
||||||
@ -1810,7 +1810,7 @@ CFortScreen::CFortScreen(const CGTownInstance * town):
|
|||||||
for(ui32 i=0; i<fortSize; i++)
|
for(ui32 i=0; i<fortSize; i++)
|
||||||
{
|
{
|
||||||
BuildingID buildingID;
|
BuildingID buildingID;
|
||||||
if(fortSize == town->town->creatures.size())
|
if(fortSize == town->getTown()->creatures.size())
|
||||||
{
|
{
|
||||||
BuildingID dwelling = BuildingID::getDwellingFromLevel(i, 1);
|
BuildingID dwelling = BuildingID::getDwellingFromLevel(i, 1);
|
||||||
|
|
||||||
@ -1839,7 +1839,7 @@ CFortScreen::CFortScreen(const CGTownInstance * town):
|
|||||||
ImagePath CFortScreen::getBgName(const CGTownInstance * town)
|
ImagePath CFortScreen::getBgName(const CGTownInstance * town)
|
||||||
{
|
{
|
||||||
ui32 fortSize = static_cast<ui32>(town->creatures.size());
|
ui32 fortSize = static_cast<ui32>(town->creatures.size());
|
||||||
if(fortSize > town->town->creatures.size() && town->creatures.back().second.empty())
|
if(fortSize > town->getTown()->creatures.size() && town->creatures.back().second.empty())
|
||||||
fortSize--;
|
fortSize--;
|
||||||
fortSize = std::min(fortSize, static_cast<ui32>(GameConstants::CREATURES_PER_TOWN)); // for 8 creatures + portal of summoning
|
fortSize = std::min(fortSize, static_cast<ui32>(GameConstants::CREATURES_PER_TOWN)); // for 8 creatures + portal of summoning
|
||||||
|
|
||||||
@ -1877,7 +1877,7 @@ CFortScreen::RecruitArea::RecruitArea(int posX, int posY, const CGTownInstance *
|
|||||||
|
|
||||||
if(getMyBuilding() != nullptr)
|
if(getMyBuilding() != nullptr)
|
||||||
{
|
{
|
||||||
buildingIcon = std::make_shared<CAnimImage>(town->town->clientInfo.buildingsIcons, getMyBuilding()->bid, 0, 4, 21);
|
buildingIcon = std::make_shared<CAnimImage>(town->getTown()->clientInfo.buildingsIcons, getMyBuilding()->bid, 0, 4, 21);
|
||||||
buildingName = std::make_shared<CLabel>(78, 101, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, getMyBuilding()->getNameTranslated(), 152);
|
buildingName = std::make_shared<CLabel>(78, 101, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, getMyBuilding()->getNameTranslated(), 152);
|
||||||
|
|
||||||
if(town->hasBuilt(getMyBuilding()->bid))
|
if(town->hasBuilt(getMyBuilding()->bid))
|
||||||
@ -1913,8 +1913,8 @@ const CCreature * CFortScreen::RecruitArea::getMyCreature()
|
|||||||
{
|
{
|
||||||
if(!town->creatures.at(level).second.empty()) // built
|
if(!town->creatures.at(level).second.empty()) // built
|
||||||
return town->creatures.at(level).second.back().toCreature();
|
return town->creatures.at(level).second.back().toCreature();
|
||||||
if(!town->town->creatures.at(level).empty()) // there are creatures on this level
|
if(!town->getTown()->creatures.at(level).empty()) // there are creatures on this level
|
||||||
return town->town->creatures.at(level).front().toCreature();
|
return town->getTown()->creatures.at(level).front().toCreature();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1922,17 +1922,17 @@ const CBuilding * CFortScreen::RecruitArea::getMyBuilding()
|
|||||||
{
|
{
|
||||||
BuildingID myID = BuildingID(BuildingID::getDwellingFromLevel(level, 0));
|
BuildingID myID = BuildingID(BuildingID::getDwellingFromLevel(level, 0));
|
||||||
|
|
||||||
if (level == town->town->creatures.size())
|
if (level == town->getTown()->creatures.size())
|
||||||
return town->town->getSpecialBuilding(BuildingSubID::PORTAL_OF_SUMMONING);
|
return town->getTown()->getSpecialBuilding(BuildingSubID::PORTAL_OF_SUMMONING);
|
||||||
|
|
||||||
if (!town->town->buildings.count(myID))
|
if (!town->getTown()->buildings.count(myID))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
const CBuilding * build = town->town->buildings.at(myID);
|
const CBuilding * build = town->getTown()->buildings.at(myID);
|
||||||
while (town->town->buildings.count(myID))
|
while (town->getTown()->buildings.count(myID))
|
||||||
{
|
{
|
||||||
if (town->hasBuilt(myID))
|
if (town->hasBuilt(myID))
|
||||||
build = town->town->buildings.at(myID);
|
build = town->getTown()->buildings.at(myID);
|
||||||
BuildingID::advanceDwelling(myID);
|
BuildingID::advanceDwelling(myID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1972,7 +1972,7 @@ CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner, const ImagePath & i
|
|||||||
{
|
{
|
||||||
OBJECT_CONSTRUCTION;
|
OBJECT_CONSTRUCTION;
|
||||||
|
|
||||||
window = std::make_shared<CPicture>(owner->town->town->clientInfo.guildWindow, 332, 76);
|
window = std::make_shared<CPicture>(owner->town->getTown()->clientInfo.guildWindow, 332, 76);
|
||||||
|
|
||||||
resdatabar = std::make_shared<CMinorResDataBar>();
|
resdatabar = std::make_shared<CMinorResDataBar>();
|
||||||
resdatabar->moveBy(pos.topLeft(), true);
|
resdatabar->moveBy(pos.topLeft(), true);
|
||||||
@ -2007,7 +2007,7 @@ void CMageGuildScreen::updateSpells(ObjectInstanceID tID)
|
|||||||
|
|
||||||
const CGTownInstance * town = LOCPLINT->cb->getTown(townId);
|
const CGTownInstance * town = LOCPLINT->cb->getTown(townId);
|
||||||
|
|
||||||
for(size_t i=0; i<town->town->mageLevel; i++)
|
for(size_t i=0; i<town->getTown()->mageLevel; i++)
|
||||||
{
|
{
|
||||||
size_t spellCount = town->spellsAtLevel((int)i+1,false); //spell at level with -1 hmmm?
|
size_t spellCount = town->spellsAtLevel((int)i+1,false); //spell at level with -1 hmmm?
|
||||||
for(size_t j=0; j<spellCount; j++)
|
for(size_t j=0; j<spellCount; j++)
|
||||||
|
@ -84,7 +84,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
|
|||||||
for(int m=0; m < hero->secSkills.size(); ++m)
|
for(int m=0; m < hero->secSkills.size(); ++m)
|
||||||
secSkillIcons[leftRight].push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SECSK32"), 0, 0, 32 + 36 * m + 454 * leftRight, qeLayout ? 83 : 88));
|
secSkillIcons[leftRight].push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SECSK32"), 0, 0, 32 + 36 * m + 454 * leftRight, qeLayout ? 83 : 88));
|
||||||
|
|
||||||
specImages[leftRight] = std::make_shared<CAnimImage>(AnimationPath::builtin("UN32"), hero->type->imageIndex, 0, 67 + 490 * leftRight, qeLayout ? 41 : 45);
|
specImages[leftRight] = std::make_shared<CAnimImage>(AnimationPath::builtin("UN32"), hero->getHeroType()->imageIndex, 0, 67 + 490 * leftRight, qeLayout ? 41 : 45);
|
||||||
|
|
||||||
expImages[leftRight] = std::make_shared<CAnimImage>(AnimationPath::builtin("PSKIL32"), 4, 0, 103 + 490 * leftRight, qeLayout ? 41 : 45);
|
expImages[leftRight] = std::make_shared<CAnimImage>(AnimationPath::builtin("PSKIL32"), 4, 0, 103 + 490 * leftRight, qeLayout ? 41 : 45);
|
||||||
expValues[leftRight] = std::make_shared<CLabel>(119 + 490 * leftRight, qeLayout ? 66 : 71, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
|
expValues[leftRight] = std::make_shared<CLabel>(119 + 490 * leftRight, qeLayout ? 66 : 71, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
|
||||||
@ -151,7 +151,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
|
|||||||
specialtyAreas[b] = std::make_shared<LRClickableAreaWText>();
|
specialtyAreas[b] = std::make_shared<LRClickableAreaWText>();
|
||||||
specialtyAreas[b]->pos = Rect(Point(pos.x + 69 + 490 * b, pos.y + (qeLayout ? 41 : 45)), Point(32, 32));
|
specialtyAreas[b]->pos = Rect(Point(pos.x + 69 + 490 * b, pos.y + (qeLayout ? 41 : 45)), Point(32, 32));
|
||||||
specialtyAreas[b]->hoverText = CGI->generaltexth->heroscrn[27];
|
specialtyAreas[b]->hoverText = CGI->generaltexth->heroscrn[27];
|
||||||
specialtyAreas[b]->text = hero->type->getSpecialtyDescriptionTranslated();
|
specialtyAreas[b]->text = hero->getHeroType()->getSpecialtyDescriptionTranslated();
|
||||||
|
|
||||||
experienceAreas[b] = std::make_shared<LRClickableAreaWText>();
|
experienceAreas[b] = std::make_shared<LRClickableAreaWText>();
|
||||||
experienceAreas[b]->pos = Rect(Point(pos.x + 105 + 490 * b, pos.y + (qeLayout ? 41 : 45)), Point(32, 32));
|
experienceAreas[b]->pos = Rect(Point(pos.x + 105 + 490 * b, pos.y + (qeLayout ? 41 : 45)), Point(32, 32));
|
||||||
|
@ -184,9 +184,9 @@ void CHeroWindow::update()
|
|||||||
name->setText(curHero->getNameTranslated());
|
name->setText(curHero->getNameTranslated());
|
||||||
title->setText((boost::format(CGI->generaltexth->allTexts[342]) % curHero->level % curHero->getClassNameTranslated()).str());
|
title->setText((boost::format(CGI->generaltexth->allTexts[342]) % curHero->level % curHero->getClassNameTranslated()).str());
|
||||||
|
|
||||||
specArea->text = curHero->type->getSpecialtyDescriptionTranslated();
|
specArea->text = curHero->getHeroType()->getSpecialtyDescriptionTranslated();
|
||||||
specImage->setFrame(curHero->type->imageIndex);
|
specImage->setFrame(curHero->getHeroType()->imageIndex);
|
||||||
specName->setText(curHero->type->getSpecialtyNameTranslated());
|
specName->setText(curHero->getHeroType()->getSpecialtyNameTranslated());
|
||||||
|
|
||||||
tacticsButton = std::make_shared<CToggleButton>(Point(539, 483), AnimationPath::builtin("hsbtns8.def"), std::make_pair(heroscrn[26], heroscrn[31]), 0, EShortcut::HERO_TOGGLE_TACTICS);
|
tacticsButton = std::make_shared<CToggleButton>(Point(539, 483), AnimationPath::builtin("hsbtns8.def"), std::make_pair(heroscrn[26], heroscrn[31]), 0, EShortcut::HERO_TOGGLE_TACTICS);
|
||||||
tacticsButton->addHoverText(EButtonState::HIGHLIGHTED, CGI->generaltexth->heroscrn[25]);
|
tacticsButton->addHoverText(EButtonState::HIGHLIGHTED, CGI->generaltexth->heroscrn[25]);
|
||||||
|
@ -300,7 +300,7 @@ int InfoBoxHeroData::getSubID()
|
|||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
case HERO_SPECIAL:
|
case HERO_SPECIAL:
|
||||||
return hero->type->getIndex();
|
return hero->getHeroTypeID().getNum();
|
||||||
case HERO_MANA:
|
case HERO_MANA:
|
||||||
case HERO_EXPERIENCE:
|
case HERO_EXPERIENCE:
|
||||||
return 0;
|
return 0;
|
||||||
@ -800,7 +800,7 @@ CTownItem::CTownItem(const CGTownInstance * Town)
|
|||||||
garr = std::make_shared<CGarrisonInt>(Point(313, 3), 4, Point(232,0), town->getUpperArmy(), town->visitingHero, true, true, CGarrisonInt::ESlotsLayout::TWO_ROWS);
|
garr = std::make_shared<CGarrisonInt>(Point(313, 3), 4, Point(232,0), town->getUpperArmy(), town->visitingHero, true, true, CGarrisonInt::ESlotsLayout::TWO_ROWS);
|
||||||
heroes = std::make_shared<HeroSlots>(town, Point(244,6), Point(475,6), garr, false);
|
heroes = std::make_shared<HeroSlots>(town, Point(244,6), Point(475,6), garr, false);
|
||||||
|
|
||||||
size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->built >= LOCPLINT->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
|
size_t iconIndex = town->getTown()->clientInfo.icons[town->hasFort()][town->built >= LOCPLINT->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
|
||||||
|
|
||||||
picture = std::make_shared<CAnimImage>(AnimationPath::builtin("ITPT"), iconIndex, 0, 5, 6);
|
picture = std::make_shared<CAnimImage>(AnimationPath::builtin("ITPT"), iconIndex, 0, 5, 6);
|
||||||
openTown = std::make_shared<LRClickableAreaOpenTown>(Rect(5, 6, 58, 64), town);
|
openTown = std::make_shared<LRClickableAreaOpenTown>(Rect(5, 6, 58, 64), town);
|
||||||
@ -823,8 +823,8 @@ CTownItem::CTownItem(const CGTownInstance * Town)
|
|||||||
if(town->hasBuilt(BuildingID::TAVERN))
|
if(town->hasBuilt(BuildingID::TAVERN))
|
||||||
LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
|
LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
|
||||||
}, [&]{
|
}, [&]{
|
||||||
if(!town->town->faction->getDescriptionTranslated().empty())
|
if(!town->getTown()->faction->getDescriptionTranslated().empty())
|
||||||
CRClickPopup::createAndPush(town->town->faction->getDescriptionTranslated());
|
CRClickPopup::createAndPush(town->getFaction()->getDescriptionTranslated());
|
||||||
});
|
});
|
||||||
fastMarket = std::make_shared<LRClickableArea>(Rect(153, 6, 65, 64), []()
|
fastMarket = std::make_shared<LRClickableArea>(Rect(153, 6, 65, 64), []()
|
||||||
{
|
{
|
||||||
|
@ -192,7 +192,7 @@ std::string CMarketWindow::getMarketTitle(const ObjectInstanceID marketId, const
|
|||||||
{
|
{
|
||||||
for(const auto & buildingId : town->getBuildings())
|
for(const auto & buildingId : town->getBuildings())
|
||||||
{
|
{
|
||||||
if(const auto building = town->town->buildings.at(buildingId); vstd::contains(building->marketModes, mode))
|
if(const auto building = town->getTown()->buildings.at(buildingId); vstd::contains(building->marketModes, mode))
|
||||||
return building->getNameTranslated();
|
return building->getNameTranslated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ void CQuestMinimap::addQuestMarks (const QuestInfo * q)
|
|||||||
|
|
||||||
int3 tile;
|
int3 tile;
|
||||||
if (q->obj)
|
if (q->obj)
|
||||||
tile = q->obj->pos;
|
tile = q->obj->visitablePos();
|
||||||
else
|
else
|
||||||
tile = q->tile;
|
tile = q->tile;
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ void CQuestMinimap::update()
|
|||||||
void CQuestMinimap::iconClicked()
|
void CQuestMinimap::iconClicked()
|
||||||
{
|
{
|
||||||
if(currentQuest->obj)
|
if(currentQuest->obj)
|
||||||
adventureInt->centerOnTile(currentQuest->obj->pos);
|
adventureInt->centerOnTile(currentQuest->obj->visitablePos());
|
||||||
//moveAdvMapSelection();
|
//moveAdvMapSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,9 +205,9 @@ CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _m
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedTab = battleSpellsOnly ? myInt->localState->spellbookSettings.spellbookLastTabBattle : myInt->localState->spellbookSettings.spellbookLastTabAdvmap;
|
selectedTab = battleSpellsOnly ? myInt->localState->getSpellbookSettings().spellbookLastTabBattle : myInt->localState->getSpellbookSettings().spellbookLastTabAdvmap;
|
||||||
schoolTab->setFrame(selectedTab, 0);
|
schoolTab->setFrame(selectedTab, 0);
|
||||||
int cp = battleSpellsOnly ? myInt->localState->spellbookSettings.spellbookLastPageBattle : myInt->localState->spellbookSettings.spellbookLastPageAdvmap;
|
int cp = battleSpellsOnly ? myInt->localState->getSpellbookSettings().spellbookLastPageBattle : myInt->localState->getSpellbookSettings().spellbookLastPageAdvmap;
|
||||||
// spellbook last page battle index is not reset after battle, so this needs to stay here
|
// spellbook last page battle index is not reset after battle, so this needs to stay here
|
||||||
vstd::abetween(cp, 0, std::max(0, pagesWithinCurrentTab() - 1));
|
vstd::abetween(cp, 0, std::max(0, pagesWithinCurrentTab() - 1));
|
||||||
setCurrentPage(cp);
|
setCurrentPage(cp);
|
||||||
@ -313,8 +313,18 @@ void CSpellWindow::processSpells()
|
|||||||
|
|
||||||
void CSpellWindow::fexitb()
|
void CSpellWindow::fexitb()
|
||||||
{
|
{
|
||||||
(myInt->battleInt ? myInt->localState->spellbookSettings.spellbookLastTabBattle : myInt->localState->spellbookSettings.spellbookLastTabAdvmap) = selectedTab;
|
auto spellBookState = myInt->localState->getSpellbookSettings();
|
||||||
(myInt->battleInt ? myInt->localState->spellbookSettings.spellbookLastPageBattle : myInt->localState->spellbookSettings.spellbookLastPageAdvmap) = currentPage;
|
if(myInt->battleInt)
|
||||||
|
{
|
||||||
|
spellBookState.spellbookLastTabBattle = selectedTab;
|
||||||
|
spellBookState.spellbookLastPageBattle = currentPage;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
spellBookState.spellbookLastTabAdvmap = selectedTab;
|
||||||
|
spellBookState.spellbookLastPageAdvmap = currentPage;
|
||||||
|
}
|
||||||
|
myInt->localState->setSpellbookSettings(spellBookState);
|
||||||
|
|
||||||
if(onSpellSelect)
|
if(onSpellSelect)
|
||||||
onSpellSelect(SpellID::NONE);
|
onSpellSelect(SpellID::NONE);
|
||||||
@ -619,8 +629,10 @@ void CSpellWindow::SpellArea::clickPressed(const Point & cursorPosition)
|
|||||||
|
|
||||||
auto guard = vstd::makeScopeGuard([this]()
|
auto guard = vstd::makeScopeGuard([this]()
|
||||||
{
|
{
|
||||||
owner->myInt->localState->spellbookSettings.spellbookLastTabAdvmap = owner->selectedTab;
|
auto spellBookState = owner->myInt->localState->getSpellbookSettings();
|
||||||
owner->myInt->localState->spellbookSettings.spellbookLastPageAdvmap = owner->currentPage;
|
spellBookState.spellbookLastTabAdvmap = owner->selectedTab;
|
||||||
|
spellBookState.spellbookLastPageAdvmap = owner->currentPage;
|
||||||
|
owner->myInt->localState->setSpellbookSettings(spellBookState);
|
||||||
});
|
});
|
||||||
|
|
||||||
spells::detail::ProblemImpl problem;
|
spells::detail::ProblemImpl problem;
|
||||||
|
@ -522,9 +522,9 @@ CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj, const std::func
|
|||||||
recruit->block(true);
|
recruit->block(true);
|
||||||
}
|
}
|
||||||
if(LOCPLINT->castleInt)
|
if(LOCPLINT->castleInt)
|
||||||
videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), LOCPLINT->castleInt->town->town->clientInfo.tavernVideo, false);
|
videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), LOCPLINT->castleInt->town->getTown()->clientInfo.tavernVideo, false);
|
||||||
else if(const auto * townObj = dynamic_cast<const CGTownInstance *>(TavernObj))
|
else if(const auto * townObj = dynamic_cast<const CGTownInstance *>(TavernObj))
|
||||||
videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), townObj->town->clientInfo.tavernVideo, false);
|
videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), townObj->getTown()->clientInfo.tavernVideo, false);
|
||||||
else
|
else
|
||||||
videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), VideoPath::builtin("TAVERN.BIK"), false);
|
videoPlayer = std::make_shared<VideoWidget>(Point(70, 56), VideoPath::builtin("TAVERN.BIK"), false);
|
||||||
|
|
||||||
@ -548,7 +548,7 @@ void CTavernWindow::addInvite()
|
|||||||
|
|
||||||
if(!inviteableHeroes.empty())
|
if(!inviteableHeroes.empty())
|
||||||
{
|
{
|
||||||
int imageIndex = heroToInvite ? (*CGI->heroh)[heroToInvite->getHeroType()]->imageIndex : 156; // 156 => special id for random
|
int imageIndex = heroToInvite ? heroToInvite->getIconIndex() : 156; // 156 => special id for random
|
||||||
if(!heroToInvite)
|
if(!heroToInvite)
|
||||||
heroToInvite = (*RandomGeneratorUtil::nextItem(inviteableHeroes, CRandomGenerator::getDefault())).second;
|
heroToInvite = (*RandomGeneratorUtil::nextItem(inviteableHeroes, CRandomGenerator::getDefault())).second;
|
||||||
|
|
||||||
@ -563,7 +563,7 @@ void CTavernWindow::recruitb()
|
|||||||
const CGHeroInstance *toBuy = (selected ? h2 : h1)->h;
|
const CGHeroInstance *toBuy = (selected ? h2 : h1)->h;
|
||||||
const CGObjectInstance *obj = tavernObj;
|
const CGObjectInstance *obj = tavernObj;
|
||||||
|
|
||||||
LOCPLINT->cb->recruitHero(obj, toBuy, heroToInvite ? heroToInvite->getHeroType() : HeroTypeID::NONE);
|
LOCPLINT->cb->recruitHero(obj, toBuy, heroToInvite ? heroToInvite->getHeroTypeID() : HeroTypeID::NONE);
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -963,7 +963,7 @@ CUniversityWindow::CUniversityWindow(const CGHeroInstance * _hero, BuildingID bu
|
|||||||
|
|
||||||
if(auto town = dynamic_cast<const CGTownInstance *>(_market))
|
if(auto town = dynamic_cast<const CGTownInstance *>(_market))
|
||||||
{
|
{
|
||||||
auto faction = town->town->faction->getId();
|
auto faction = town->getTown()->faction->getId();
|
||||||
titlePic = std::make_shared<CAnimImage>((*CGI->townh)[faction]->town->clientInfo.buildingsIcons, building);
|
titlePic = std::make_shared<CAnimImage>((*CGI->townh)[faction]->town->clientInfo.buildingsIcons, building);
|
||||||
}
|
}
|
||||||
else if(auto uni = dynamic_cast<const CGUniversity *>(_market); uni->appearance)
|
else if(auto uni = dynamic_cast<const CGUniversity *>(_market); uni->appearance)
|
||||||
|
@ -51,9 +51,9 @@ 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);
|
||||||
for (int i = 0; i < town->town->creatures.size(); i++)
|
for (int i = 0; i < town->getTown()->creatures.size(); i++)
|
||||||
{
|
{
|
||||||
if(!town->town->creatures.at(i).empty() && !town->creatures.at(i).second.empty() && town->creatures[i].first)
|
if(!town->getTown()->creatures.at(i).empty() && !town->creatures.at(i).second.empty() && town->creatures[i].first)
|
||||||
{
|
{
|
||||||
cards.push_back(std::make_shared<CreaturePurchaseCard>(town->creatures[i].second, position, town->creatures[i].first, this));
|
cards.push_back(std::make_shared<CreaturePurchaseCard>(town->creatures[i].second, position, town->creatures[i].first, this));
|
||||||
position.x += 108;
|
position.x += 108;
|
||||||
@ -108,7 +108,7 @@ void QuickRecruitmentWindow::purchaseUnits()
|
|||||||
{
|
{
|
||||||
int level = 0;
|
int level = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for(auto c : town->town->creatures)
|
for(auto c : town->getTown()->creatures)
|
||||||
{
|
{
|
||||||
for(auto c2 : c)
|
for(auto c2 : c)
|
||||||
if(c2 == selected->creatureOnTheCard->getId())
|
if(c2 == selected->creatureOnTheCard->getId())
|
||||||
@ -129,8 +129,8 @@ void QuickRecruitmentWindow::purchaseUnits()
|
|||||||
int QuickRecruitmentWindow::getAvailableCreatures()
|
int QuickRecruitmentWindow::getAvailableCreatures()
|
||||||
{
|
{
|
||||||
int creaturesAmount = 0;
|
int creaturesAmount = 0;
|
||||||
for (int i=0; i< town->town->creatures.size(); i++)
|
for (int i=0; i< town->getTown()->creatures.size(); i++)
|
||||||
if(!town->town->creatures.at(i).empty() && !town->creatures.at(i).second.empty() && town->creatures[i].first)
|
if(!town->getTown()->creatures.at(i).empty() && !town->creatures.at(i).second.empty() && town->creatures[i].first)
|
||||||
creaturesAmount++;
|
creaturesAmount++;
|
||||||
return creaturesAmount;
|
return creaturesAmount;
|
||||||
}
|
}
|
||||||
|
@ -194,10 +194,8 @@ GeneralOptionsTab::GeneralOptionsTab()
|
|||||||
|
|
||||||
build(config);
|
build(config);
|
||||||
|
|
||||||
const auto & currentResolution = settings["video"]["resolution"];
|
|
||||||
|
|
||||||
std::shared_ptr<CLabel> scalingLabel = widget<CLabel>("scalingLabel");
|
std::shared_ptr<CLabel> scalingLabel = widget<CLabel>("scalingLabel");
|
||||||
scalingLabel->setText(scalingToLabelString(currentResolution["scaling"].Integer()));
|
scalingLabel->setText(scalingToLabelString(GH.screenHandler().getInterfaceScalingPercentage()));
|
||||||
|
|
||||||
std::shared_ptr<CLabel> longTouchLabel = widget<CLabel>("longTouchLabel");
|
std::shared_ptr<CLabel> longTouchLabel = widget<CLabel>("longTouchLabel");
|
||||||
if (longTouchLabel)
|
if (longTouchLabel)
|
||||||
|
@ -184,6 +184,7 @@
|
|||||||
"targetfps",
|
"targetfps",
|
||||||
"vsync",
|
"vsync",
|
||||||
"fontsType",
|
"fontsType",
|
||||||
|
"cursorScalingFactor",
|
||||||
"fontScalingFactor",
|
"fontScalingFactor",
|
||||||
"upscalingFilter",
|
"upscalingFilter",
|
||||||
"fontUpscalingFilter",
|
"fontUpscalingFilter",
|
||||||
@ -195,22 +196,19 @@
|
|||||||
"additionalProperties" : false,
|
"additionalProperties" : false,
|
||||||
"required" : [ "width", "height", "scaling" ],
|
"required" : [ "width", "height", "scaling" ],
|
||||||
"properties" : {
|
"properties" : {
|
||||||
"width" : { "type" : "number" },
|
"width" : { "type" : "number", "default" : 1280 },
|
||||||
"height" : { "type" : "number" },
|
"height" : { "type" : "number", "default" : 720 },
|
||||||
"scaling" : { "type" : "number" }
|
"scaling" : { "type" : "number", "default" : 0 }
|
||||||
},
|
}
|
||||||
"defaultIOS" : {"width" : 800, "height" : 600, "scaling" : 200 },
|
|
||||||
"defaultAndroid" : {"width" : 800, "height" : 600, "scaling" : 200 },
|
|
||||||
"default" : {"width" : 800, "height" : 600, "scaling" : 100 }
|
|
||||||
},
|
},
|
||||||
"reservedWidth" : {
|
"reservedWidth" : {
|
||||||
"type" : "number",
|
"type" : "number",
|
||||||
"defaultIOS" : 0.1, // iOS camera cutout / notch is excluded from available area by SDL
|
"defaultIOS" : 0.1, // iOS camera cutout / notch is not excluded from available area by SDL, handle it this way
|
||||||
"default" : 0
|
"default" : 0
|
||||||
},
|
},
|
||||||
"fullscreen" : {
|
"fullscreen" : {
|
||||||
"type" : "boolean",
|
"type" : "boolean",
|
||||||
"default" : false
|
"default" : true
|
||||||
},
|
},
|
||||||
"realFullscreen" : {
|
"realFullscreen" : {
|
||||||
"type" : "boolean",
|
"type" : "boolean",
|
||||||
@ -256,6 +254,10 @@
|
|||||||
"enum" : [ "auto", "original", "scalable" ],
|
"enum" : [ "auto", "original", "scalable" ],
|
||||||
"default" : "auto"
|
"default" : "auto"
|
||||||
},
|
},
|
||||||
|
"cursorScalingFactor" : {
|
||||||
|
"type" : "number",
|
||||||
|
"default" : 1
|
||||||
|
},
|
||||||
"fontScalingFactor" : {
|
"fontScalingFactor" : {
|
||||||
"type" : "number",
|
"type" : "number",
|
||||||
"default" : 1
|
"default" : 1
|
||||||
|
@ -26,7 +26,7 @@ class DLL_LINKAGE INativeTerrainProvider
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual TerrainId getNativeTerrain() const = 0;
|
virtual TerrainId getNativeTerrain() const = 0;
|
||||||
virtual FactionID getFaction() const = 0;
|
virtual FactionID getFactionID() const = 0;
|
||||||
virtual bool isNativeTerrain(TerrainId terrain) const;
|
virtual bool isNativeTerrain(TerrainId terrain) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -202,6 +202,10 @@ elseif(NOT APPLE_IOS)
|
|||||||
target_link_libraries(vcmilauncher SDL2::SDL2)
|
target_link_libraries(vcmilauncher SDL2::SDL2)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(ENABLE_STATIC_LIBS OR NOT (ENABLE_EDITOR AND ENABLE_LAUNCHER))
|
||||||
|
target_compile_definitions(vcmilauncher PRIVATE VCMIQT_STATIC)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_libraries(vcmilauncher vcmi vcmiqt Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network)
|
target_link_libraries(vcmilauncher vcmi vcmiqt Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network)
|
||||||
target_include_directories(vcmilauncher
|
target_include_directories(vcmilauncher
|
||||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
|
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
@ -127,7 +127,12 @@ void CSettingsView::loadSettings()
|
|||||||
#endif
|
#endif
|
||||||
fillValidScalingRange();
|
fillValidScalingRange();
|
||||||
|
|
||||||
ui->spinBoxInterfaceScaling->setValue(settings["video"]["resolution"]["scaling"].Float());
|
ui->buttonScalingAuto->setChecked(settings["video"]["resolution"]["scaling"].Integer() == 0);
|
||||||
|
if (settings["video"]["resolution"]["scaling"].Integer() == 0)
|
||||||
|
ui->spinBoxInterfaceScaling->setValue(100);
|
||||||
|
else
|
||||||
|
ui->spinBoxInterfaceScaling->setValue(settings["video"]["resolution"]["scaling"].Float());
|
||||||
|
|
||||||
ui->spinBoxFramerateLimit->setValue(settings["video"]["targetfps"].Float());
|
ui->spinBoxFramerateLimit->setValue(settings["video"]["targetfps"].Float());
|
||||||
ui->spinBoxFramerateLimit->setDisabled(settings["video"]["vsync"].Bool());
|
ui->spinBoxFramerateLimit->setDisabled(settings["video"]["vsync"].Bool());
|
||||||
ui->sliderReservedArea->setValue(std::round(settings["video"]["reservedWidth"].Float() * 100));
|
ui->sliderReservedArea->setValue(std::round(settings["video"]["reservedWidth"].Float() * 100));
|
||||||
@ -174,6 +179,7 @@ void CSettingsView::loadSettings()
|
|||||||
ui->sliderControllerSticksAcceleration->setValue(settings["input"]["controllerAxisScale"].Float() * 100);
|
ui->sliderControllerSticksAcceleration->setValue(settings["input"]["controllerAxisScale"].Float() * 100);
|
||||||
ui->lineEditGameLobbyHost->setText(QString::fromStdString(settings["lobby"]["hostname"].String()));
|
ui->lineEditGameLobbyHost->setText(QString::fromStdString(settings["lobby"]["hostname"].String()));
|
||||||
ui->spinBoxNetworkPortLobby->setValue(settings["lobby"]["port"].Integer());
|
ui->spinBoxNetworkPortLobby->setValue(settings["lobby"]["port"].Integer());
|
||||||
|
ui->buttonVSync->setChecked(settings["video"]["vsync"].Bool());
|
||||||
|
|
||||||
if (settings["video"]["fontsType"].String() == "auto")
|
if (settings["video"]["fontsType"].String() == "auto")
|
||||||
ui->buttonFontAuto->setChecked(true);
|
ui->buttonFontAuto->setChecked(true);
|
||||||
@ -195,7 +201,6 @@ void CSettingsView::loadSettings()
|
|||||||
void CSettingsView::loadToggleButtonSettings()
|
void CSettingsView::loadToggleButtonSettings()
|
||||||
{
|
{
|
||||||
setCheckbuttonState(ui->buttonShowIntro, settings["video"]["showIntro"].Bool());
|
setCheckbuttonState(ui->buttonShowIntro, settings["video"]["showIntro"].Bool());
|
||||||
setCheckbuttonState(ui->buttonVSync, settings["video"]["vsync"].Bool());
|
|
||||||
setCheckbuttonState(ui->buttonAutoCheck, settings["launcher"]["autoCheckRepositories"].Bool());
|
setCheckbuttonState(ui->buttonAutoCheck, settings["launcher"]["autoCheckRepositories"].Bool());
|
||||||
|
|
||||||
setCheckbuttonState(ui->buttonRepositoryDefault, settings["launcher"]["defaultRepositoryEnabled"].Bool());
|
setCheckbuttonState(ui->buttonRepositoryDefault, settings["launcher"]["defaultRepositoryEnabled"].Bool());
|
||||||
@ -212,10 +217,15 @@ void CSettingsView::loadToggleButtonSettings()
|
|||||||
std::string cursorType = settings["video"]["cursor"].String();
|
std::string cursorType = settings["video"]["cursor"].String();
|
||||||
int cursorTypeIndex = vstd::find_pos(cursorTypesList, cursorType);
|
int cursorTypeIndex = vstd::find_pos(cursorTypesList, cursorType);
|
||||||
setCheckbuttonState(ui->buttonCursorType, cursorTypeIndex);
|
setCheckbuttonState(ui->buttonCursorType, cursorTypeIndex);
|
||||||
|
ui->sliderScalingCursor->setDisabled(cursorType == "software"); // Not supported
|
||||||
|
ui->labelScalingCursorValue->setDisabled(cursorType == "software"); // Not supported
|
||||||
|
|
||||||
int fontScalingPercentage = settings["video"]["fontScalingFactor"].Float() * 100;
|
int fontScalingPercentage = settings["video"]["fontScalingFactor"].Float() * 100;
|
||||||
ui->sliderScalingFont->setValue(fontScalingPercentage / 5);
|
ui->sliderScalingFont->setValue(fontScalingPercentage / 5);
|
||||||
|
|
||||||
|
int cursorScalingPercentage = settings["video"]["cursorScalingFactor"].Float() * 100;
|
||||||
|
ui->sliderScalingCursor->setValue(cursorScalingPercentage / 5);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSettingsView::fillValidResolutions()
|
void CSettingsView::fillValidResolutions()
|
||||||
@ -494,6 +504,8 @@ void CSettingsView::on_buttonCursorType_toggled(bool value)
|
|||||||
Settings node = settings.write["video"]["cursor"];
|
Settings node = settings.write["video"]["cursor"];
|
||||||
node->String() = cursorTypesList[value ? 1 : 0];
|
node->String() = cursorTypesList[value ? 1 : 0];
|
||||||
updateCheckbuttonText(ui->buttonCursorType);
|
updateCheckbuttonText(ui->buttonCursorType);
|
||||||
|
ui->sliderScalingCursor->setDisabled(value == 1); // Not supported
|
||||||
|
ui->labelScalingCursorValue->setDisabled(value == 1); // Not supported
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSettingsView::loadTranslation()
|
void CSettingsView::loadTranslation()
|
||||||
@ -627,7 +639,6 @@ void CSettingsView::on_buttonVSync_toggled(bool value)
|
|||||||
Settings node = settings.write["video"]["vsync"];
|
Settings node = settings.write["video"]["vsync"];
|
||||||
node->Bool() = value;
|
node->Bool() = value;
|
||||||
ui->spinBoxFramerateLimit->setDisabled(settings["video"]["vsync"].Bool());
|
ui->spinBoxFramerateLimit->setDisabled(settings["video"]["vsync"].Bool());
|
||||||
updateCheckbuttonText(ui->buttonVSync);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSettingsView::on_comboBoxEnemyPlayerAI_currentTextChanged(const QString &arg1)
|
void CSettingsView::on_comboBoxEnemyPlayerAI_currentTextChanged(const QString &arg1)
|
||||||
@ -816,3 +827,21 @@ void CSettingsView::on_buttonValidationFull_clicked(bool checked)
|
|||||||
Settings node = settings.write["mods"]["validation"];
|
Settings node = settings.write["mods"]["validation"];
|
||||||
node->String() = "full";
|
node->String() = "full";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSettingsView::on_sliderScalingCursor_valueChanged(int value)
|
||||||
|
{
|
||||||
|
int actualValuePercentage = value * 5;
|
||||||
|
ui->labelScalingCursorValue->setText(QString("%1%").arg(actualValuePercentage));
|
||||||
|
Settings node = settings.write["video"]["cursorScalingFactor"];
|
||||||
|
node->Float() = actualValuePercentage / 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSettingsView::on_buttonScalingAuto_toggled(bool checked)
|
||||||
|
{
|
||||||
|
ui->spinBoxInterfaceScaling->setDisabled(checked);
|
||||||
|
ui->spinBoxInterfaceScaling->setValue(100);
|
||||||
|
|
||||||
|
Settings node = settings.write["video"]["resolution"]["scaling"];
|
||||||
|
node->Integer() = checked ? 0 : 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -97,6 +97,10 @@ private slots:
|
|||||||
|
|
||||||
void on_buttonValidationFull_clicked(bool checked);
|
void on_buttonValidationFull_clicked(bool checked);
|
||||||
|
|
||||||
|
void on_sliderScalingCursor_valueChanged(int value);
|
||||||
|
|
||||||
|
void on_buttonScalingAuto_toggled(bool checked);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::CSettingsView * ui;
|
Ui::CSettingsView * ui;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -38,7 +38,7 @@ TerrainId AFactionMember::getNativeTerrain() const
|
|||||||
//this code is used in the CreatureTerrainLimiter::limit to setup battle bonuses
|
//this code is used in the CreatureTerrainLimiter::limit to setup battle bonuses
|
||||||
//and in the CGHeroInstance::getNativeTerrain() to setup movement bonuses or/and penalties.
|
//and in the CGHeroInstance::getNativeTerrain() to setup movement bonuses or/and penalties.
|
||||||
return getBonusBearer()->hasBonus(selectorNoTerrainPenalty, cachingStringNoTerrainPenalty)
|
return getBonusBearer()->hasBonus(selectorNoTerrainPenalty, cachingStringNoTerrainPenalty)
|
||||||
? TerrainId::ANY_TERRAIN : VLC->factions()->getById(getFaction())->getNativeTerrain();
|
? TerrainId::ANY_TERRAIN : getFactionID().toEntity(VLC)->getNativeTerrain();
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t AFactionMember::magicResistance() const
|
int32_t AFactionMember::magicResistance() const
|
||||||
|
@ -117,7 +117,7 @@ int32_t CCreature::getHorde() const
|
|||||||
return hordeGrowth;
|
return hordeGrowth;
|
||||||
}
|
}
|
||||||
|
|
||||||
FactionID CCreature::getFaction() const
|
FactionID CCreature::getFactionID() const
|
||||||
{
|
{
|
||||||
return FactionID(faction);
|
return FactionID(faction);
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ public:
|
|||||||
std::string getNamePluralTextID() const override;
|
std::string getNamePluralTextID() const override;
|
||||||
std::string getNameSingularTextID() const override;
|
std::string getNameSingularTextID() const override;
|
||||||
|
|
||||||
FactionID getFaction() const override;
|
FactionID getFactionID() const override;
|
||||||
int32_t getIndex() const override;
|
int32_t getIndex() const override;
|
||||||
int32_t getIconIndex() const override;
|
int32_t getIconIndex() const override;
|
||||||
std::string getJsonKey() const override;
|
std::string getJsonKey() const override;
|
||||||
|
@ -926,10 +926,10 @@ void CStackInstance::serializeJson(JsonSerializeFormat & handler)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FactionID CStackInstance::getFaction() const
|
FactionID CStackInstance::getFactionID() const
|
||||||
{
|
{
|
||||||
if(type)
|
if(type)
|
||||||
return type->getFaction();
|
return type->getFactionID();
|
||||||
|
|
||||||
return FactionID::NEUTRAL;
|
return FactionID::NEUTRAL;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ public:
|
|||||||
//IConstBonusProvider
|
//IConstBonusProvider
|
||||||
const IBonusBearer* getBonusBearer() const override;
|
const IBonusBearer* getBonusBearer() const override;
|
||||||
//INativeTerrainProvider
|
//INativeTerrainProvider
|
||||||
FactionID getFaction() const override;
|
FactionID getFactionID() const override;
|
||||||
|
|
||||||
virtual ui64 getPower() const;
|
virtual ui64 getPower() const;
|
||||||
/// Returns total market value of resources needed to recruit this unit
|
/// Returns total market value of resources needed to recruit this unit
|
||||||
|
@ -381,7 +381,7 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero
|
|||||||
|
|
||||||
for(const auto & creature : VLC->creh->objects)
|
for(const auto & creature : VLC->creh->objects)
|
||||||
{
|
{
|
||||||
if(creature->getFaction() == factionIndex && static_cast<int>(creature->getAIValue()) > maxAIValue)
|
if(creature->getFactionID() == factionIndex && static_cast<int>(creature->getAIValue()) > maxAIValue)
|
||||||
{
|
{
|
||||||
maxAIValue = creature->getAIValue();
|
maxAIValue = creature->getAIValue();
|
||||||
mostStrong = creature.get();
|
mostStrong = creature.get();
|
||||||
@ -539,7 +539,7 @@ EDiggingStatus CGameInfoCallback::getTileDigStatus(int3 tile, bool verbose) cons
|
|||||||
|
|
||||||
for(const auto & object : gs->map->objects)
|
for(const auto & object : gs->map->objects)
|
||||||
{
|
{
|
||||||
if(object && object->ID == Obj::HOLE && object->pos == tile)
|
if(object && object->ID == Obj::HOLE && object->anchorPos() == tile)
|
||||||
return EDiggingStatus::TILE_OCCUPIED;
|
return EDiggingStatus::TILE_OCCUPIED;
|
||||||
}
|
}
|
||||||
return getTile(tile)->getDiggingStatus();
|
return getTile(tile)->getDiggingStatus();
|
||||||
@ -575,10 +575,10 @@ EBuildingState CGameInfoCallback::canBuildStructure( const CGTownInstance *t, Bu
|
|||||||
{
|
{
|
||||||
ERROR_RET_VAL_IF(!canGetFullInfo(t), "Town is not owned!", EBuildingState::TOWN_NOT_OWNED);
|
ERROR_RET_VAL_IF(!canGetFullInfo(t), "Town is not owned!", EBuildingState::TOWN_NOT_OWNED);
|
||||||
|
|
||||||
if(!t->town->buildings.count(ID))
|
if(!t->getTown()->buildings.count(ID))
|
||||||
return EBuildingState::BUILDING_ERROR;
|
return EBuildingState::BUILDING_ERROR;
|
||||||
|
|
||||||
const CBuilding * building = t->town->buildings.at(ID);
|
const CBuilding * building = t->getTown()->buildings.at(ID);
|
||||||
|
|
||||||
|
|
||||||
if(t->hasBuilt(ID)) //already built
|
if(t->hasBuilt(ID)) //already built
|
||||||
|
@ -559,6 +559,7 @@ set(lib_MAIN_HEADERS
|
|||||||
networkPacks/PacksForServer.h
|
networkPacks/PacksForServer.h
|
||||||
networkPacks/SetRewardableConfiguration.h
|
networkPacks/SetRewardableConfiguration.h
|
||||||
networkPacks/SetStackEffect.h
|
networkPacks/SetStackEffect.h
|
||||||
|
networkPacks/SaveLocalState.h
|
||||||
networkPacks/StackLocation.h
|
networkPacks/StackLocation.h
|
||||||
networkPacks/TradeItem.h
|
networkPacks/TradeItem.h
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "StdInc.h"
|
#include "StdInc.h"
|
||||||
|
|
||||||
#include "CPlayerState.h"
|
#include "CPlayerState.h"
|
||||||
|
#include "json/JsonNode.h"
|
||||||
#include "mapObjects/CGDwelling.h"
|
#include "mapObjects/CGDwelling.h"
|
||||||
#include "mapObjects/CGTownInstance.h"
|
#include "mapObjects/CGTownInstance.h"
|
||||||
#include "mapObjects/CGHeroInstance.h"
|
#include "mapObjects/CGHeroInstance.h"
|
||||||
@ -20,8 +21,13 @@
|
|||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
PlayerState::PlayerState()
|
PlayerState::PlayerState()
|
||||||
: color(-1), human(false), cheated(false), enteredWinningCheatCode(false),
|
: color(-1)
|
||||||
enteredLosingCheatCode(false), status(EPlayerStatus::INGAME)
|
, playerLocalSettings(std::make_unique<JsonNode>())
|
||||||
|
, human(false)
|
||||||
|
, cheated(false)
|
||||||
|
, enteredWinningCheatCode(false)
|
||||||
|
, enteredLosingCheatCode(false)
|
||||||
|
, status(EPlayerStatus::INGAME)
|
||||||
{
|
{
|
||||||
setNodeType(PLAYER);
|
setNodeType(PLAYER);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#include "bonuses/CBonusSystemNode.h"
|
#include "bonuses/CBonusSystemNode.h"
|
||||||
#include "ResourceSet.h"
|
#include "ResourceSet.h"
|
||||||
#include "TurnTimerInfo.h"
|
#include "TurnTimerInfo.h"
|
||||||
#include "ConstTransitivePtr.h"
|
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -66,6 +65,7 @@ public:
|
|||||||
std::vector<QuestInfo> quests; //store info about all received quests
|
std::vector<QuestInfo> quests; //store info about all received quests
|
||||||
std::vector<Bonus> battleBonuses; //additional bonuses to be added during battle with neutrals
|
std::vector<Bonus> battleBonuses; //additional bonuses to be added during battle with neutrals
|
||||||
std::map<uint32_t, std::map<ArtifactPosition, ArtifactID>> costumesArtifacts;
|
std::map<uint32_t, std::map<ArtifactPosition, ArtifactID>> costumesArtifacts;
|
||||||
|
std::unique_ptr<JsonNode> playerLocalSettings; // Json with client-defined data, such as order of heroes or current hero paths. Not used by client/lib
|
||||||
|
|
||||||
bool cheated;
|
bool cheated;
|
||||||
bool enteredWinningCheatCode, enteredLosingCheatCode; //if true, this player has entered cheat codes for loss / victory
|
bool enteredWinningCheatCode, enteredLosingCheatCode; //if true, this player has entered cheat codes for loss / victory
|
||||||
@ -116,6 +116,9 @@ public:
|
|||||||
h & status;
|
h & status;
|
||||||
h & turnTimer;
|
h & turnTimer;
|
||||||
|
|
||||||
|
if (h.version >= Handler::Version::LOCAL_PLAYER_STATE_DATA)
|
||||||
|
h & *playerLocalSettings;
|
||||||
|
|
||||||
if (h.version >= Handler::Version::PLAYER_STATE_OWNED_OBJECTS)
|
if (h.version >= Handler::Version::PLAYER_STATE_OWNED_OBJECTS)
|
||||||
{
|
{
|
||||||
h & ownedObjects;
|
h & ownedObjects;
|
||||||
|
@ -416,9 +416,9 @@ int32_t CUnitState::creatureIconIndex() const
|
|||||||
return unitType()->getIconIndex();
|
return unitType()->getIconIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
FactionID CUnitState::getFaction() const
|
FactionID CUnitState::getFactionID() const
|
||||||
{
|
{
|
||||||
return unitType()->getFaction();
|
return unitType()->getFactionID();
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t CUnitState::getCasterUnitId() const
|
int32_t CUnitState::getCasterUnitId() const
|
||||||
|
@ -253,7 +253,7 @@ public:
|
|||||||
void localInit(const IUnitEnvironment * env_);
|
void localInit(const IUnitEnvironment * env_);
|
||||||
void serializeJson(JsonSerializeFormat & handler);
|
void serializeJson(JsonSerializeFormat & handler);
|
||||||
|
|
||||||
FactionID getFaction() const override;
|
FactionID getFactionID() const override;
|
||||||
|
|
||||||
void afterAttack(bool ranged, bool counter);
|
void afterAttack(bool ranged, bool counter);
|
||||||
|
|
||||||
|
@ -300,15 +300,15 @@ ILimiter::EDecision FactionLimiter::limit(const BonusLimitationContext &context)
|
|||||||
if(bearer)
|
if(bearer)
|
||||||
{
|
{
|
||||||
if(faction != FactionID::DEFAULT)
|
if(faction != FactionID::DEFAULT)
|
||||||
return bearer->getFaction() == faction ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
return bearer->getFactionID() == faction ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||||
|
|
||||||
switch(context.b.source)
|
switch(context.b.source)
|
||||||
{
|
{
|
||||||
case BonusSource::CREATURE_ABILITY:
|
case BonusSource::CREATURE_ABILITY:
|
||||||
return bearer->getFaction() == context.b.sid.as<CreatureID>().toCreature()->getFaction() ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
return bearer->getFactionID() == context.b.sid.as<CreatureID>().toCreature()->getFactionID() ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||||
|
|
||||||
case BonusSource::TOWN_STRUCTURE:
|
case BonusSource::TOWN_STRUCTURE:
|
||||||
return bearer->getFaction() == context.b.sid.as<BuildingTypeUniqueID>().getFaction() ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
return bearer->getFactionID() == context.b.sid.as<BuildingTypeUniqueID>().getFaction() ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||||
|
|
||||||
//TODO: other sources of bonuses
|
//TODO: other sources of bonuses
|
||||||
}
|
}
|
||||||
|
@ -351,14 +351,14 @@ void CampaignState::setCurrentMapAsConquered(std::vector<CGHeroInstance *> heroe
|
|||||||
{
|
{
|
||||||
JsonNode node = CampaignState::crossoverSerialize(hero);
|
JsonNode node = CampaignState::crossoverSerialize(hero);
|
||||||
|
|
||||||
if (reservedHeroes.count(hero->getHeroType()))
|
if (reservedHeroes.count(hero->getHeroTypeID()))
|
||||||
{
|
{
|
||||||
logGlobal->info("Hero crossover: %d (%s) exported to global pool", hero->getHeroType(), hero->getNameTranslated());
|
logGlobal->info("Hero crossover: %d (%s) exported to global pool", hero->getHeroTypeID(), hero->getNameTranslated());
|
||||||
globalHeroPool[hero->getHeroType()] = node;
|
globalHeroPool[hero->getHeroTypeID()] = node;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logGlobal->info("Hero crossover: %d (%s) exported to scenario pool", hero->getHeroType(), hero->getNameTranslated());
|
logGlobal->info("Hero crossover: %d (%s) exported to scenario pool", hero->getHeroTypeID(), hero->getNameTranslated());
|
||||||
scenarioHeroPool[*currentMap].push_back(node);
|
scenarioHeroPool[*currentMap].push_back(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ FactionID CFaction::getId() const
|
|||||||
return FactionID(index);
|
return FactionID(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
FactionID CFaction::getFaction() const
|
FactionID CFaction::getFactionID() const
|
||||||
{
|
{
|
||||||
return FactionID(index);
|
return FactionID(index);
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ class DLL_LINKAGE CFaction : public Faction
|
|||||||
|
|
||||||
FactionID index = FactionID::NEUTRAL;
|
FactionID index = FactionID::NEUTRAL;
|
||||||
|
|
||||||
FactionID getFaction() const override; //This function should not be used
|
FactionID getFactionID() const override; //This function should not be used
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TerrainId nativeTerrain;
|
TerrainId nativeTerrain;
|
||||||
|
@ -883,8 +883,8 @@ void CTownHandler::beforeValidate(JsonNode & object)
|
|||||||
if (building.second.Struct().count("onVisitBonuses"))
|
if (building.second.Struct().count("onVisitBonuses"))
|
||||||
{
|
{
|
||||||
building.second["configuration"]["visitMode"] = JsonNode("bonus");
|
building.second["configuration"]["visitMode"] = JsonNode("bonus");
|
||||||
building.second["configuration"]["visitMode"]["rewards"][0]["message"] = building.second["description"];
|
building.second["configuration"]["rewards"][0]["message"] = building.second["description"];
|
||||||
building.second["configuration"]["visitMode"]["rewards"][0]["bonuses"] = building.second["onVisitBonuses"];
|
building.second["configuration"]["rewards"][0]["bonuses"] = building.second["onVisitBonuses"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -449,7 +449,7 @@ void CGameState::initGrailPosition()
|
|||||||
//remove tiles with holes
|
//remove tiles with holes
|
||||||
for(auto & elem : map->objects)
|
for(auto & elem : map->objects)
|
||||||
if(elem && elem->ID == Obj::HOLE)
|
if(elem && elem->ID == Obj::HOLE)
|
||||||
allowedPos -= elem->pos;
|
allowedPos -= elem->anchorPos();
|
||||||
|
|
||||||
if(!allowedPos.empty())
|
if(!allowedPos.empty())
|
||||||
{
|
{
|
||||||
@ -495,7 +495,7 @@ void CGameState::randomizeMapObjects()
|
|||||||
{
|
{
|
||||||
for (int j = 0; j < object->getHeight() ; j++)
|
for (int j = 0; j < object->getHeight() ; j++)
|
||||||
{
|
{
|
||||||
int3 pos = object->pos - int3(i,j,0);
|
int3 pos = object->anchorPos() - int3(i,j,0);
|
||||||
if(map->isInTheMap(pos)) map->getTile(pos).extTileFlags |= 128;
|
if(map->isInTheMap(pos)) map->getTile(pos).extTileFlags |= 128;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -530,7 +530,7 @@ void CGameState::placeStartingHero(const PlayerColor & playerColor, const HeroTy
|
|||||||
{
|
{
|
||||||
for(auto town : map->towns)
|
for(auto town : map->towns)
|
||||||
{
|
{
|
||||||
if(town->getPosition() == townPos)
|
if(town->anchorPos() == townPos)
|
||||||
{
|
{
|
||||||
townPos = town->visitablePos();
|
townPos = town->visitablePos();
|
||||||
break;
|
break;
|
||||||
@ -545,8 +545,7 @@ void CGameState::placeStartingHero(const PlayerColor & playerColor, const HeroTy
|
|||||||
hero->setHeroType(heroTypeId);
|
hero->setHeroType(heroTypeId);
|
||||||
hero->tempOwner = playerColor;
|
hero->tempOwner = playerColor;
|
||||||
|
|
||||||
hero->pos = townPos;
|
hero->setAnchorPos(townPos + hero->getVisitableOffset());
|
||||||
hero->pos += hero->getVisitableOffset();
|
|
||||||
map->getEditManager()->insertObject(hero);
|
map->getEditManager()->insertObject(hero);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,7 +599,7 @@ void CGameState::initHeroes()
|
|||||||
}
|
}
|
||||||
|
|
||||||
hero->initHero(getRandomGenerator());
|
hero->initHero(getRandomGenerator());
|
||||||
map->allHeroes[hero->getHeroType().getNum()] = hero;
|
map->allHeroes[hero->getHeroTypeID().getNum()] = hero;
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate boats for all heroes on water
|
// generate boats for all heroes on water
|
||||||
@ -614,7 +613,7 @@ void CGameState::initHeroes()
|
|||||||
auto boat = dynamic_cast<CGBoat*>(handler->create(callback, nullptr));
|
auto boat = dynamic_cast<CGBoat*>(handler->create(callback, nullptr));
|
||||||
handler->configureObject(boat, gs->getRandomGenerator());
|
handler->configureObject(boat, gs->getRandomGenerator());
|
||||||
|
|
||||||
boat->pos = hero->pos;
|
boat->setAnchorPos(hero->anchorPos());
|
||||||
boat->appearance = handler->getTemplates().front();
|
boat->appearance = handler->getTemplates().front();
|
||||||
boat->id = ObjectInstanceID(static_cast<si32>(gs->map->objects.size()));
|
boat->id = ObjectInstanceID(static_cast<si32>(gs->map->objects.size()));
|
||||||
|
|
||||||
@ -630,20 +629,20 @@ void CGameState::initHeroes()
|
|||||||
{
|
{
|
||||||
auto * hero = dynamic_cast<CGHeroInstance*>(obj.get());
|
auto * hero = dynamic_cast<CGHeroInstance*>(obj.get());
|
||||||
hero->initHero(getRandomGenerator());
|
hero->initHero(getRandomGenerator());
|
||||||
map->allHeroes[hero->getHeroType().getNum()] = hero;
|
map->allHeroes[hero->getHeroTypeID().getNum()] = hero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<HeroTypeID> heroesToCreate = getUnusedAllowedHeroes(); //ids of heroes to be created and put into the pool
|
std::set<HeroTypeID> heroesToCreate = getUnusedAllowedHeroes(); //ids of heroes to be created and put into the pool
|
||||||
for(auto ph : map->predefinedHeroes)
|
for(auto ph : map->predefinedHeroes)
|
||||||
{
|
{
|
||||||
if(!vstd::contains(heroesToCreate, ph->getHeroType()))
|
if(!vstd::contains(heroesToCreate, ph->getHeroTypeID()))
|
||||||
continue;
|
continue;
|
||||||
ph->initHero(getRandomGenerator());
|
ph->initHero(getRandomGenerator());
|
||||||
heroesPool->addHeroToPool(ph);
|
heroesPool->addHeroToPool(ph);
|
||||||
heroesToCreate.erase(ph->type->getId());
|
heroesToCreate.erase(ph->getHeroTypeID());
|
||||||
|
|
||||||
map->allHeroes[ph->getHeroType().getNum()] = ph;
|
map->allHeroes[ph->getHeroTypeID().getNum()] = ph;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const HeroTypeID & htype : heroesToCreate) //all not used allowed heroes go with default state into the pool
|
for(const HeroTypeID & htype : heroesToCreate) //all not used allowed heroes go with default state into the pool
|
||||||
@ -757,12 +756,12 @@ void CGameState::initTownNames()
|
|||||||
|
|
||||||
for(auto & vti : map->towns)
|
for(auto & vti : map->towns)
|
||||||
{
|
{
|
||||||
assert(vti->town);
|
assert(vti->getTown());
|
||||||
|
|
||||||
if(!vti->getNameTextID().empty())
|
if(!vti->getNameTextID().empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
FactionID faction = vti->getFaction();
|
FactionID faction = vti->getFactionID();
|
||||||
|
|
||||||
if(availableNames.empty())
|
if(availableNames.empty())
|
||||||
{
|
{
|
||||||
@ -799,8 +798,8 @@ void CGameState::initTowns()
|
|||||||
|
|
||||||
for (auto & vti : map->towns)
|
for (auto & vti : map->towns)
|
||||||
{
|
{
|
||||||
assert(vti->town);
|
assert(vti->getTown());
|
||||||
assert(vti->town->creatures.size() <= GameConstants::CREATURES_PER_TOWN);
|
assert(vti->getTown()->creatures.size() <= GameConstants::CREATURES_PER_TOWN);
|
||||||
|
|
||||||
constexpr std::array basicDwellings = { BuildingID::DWELL_FIRST, BuildingID::DWELL_LVL_2, BuildingID::DWELL_LVL_3, BuildingID::DWELL_LVL_4, BuildingID::DWELL_LVL_5, BuildingID::DWELL_LVL_6, BuildingID::DWELL_LVL_7, BuildingID::DWELL_LVL_8 };
|
constexpr std::array basicDwellings = { BuildingID::DWELL_FIRST, BuildingID::DWELL_LVL_2, BuildingID::DWELL_LVL_3, BuildingID::DWELL_LVL_4, BuildingID::DWELL_LVL_5, BuildingID::DWELL_LVL_6, BuildingID::DWELL_LVL_7, BuildingID::DWELL_LVL_8 };
|
||||||
constexpr std::array upgradedDwellings = { BuildingID::DWELL_UP_FIRST, BuildingID::DWELL_LVL_2_UP, BuildingID::DWELL_LVL_3_UP, BuildingID::DWELL_LVL_4_UP, BuildingID::DWELL_LVL_5_UP, BuildingID::DWELL_LVL_6_UP, BuildingID::DWELL_LVL_7_UP, BuildingID::DWELL_LVL_8_UP };
|
constexpr std::array upgradedDwellings = { BuildingID::DWELL_UP_FIRST, BuildingID::DWELL_LVL_2_UP, BuildingID::DWELL_LVL_3_UP, BuildingID::DWELL_LVL_4_UP, BuildingID::DWELL_LVL_5_UP, BuildingID::DWELL_LVL_6_UP, BuildingID::DWELL_LVL_7_UP, BuildingID::DWELL_LVL_8_UP };
|
||||||
@ -829,7 +828,7 @@ void CGameState::initTowns()
|
|||||||
vti->addBuilding(BuildingID::VILLAGE_HALL);
|
vti->addBuilding(BuildingID::VILLAGE_HALL);
|
||||||
|
|
||||||
//init hordes
|
//init hordes
|
||||||
for (int i = 0; i < vti->town->creatures.size(); i++)
|
for (int i = 0; i < vti->getTown()->creatures.size(); i++)
|
||||||
{
|
{
|
||||||
if(vti->hasBuilt(hordes[i])) //if we have horde for this level
|
if(vti->hasBuilt(hordes[i])) //if we have horde for this level
|
||||||
{
|
{
|
||||||
@ -895,7 +894,7 @@ void CGameState::initTowns()
|
|||||||
int sel = -1;
|
int sel = -1;
|
||||||
|
|
||||||
for(ui32 ps=0;ps<vti->possibleSpells.size();ps++)
|
for(ui32 ps=0;ps<vti->possibleSpells.size();ps++)
|
||||||
total += vti->possibleSpells[ps].toSpell()->getProbability(vti->getFaction());
|
total += vti->possibleSpells[ps].toSpell()->getProbability(vti->getFactionID());
|
||||||
|
|
||||||
if (total == 0) // remaining spells have 0 probability
|
if (total == 0) // remaining spells have 0 probability
|
||||||
break;
|
break;
|
||||||
@ -903,7 +902,7 @@ void CGameState::initTowns()
|
|||||||
auto r = getRandomGenerator().nextInt(total - 1);
|
auto r = getRandomGenerator().nextInt(total - 1);
|
||||||
for(ui32 ps=0; ps<vti->possibleSpells.size();ps++)
|
for(ui32 ps=0; ps<vti->possibleSpells.size();ps++)
|
||||||
{
|
{
|
||||||
r -= vti->possibleSpells[ps].toSpell()->getProbability(vti->getFaction());
|
r -= vti->possibleSpells[ps].toSpell()->getProbability(vti->getFactionID());
|
||||||
if(r<0)
|
if(r<0)
|
||||||
{
|
{
|
||||||
sel = ps;
|
sel = ps;
|
||||||
@ -964,22 +963,18 @@ void CGameState::placeHeroesInTowns()
|
|||||||
{
|
{
|
||||||
for(CGTownInstance * t : player.second.getTowns())
|
for(CGTownInstance * t : player.second.getTowns())
|
||||||
{
|
{
|
||||||
if(h->visitablePos().z != t->visitablePos().z)
|
bool heroOnTownBlockableTile = t->blockingAt(h->visitablePos());
|
||||||
continue;
|
|
||||||
|
|
||||||
bool heroOnTownBlockableTile = t->blockingAt(h->visitablePos().x, h->visitablePos().y);
|
|
||||||
|
|
||||||
// current hero position is at one of blocking tiles of current town
|
// current hero position is at one of blocking tiles of current town
|
||||||
// assume that this hero should be visiting the town (H3M format quirk) and move hero to correct position
|
// assume that this hero should be visiting the town (H3M format quirk) and move hero to correct position
|
||||||
if (heroOnTownBlockableTile)
|
if (heroOnTownBlockableTile)
|
||||||
{
|
{
|
||||||
int3 correctedPos = h->convertFromVisitablePos(t->visitablePos());
|
|
||||||
|
|
||||||
map->removeBlockVisTiles(h);
|
map->removeBlockVisTiles(h);
|
||||||
h->pos = correctedPos;
|
int3 correctedPos = h->convertFromVisitablePos(t->visitablePos());
|
||||||
|
h->setAnchorPos(correctedPos);
|
||||||
map->addBlockVisTiles(h);
|
map->addBlockVisTiles(h);
|
||||||
|
|
||||||
assert(t->visitableAt(h->visitablePos().x, h->visitablePos().y));
|
assert(t->visitableAt(h->visitablePos()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1001,7 +996,7 @@ void CGameState::initVisitingAndGarrisonedHeroes()
|
|||||||
if(h->visitablePos().z != t->visitablePos().z)
|
if(h->visitablePos().z != t->visitablePos().z)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (t->visitableAt(h->visitablePos().x, h->visitablePos().y))
|
if (t->visitableAt(h->visitablePos()))
|
||||||
{
|
{
|
||||||
assert(t->visitingHero == nullptr);
|
assert(t->visitingHero == nullptr);
|
||||||
t->setVisitingHero(h);
|
t->setVisitingHero(h);
|
||||||
@ -1066,7 +1061,7 @@ BattleField CGameState::battleGetBattlefieldType(int3 tile, vstd::RNG & rand)
|
|||||||
for(auto &obj : map->objects)
|
for(auto &obj : map->objects)
|
||||||
{
|
{
|
||||||
//look only for objects covering given tile
|
//look only for objects covering given tile
|
||||||
if( !obj || obj->pos.z != tile.z || !obj->coveringAt(tile.x, tile.y))
|
if( !obj || !obj->coveringAt(tile))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto customBattlefield = obj->getBattlefield();
|
auto customBattlefield = obj->getBattlefield();
|
||||||
@ -1250,10 +1245,10 @@ bool CGameState::isVisible(const CGObjectInstance * obj, const std::optional<Pla
|
|||||||
{
|
{
|
||||||
for(int fx=0; fx < obj->getWidth(); ++fx)
|
for(int fx=0; fx < obj->getWidth(); ++fx)
|
||||||
{
|
{
|
||||||
int3 pos = obj->pos + int3(-fx, -fy, 0);
|
int3 pos = obj->anchorPos() + int3(-fx, -fy, 0);
|
||||||
|
|
||||||
if ( map->isInTheMap(pos) &&
|
if ( map->isInTheMap(pos) &&
|
||||||
obj->coveringAt(pos.x, pos.y) &&
|
obj->coveringAt(pos) &&
|
||||||
isVisible(pos, *player))
|
isVisible(pos, *player))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1660,18 +1655,13 @@ std::set<HeroTypeID> CGameState::getUnusedAllowedHeroes(bool alsoIncludeNotAllow
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(auto hero : map->heroesOnMap) //heroes instances initialization
|
for(auto hero : map->heroesOnMap) //heroes instances initialization
|
||||||
{
|
ret -= hero->getHeroTypeID();
|
||||||
if(hero->type)
|
|
||||||
ret -= hero->type->getId();
|
|
||||||
else
|
|
||||||
ret -= hero->getHeroType();
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto obj : map->objects) //prisons
|
for(auto obj : map->objects) //prisons
|
||||||
{
|
{
|
||||||
auto * hero = dynamic_cast<const CGHeroInstance *>(obj.get());
|
auto * hero = dynamic_cast<const CGHeroInstance *>(obj.get());
|
||||||
if(hero && hero->ID == Obj::PRISON)
|
if(hero && hero->ID == Obj::PRISON)
|
||||||
ret -= hero->getHeroType();
|
ret -= hero->getHeroTypeID();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -1695,7 +1685,7 @@ CGHeroInstance * CGameState::getUsedHero(const HeroTypeID & hid) const
|
|||||||
auto * hero = dynamic_cast<CGHeroInstance *>(obj.get());
|
auto * hero = dynamic_cast<CGHeroInstance *>(obj.get());
|
||||||
assert(hero);
|
assert(hero);
|
||||||
|
|
||||||
if (hero->getHeroType() == hid)
|
if (hero->getHeroTypeID() == hid)
|
||||||
return hero;
|
return hero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(const CampaignTravel & tr
|
|||||||
.And(Selector::subtype()(BonusSubtypeID(g)))
|
.And(Selector::subtype()(BonusSubtypeID(g)))
|
||||||
.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL));
|
.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL));
|
||||||
|
|
||||||
hero.hero->getLocalBonus(sel)->val = hero.hero->type->heroClass->primarySkillInitial[g.getNum()];
|
hero.hero->getLocalBonus(sel)->val = hero.hero->getHeroClass()->primarySkillInitial[g.getNum()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(const CampaignTravel & tr
|
|||||||
//trimming sec skills
|
//trimming sec skills
|
||||||
for(auto & hero : campaignHeroReplacements)
|
for(auto & hero : campaignHeroReplacements)
|
||||||
{
|
{
|
||||||
hero.hero->secSkills = hero.hero->type->secSkillsInit;
|
hero.hero->secSkills = hero.hero->getHeroType()->secSkillsInit;
|
||||||
hero.hero->recreateSecondarySkillsBonuses();
|
hero.hero->recreateSecondarySkillsBonuses();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,7 +240,7 @@ void CGameStateCampaign::placeCampaignHeroes()
|
|||||||
|
|
||||||
for(auto & replacement : campaignHeroReplacements)
|
for(auto & replacement : campaignHeroReplacements)
|
||||||
if (replacement.heroPlaceholderId.hasValue())
|
if (replacement.heroPlaceholderId.hasValue())
|
||||||
heroesToRemove.insert(replacement.hero->getHeroType());
|
heroesToRemove.insert(replacement.hero->getHeroTypeID());
|
||||||
|
|
||||||
for(auto & heroID : heroesToRemove)
|
for(auto & heroID : heroesToRemove)
|
||||||
{
|
{
|
||||||
@ -368,9 +368,9 @@ void CGameStateCampaign::replaceHeroesPlaceholders()
|
|||||||
heroToPlace->id = campaignHeroReplacement.heroPlaceholderId;
|
heroToPlace->id = campaignHeroReplacement.heroPlaceholderId;
|
||||||
if(heroPlaceholder->tempOwner.isValidPlayer())
|
if(heroPlaceholder->tempOwner.isValidPlayer())
|
||||||
heroToPlace->tempOwner = heroPlaceholder->tempOwner;
|
heroToPlace->tempOwner = heroPlaceholder->tempOwner;
|
||||||
heroToPlace->pos = heroPlaceholder->pos;
|
heroToPlace->setAnchorPos(heroPlaceholder->anchorPos());
|
||||||
heroToPlace->type = heroToPlace->getHeroType().toHeroType();
|
heroToPlace->setHeroType(heroToPlace->getHeroTypeID());
|
||||||
heroToPlace->appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, heroToPlace->type->heroClass->getIndex())->getTemplates().front();
|
heroToPlace->appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, heroToPlace->getHeroTypeID())->getTemplates().front();
|
||||||
|
|
||||||
gameState->map->removeBlockVisTiles(heroPlaceholder, true);
|
gameState->map->removeBlockVisTiles(heroPlaceholder, true);
|
||||||
gameState->map->objects[heroPlaceholder->id.getNum()] = nullptr;
|
gameState->map->objects[heroPlaceholder->id.getNum()] = nullptr;
|
||||||
@ -563,7 +563,7 @@ void CGameStateCampaign::initHeroes()
|
|||||||
{
|
{
|
||||||
for (auto & hero : heroes)
|
for (auto & hero : heroes)
|
||||||
{
|
{
|
||||||
if (hero->getHeroType().getNum() == chosenBonus->info1)
|
if (hero->getHeroTypeID().getNum() == chosenBonus->info1)
|
||||||
{
|
{
|
||||||
giveCampaignBonusToHero(hero);
|
giveCampaignBonusToHero(hero);
|
||||||
break;
|
break;
|
||||||
@ -655,14 +655,14 @@ void CGameStateCampaign::initTowns()
|
|||||||
if (!owner->human)
|
if (!owner->human)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (town->pos != pi.posOfMainTown)
|
if (town->anchorPos() != pi.posOfMainTown)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
BuildingID newBuilding;
|
BuildingID newBuilding;
|
||||||
if(gameState->scenarioOps->campState->formatVCMI())
|
if(gameState->scenarioOps->campState->formatVCMI())
|
||||||
newBuilding = BuildingID(chosenBonus->info1);
|
newBuilding = BuildingID(chosenBonus->info1);
|
||||||
else
|
else
|
||||||
newBuilding = CBuildingHandler::campToERMU(chosenBonus->info1, town->getFaction(), town->getBuildings());
|
newBuilding = CBuildingHandler::campToERMU(chosenBonus->info1, town->getFactionID(), town->getBuildings());
|
||||||
|
|
||||||
// Build granted building & all prerequisites - e.g. Mages Guild Lvl 3 should also give Mages Guild Lvl 1 & 2
|
// Build granted building & all prerequisites - e.g. Mages Guild Lvl 3 should also give Mages Guild Lvl 1 & 2
|
||||||
while(true)
|
while(true)
|
||||||
@ -675,7 +675,7 @@ void CGameStateCampaign::initTowns()
|
|||||||
|
|
||||||
town->addBuilding(newBuilding);
|
town->addBuilding(newBuilding);
|
||||||
|
|
||||||
auto building = town->town->buildings.at(newBuilding);
|
auto building = town->getTown()->buildings.at(newBuilding);
|
||||||
newBuilding = building->upgrade;
|
newBuilding = building->upgrade;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -381,7 +381,7 @@ float Statistic::getTownBuiltRatio(const PlayerState * ps)
|
|||||||
for(const auto & t : ps->getTowns())
|
for(const auto & t : ps->getTowns())
|
||||||
{
|
{
|
||||||
built += t->getBuildings().size();
|
built += t->getBuildings().size();
|
||||||
for(const auto & b : t->town->buildings)
|
for(const auto & b : t->getTown()->buildings)
|
||||||
if(!t->forbiddenBuildings.count(b.first))
|
if(!t->forbiddenBuildings.count(b.first))
|
||||||
total += 1;
|
total += 1;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ void InfoAboutHero::initFromHero(const CGHeroInstance *h, InfoAboutHero::EInfoLe
|
|||||||
|
|
||||||
initFromArmy(h, detailed);
|
initFromArmy(h, detailed);
|
||||||
|
|
||||||
hclass = h->type->heroClass;
|
hclass = h->getHeroClass();
|
||||||
name = h->getNameTranslated();
|
name = h->getNameTranslated();
|
||||||
portraitSource = h->getPortraitSource();
|
portraitSource = h->getPortraitSource();
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ std::map<HeroTypeID, CGHeroInstance*> TavernHeroesPool::unusedHeroesFromPool() c
|
|||||||
{
|
{
|
||||||
std::map<HeroTypeID, CGHeroInstance*> pool = heroesPool;
|
std::map<HeroTypeID, CGHeroInstance*> pool = heroesPool;
|
||||||
for(const auto & slot : currentTavern)
|
for(const auto & slot : currentTavern)
|
||||||
pool.erase(slot.hero->getHeroType());
|
pool.erase(slot.hero->getHeroTypeID());
|
||||||
|
|
||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ TavernSlotRole TavernHeroesPool::getSlotRole(HeroTypeID hero) const
|
|||||||
{
|
{
|
||||||
for (auto const & slot : currentTavern)
|
for (auto const & slot : currentTavern)
|
||||||
{
|
{
|
||||||
if (slot.hero->getHeroType() == hero)
|
if (slot.hero->getHeroTypeID() == hero)
|
||||||
return slot.role;
|
return slot.role;
|
||||||
}
|
}
|
||||||
return TavernSlotRole::NONE;
|
return TavernSlotRole::NONE;
|
||||||
@ -106,7 +106,7 @@ CGHeroInstance * TavernHeroesPool::takeHeroFromPool(HeroTypeID hero)
|
|||||||
heroesPool.erase(hero);
|
heroesPool.erase(hero);
|
||||||
|
|
||||||
vstd::erase_if(currentTavern, [&](const TavernSlot & entry){
|
vstd::erase_if(currentTavern, [&](const TavernSlot & entry){
|
||||||
return entry.hero->type->getId() == hero;
|
return entry.hero->getHeroTypeID() == hero;
|
||||||
});
|
});
|
||||||
|
|
||||||
assert(result);
|
assert(result);
|
||||||
@ -138,7 +138,7 @@ void TavernHeroesPool::onNewDay()
|
|||||||
|
|
||||||
void TavernHeroesPool::addHeroToPool(CGHeroInstance * hero)
|
void TavernHeroesPool::addHeroToPool(CGHeroInstance * hero)
|
||||||
{
|
{
|
||||||
heroesPool[hero->getHeroType()] = hero;
|
heroesPool[hero->getHeroTypeID()] = hero;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TavernHeroesPool::setAvailability(HeroTypeID hero, std::set<PlayerColor> mask)
|
void TavernHeroesPool::setAvailability(HeroTypeID hero, std::set<PlayerColor> mask)
|
||||||
|
@ -207,8 +207,13 @@ TObjectTypeHandler CObjectClassesHandler::loadSubObjectFromJson(const std::strin
|
|||||||
|
|
||||||
// Compatibility with 1.5 mods for 1.6. To be removed in 1.7
|
// Compatibility with 1.5 mods for 1.6. To be removed in 1.7
|
||||||
// Detect banks that use old format and load them using old bank hander
|
// Detect banks that use old format and load them using old bank hander
|
||||||
if (baseObject->id == Obj::CREATURE_BANK && entry.Struct().count("levels") && !entry.Struct().count("rewards"))
|
if (baseObject->id == Obj::CREATURE_BANK)
|
||||||
handler = "bank";
|
{
|
||||||
|
if (entry.Struct().count("levels") && !entry.Struct().count("rewards"))
|
||||||
|
handler = "bank";
|
||||||
|
else
|
||||||
|
handler = "configurable";
|
||||||
|
}
|
||||||
|
|
||||||
auto createdObject = handlerConstructors.at(handler)();
|
auto createdObject = handlerConstructors.at(handler)();
|
||||||
|
|
||||||
|
@ -96,7 +96,6 @@ bool CTownInstanceConstructor::objectFilter(const CGObjectInstance * object, std
|
|||||||
|
|
||||||
void CTownInstanceConstructor::initializeObject(CGTownInstance * obj) const
|
void CTownInstanceConstructor::initializeObject(CGTownInstance * obj) const
|
||||||
{
|
{
|
||||||
obj->town = faction->town;
|
|
||||||
obj->tempOwner = PlayerColor::NEUTRAL;
|
obj->tempOwner = PlayerColor::NEUTRAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +143,7 @@ bool CHeroInstanceConstructor::objectFilter(const CGObjectInstance * object, std
|
|||||||
|
|
||||||
auto heroTest = [&](const HeroTypeID & id)
|
auto heroTest = [&](const HeroTypeID & id)
|
||||||
{
|
{
|
||||||
return hero->type->getId() == id;
|
return hero->getHeroTypeID() == id;
|
||||||
};
|
};
|
||||||
|
|
||||||
if(filters.count(templ->stringID))
|
if(filters.count(templ->stringID))
|
||||||
@ -154,11 +153,6 @@ bool CHeroInstanceConstructor::objectFilter(const CGObjectInstance * object, std
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHeroInstanceConstructor::initializeObject(CGHeroInstance * obj) const
|
|
||||||
{
|
|
||||||
obj->type = nullptr; //FIXME: set to valid value. somehow.
|
|
||||||
}
|
|
||||||
|
|
||||||
void CHeroInstanceConstructor::randomizeObject(CGHeroInstance * object, vstd::RNG & rng) const
|
void CHeroInstanceConstructor::randomizeObject(CGHeroInstance * object, vstd::RNG & rng) const
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -81,7 +81,6 @@ public:
|
|||||||
const CHeroClass * heroClass = nullptr;
|
const CHeroClass * heroClass = nullptr;
|
||||||
std::map<std::string, LogicalExpression<HeroTypeID>> filters;
|
std::map<std::string, LogicalExpression<HeroTypeID>> filters;
|
||||||
|
|
||||||
void initializeObject(CGHeroInstance * object) const override;
|
|
||||||
void randomizeObject(CGHeroInstance * object, vstd::RNG & rng) const override;
|
void randomizeObject(CGHeroInstance * object, vstd::RNG & rng) const override;
|
||||||
void afterLoadFinalization() override;
|
void afterLoadFinalization() override;
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ void CArmedInstance::updateMoraleBonusFromArmy()
|
|||||||
const CStackInstance * inst = slot.second;
|
const CStackInstance * inst = slot.second;
|
||||||
const auto * creature = inst->getCreatureID().toEntity(VLC);
|
const auto * creature = inst->getCreatureID().toEntity(VLC);
|
||||||
|
|
||||||
factions.insert(creature->getFaction());
|
factions.insert(creature->getFactionID());
|
||||||
// Check for undead flag instead of faction (undead mummies are neutral)
|
// Check for undead flag instead of faction (undead mummies are neutral)
|
||||||
if (!hasUndead)
|
if (!hasUndead)
|
||||||
{
|
{
|
||||||
|
@ -33,7 +33,7 @@ std::string CGCreature::getHoverText(PlayerColor player) const
|
|||||||
if(stacks.empty())
|
if(stacks.empty())
|
||||||
{
|
{
|
||||||
//should not happen...
|
//should not happen...
|
||||||
logGlobal->error("Invalid stack at tile %s: subID=%d; id=%d", pos.toString(), getCreature(), id.getNum());
|
logGlobal->error("Invalid stack at tile %s: subID=%d; id=%d", anchorPos().toString(), getCreature(), id.getNum());
|
||||||
return "INVALID_STACK";
|
return "INVALID_STACK";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ std::string CGCreature::getHoverText(PlayerColor player) const
|
|||||||
else
|
else
|
||||||
ms.appendLocalString(EMetaText::ARRAY_TXT, quantityTextIndex);
|
ms.appendLocalString(EMetaText::ARRAY_TXT, quantityTextIndex);
|
||||||
ms.appendRawString(" ");
|
ms.appendRawString(" ");
|
||||||
ms.appendNamePlural(getCreature());
|
ms.appendNamePlural(getCreatureID());
|
||||||
|
|
||||||
return ms.toString();
|
return ms.toString();
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ std::string CGCreature::getHoverText(const CGHeroInstance * hero) const
|
|||||||
MetaString ms;
|
MetaString ms;
|
||||||
ms.appendNumber(stacks.begin()->second->count);
|
ms.appendNumber(stacks.begin()->second->count);
|
||||||
ms.appendRawString(" ");
|
ms.appendRawString(" ");
|
||||||
ms.appendName(getCreature(), stacks.begin()->second->count);
|
ms.appendName(getCreatureID(), stacks.begin()->second->count);
|
||||||
return ms.toString();
|
return ms.toString();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -69,11 +69,11 @@ std::string CGCreature::getHoverText(const CGHeroInstance * hero) const
|
|||||||
std::string CGCreature::getMonsterLevelText() const
|
std::string CGCreature::getMonsterLevelText() const
|
||||||
{
|
{
|
||||||
std::string monsterLevel = VLC->generaltexth->translate("vcmi.adventureMap.monsterLevel");
|
std::string monsterLevel = VLC->generaltexth->translate("vcmi.adventureMap.monsterLevel");
|
||||||
bool isRanged = VLC->creatures()->getById(getCreature())->getBonusBearer()->hasBonusOfType(BonusType::SHOOTER);
|
bool isRanged = getCreature()->getBonusBearer()->hasBonusOfType(BonusType::SHOOTER);
|
||||||
std::string attackTypeKey = isRanged ? "vcmi.adventureMap.monsterRangedType" : "vcmi.adventureMap.monsterMeleeType";
|
std::string attackTypeKey = isRanged ? "vcmi.adventureMap.monsterRangedType" : "vcmi.adventureMap.monsterMeleeType";
|
||||||
std::string attackType = VLC->generaltexth->translate(attackTypeKey);
|
std::string attackType = VLC->generaltexth->translate(attackTypeKey);
|
||||||
boost::replace_first(monsterLevel, "%TOWN", (*VLC->townh)[VLC->creatures()->getById(getCreature())->getFaction()]->getNameTranslated());
|
boost::replace_first(monsterLevel, "%TOWN", getCreature()->getFactionID().toEntity(VLC)->getNameTranslated());
|
||||||
boost::replace_first(monsterLevel, "%LEVEL", std::to_string(VLC->creatures()->getById(getCreature())->getLevel()));
|
boost::replace_first(monsterLevel, "%LEVEL", std::to_string(getCreature()->getLevel()));
|
||||||
boost::replace_first(monsterLevel, "%ATTACK_TYPE", attackType);
|
boost::replace_first(monsterLevel, "%ATTACK_TYPE", attackType);
|
||||||
return monsterLevel;
|
return monsterLevel;
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ std::string CGCreature::getPopupText(PlayerColor player) const
|
|||||||
std::vector<Component> CGCreature::getPopupComponents(PlayerColor player) const
|
std::vector<Component> CGCreature::getPopupComponents(PlayerColor player) const
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
Component(ComponentType::CREATURE, getCreature())
|
Component(ComponentType::CREATURE, getCreatureID())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
|
|||||||
BlockingDialog ynd(true,false);
|
BlockingDialog ynd(true,false);
|
||||||
ynd.player = h->tempOwner;
|
ynd.player = h->tempOwner;
|
||||||
ynd.text.appendLocalString(EMetaText::ADVOB_TXT, 86);
|
ynd.text.appendLocalString(EMetaText::ADVOB_TXT, 86);
|
||||||
ynd.text.replaceName(getCreature(), getStackCount(SlotID(0)));
|
ynd.text.replaceName(getCreatureID(), getStackCount(SlotID(0)));
|
||||||
cb->showBlockingDialog(this, &ynd);
|
cb->showBlockingDialog(this, &ynd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -197,7 +197,7 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
|
|||||||
std::string tmp = VLC->generaltexth->advobtxt[90];
|
std::string tmp = VLC->generaltexth->advobtxt[90];
|
||||||
boost::algorithm::replace_first(tmp, "%d", std::to_string(getStackCount(SlotID(0))));
|
boost::algorithm::replace_first(tmp, "%d", std::to_string(getStackCount(SlotID(0))));
|
||||||
boost::algorithm::replace_first(tmp, "%d", std::to_string(action));
|
boost::algorithm::replace_first(tmp, "%d", std::to_string(action));
|
||||||
boost::algorithm::replace_first(tmp,"%s",VLC->creatures()->getById(getCreature())->getNamePluralTranslated());
|
boost::algorithm::replace_first(tmp,"%s",getCreature()->getNamePluralTranslated());
|
||||||
ynd.text.appendRawString(tmp);
|
ynd.text.appendRawString(tmp);
|
||||||
cb->showBlockingDialog(this, &ynd);
|
cb->showBlockingDialog(this, &ynd);
|
||||||
break;
|
break;
|
||||||
@ -205,11 +205,16 @@ void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CreatureID CGCreature::getCreature() const
|
CreatureID CGCreature::getCreatureID() const
|
||||||
{
|
{
|
||||||
return CreatureID(getObjTypeIndex().getNum());
|
return CreatureID(getObjTypeIndex().getNum());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CCreature * CGCreature::getCreature() const
|
||||||
|
{
|
||||||
|
return getCreatureID().toCreature();
|
||||||
|
}
|
||||||
|
|
||||||
void CGCreature::pickRandomObject(vstd::RNG & rand)
|
void CGCreature::pickRandomObject(vstd::RNG & rand)
|
||||||
{
|
{
|
||||||
switch(ID.toEnum())
|
switch(ID.toEnum())
|
||||||
@ -279,7 +284,7 @@ void CGCreature::initObj(vstd::RNG & rand)
|
|||||||
|
|
||||||
stacks[SlotID(0)]->setType(getCreature());
|
stacks[SlotID(0)]->setType(getCreature());
|
||||||
TQuantity &amount = stacks[SlotID(0)]->count;
|
TQuantity &amount = stacks[SlotID(0)]->count;
|
||||||
const Creature * c = VLC->creatures()->getById(getCreature());
|
const Creature * c = getCreature();
|
||||||
if(amount == 0)
|
if(amount == 0)
|
||||||
{
|
{
|
||||||
amount = rand.nextInt(c->getAdvMapAmountMin(), c->getAdvMapAmountMax());
|
amount = rand.nextInt(c->getAdvMapAmountMin(), c->getAdvMapAmountMax());
|
||||||
@ -353,8 +358,8 @@ int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const
|
|||||||
|
|
||||||
for(const auto & elem : h->Slots())
|
for(const auto & elem : h->Slots())
|
||||||
{
|
{
|
||||||
bool isOurUpgrade = vstd::contains(getCreature().toCreature()->upgrades, elem.second->getCreatureID());
|
bool isOurUpgrade = vstd::contains(getCreature()->upgrades, elem.second->getCreatureID());
|
||||||
bool isOurDowngrade = vstd::contains(elem.second->type->upgrades, getCreature());
|
bool isOurDowngrade = vstd::contains(elem.second->type->upgrades, getCreatureID());
|
||||||
|
|
||||||
if(isOurUpgrade || isOurDowngrade)
|
if(isOurUpgrade || isOurDowngrade)
|
||||||
count += elem.second->count;
|
count += elem.second->count;
|
||||||
@ -380,7 +385,7 @@ int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const
|
|||||||
|
|
||||||
if(diplomacy * 2 + sympathy + 1 >= character)
|
if(diplomacy * 2 + sympathy + 1 >= character)
|
||||||
{
|
{
|
||||||
int32_t recruitCost = VLC->creatures()->getById(getCreature())->getRecruitCost(EGameResID::GOLD);
|
int32_t recruitCost = getCreature()->getRecruitCost(EGameResID::GOLD);
|
||||||
int32_t stackCount = getStackCount(SlotID(0));
|
int32_t stackCount = getStackCount(SlotID(0));
|
||||||
return recruitCost * stackCount; //join for gold
|
return recruitCost * stackCount; //join for gold
|
||||||
}
|
}
|
||||||
@ -493,7 +498,7 @@ void CGCreature::flee( const CGHeroInstance * h ) const
|
|||||||
BlockingDialog ynd(true,false);
|
BlockingDialog ynd(true,false);
|
||||||
ynd.player = h->tempOwner;
|
ynd.player = h->tempOwner;
|
||||||
ynd.text.appendLocalString(EMetaText::ADVOB_TXT,91);
|
ynd.text.appendLocalString(EMetaText::ADVOB_TXT,91);
|
||||||
ynd.text.replaceName(getCreature(), getStackCount(SlotID(0)));
|
ynd.text.replaceName(getCreatureID(), getStackCount(SlotID(0)));
|
||||||
cb->showBlockingDialog(this, &ynd);
|
cb->showBlockingDialog(this, &ynd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,7 +518,7 @@ void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult &
|
|||||||
{
|
{
|
||||||
//merge stacks into one
|
//merge stacks into one
|
||||||
TSlots::const_iterator i;
|
TSlots::const_iterator i;
|
||||||
const CCreature * cre = getCreature().toCreature();
|
const CCreature * cre = getCreature();
|
||||||
for(i = stacks.begin(); i != stacks.end(); i++)
|
for(i = stacks.begin(); i != stacks.end(); i++)
|
||||||
{
|
{
|
||||||
if(cre->isMyUpgrade(i->second->type))
|
if(cre->isMyUpgrade(i->second->type))
|
||||||
@ -562,7 +567,7 @@ bool CGCreature::containsUpgradedStack() const
|
|||||||
float c = 5325.181015f;
|
float c = 5325.181015f;
|
||||||
float d = 32788.727920f;
|
float d = 32788.727920f;
|
||||||
|
|
||||||
int val = static_cast<int>(std::floor(a * pos.x + b * pos.y + c * pos.z + d));
|
int val = static_cast<int>(std::floor(a * visitablePos().x + b * visitablePos().y + c * visitablePos().z + d));
|
||||||
return ((val % 32768) % 100) < 50;
|
return ((val % 32768) % 100) < 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,7 +596,7 @@ int CGCreature::getNumberOfStacks(const CGHeroInstance *hero) const
|
|||||||
ui32 c = 1943276003u;
|
ui32 c = 1943276003u;
|
||||||
ui32 d = 3174620878u;
|
ui32 d = 3174620878u;
|
||||||
|
|
||||||
ui32 R1 = a * static_cast<ui32>(pos.x) + b * static_cast<ui32>(pos.y) + c * static_cast<ui32>(pos.z) + d;
|
ui32 R1 = a * static_cast<ui32>(visitablePos().x) + b * static_cast<ui32>(visitablePos().y) + c * static_cast<ui32>(visitablePos().z) + d;
|
||||||
ui32 R2 = (R1 >> 16) & 0x7fff;
|
ui32 R2 = (R1 >> 16) & 0x7fff;
|
||||||
|
|
||||||
int R4 = R2 % 100 + 1;
|
int R4 = R2 % 100 + 1;
|
||||||
|
@ -49,7 +49,8 @@ public:
|
|||||||
void newTurn(vstd::RNG & rand) const override;
|
void newTurn(vstd::RNG & rand) const override;
|
||||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
|
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
|
||||||
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
|
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
|
||||||
CreatureID getCreature() const;
|
CreatureID getCreatureID() const;
|
||||||
|
const CCreature * getCreature() const;
|
||||||
|
|
||||||
//stack formation depends on position,
|
//stack formation depends on position,
|
||||||
bool containsUpgradedStack() const;
|
bool containsUpgradedStack() const;
|
||||||
|
@ -93,7 +93,7 @@ FactionID CGDwelling::randomizeFaction(vstd::RNG & rand)
|
|||||||
|
|
||||||
assert(linkedTown->ID == Obj::TOWN);
|
assert(linkedTown->ID == Obj::TOWN);
|
||||||
if(linkedTown->ID==Obj::TOWN)
|
if(linkedTown->ID==Obj::TOWN)
|
||||||
return linkedTown->getFaction();
|
return linkedTown->getFactionID();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!randomizationInfo->allowedFactions.empty())
|
if(!randomizationInfo->allowedFactions.empty())
|
||||||
|
@ -116,9 +116,9 @@ ui32 CGHeroInstance::getTileMovementCost(const TerrainTile & dest, const Terrain
|
|||||||
return static_cast<ui32>(ret);
|
return static_cast<ui32>(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
FactionID CGHeroInstance::getFaction() const
|
FactionID CGHeroInstance::getFactionID() const
|
||||||
{
|
{
|
||||||
return FactionID(type->heroClass->faction);
|
return getHeroClass()->faction;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IBonusBearer* CGHeroInstance::getBonusBearer() const
|
const IBonusBearer* CGHeroInstance::getBonusBearer() const
|
||||||
@ -229,10 +229,10 @@ bool CGHeroInstance::canLearnSkill(const SecondarySkill & which) const
|
|||||||
if (getSecSkillLevel(which) > 0)
|
if (getSecSkillLevel(which) > 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (type->heroClass->secSkillProbability.count(which) == 0)
|
if (getHeroClass()->secSkillProbability.count(which) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (type->heroClass->secSkillProbability.at(which) == 0)
|
if (getHeroClass()->secSkillProbability.at(which) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -282,7 +282,6 @@ int CGHeroInstance::movementPointsLimitCached(bool onLand, const TurnInfo * ti)
|
|||||||
|
|
||||||
CGHeroInstance::CGHeroInstance(IGameCallback * cb)
|
CGHeroInstance::CGHeroInstance(IGameCallback * cb)
|
||||||
: CArmedInstance(cb),
|
: CArmedInstance(cb),
|
||||||
type(nullptr),
|
|
||||||
tacticFormationEnabled(false),
|
tacticFormationEnabled(false),
|
||||||
inTownGarrison(false),
|
inTownGarrison(false),
|
||||||
moveDir(4),
|
moveDir(4),
|
||||||
@ -303,14 +302,30 @@ PlayerColor CGHeroInstance::getOwner() const
|
|||||||
return tempOwner;
|
return tempOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
HeroTypeID CGHeroInstance::getHeroType() const
|
const CHeroClass * CGHeroInstance::getHeroClass() const
|
||||||
{
|
{
|
||||||
|
return getHeroType()->heroClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
HeroClassID CGHeroInstance::getHeroClassID() const
|
||||||
|
{
|
||||||
|
return getHeroType()->heroClass->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
const CHero * CGHeroInstance::getHeroType() const
|
||||||
|
{
|
||||||
|
return getHeroTypeID().toHeroType();
|
||||||
|
}
|
||||||
|
|
||||||
|
HeroTypeID CGHeroInstance::getHeroTypeID() const
|
||||||
|
{
|
||||||
|
if (ID == Obj::RANDOM_HERO)
|
||||||
|
return HeroTypeID::NONE;
|
||||||
return HeroTypeID(getObjTypeIndex().getNum());
|
return HeroTypeID(getObjTypeIndex().getNum());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGHeroInstance::setHeroType(HeroTypeID heroType)
|
void CGHeroInstance::setHeroType(HeroTypeID heroType)
|
||||||
{
|
{
|
||||||
assert(type == nullptr);
|
|
||||||
subID = heroType;
|
subID = heroType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,16 +338,14 @@ void CGHeroInstance::initHero(vstd::RNG & rand, const HeroTypeID & SUBID)
|
|||||||
void CGHeroInstance::initHero(vstd::RNG & rand)
|
void CGHeroInstance::initHero(vstd::RNG & rand)
|
||||||
{
|
{
|
||||||
assert(validTypes(true));
|
assert(validTypes(true));
|
||||||
if(!type)
|
|
||||||
type = getHeroType().toHeroType();
|
|
||||||
|
|
||||||
if (ID == Obj::HERO)
|
if (ID == Obj::HERO)
|
||||||
appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, type->heroClass->getIndex())->getTemplates().front();
|
appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, getHeroClass()->getIndex())->getTemplates().front();
|
||||||
|
|
||||||
if(!vstd::contains(spells, SpellID::PRESET))
|
if(!vstd::contains(spells, SpellID::PRESET))
|
||||||
{
|
{
|
||||||
// hero starts with default spells
|
// hero starts with default spells
|
||||||
for(const auto & spellID : type->spells)
|
for(const auto & spellID : getHeroType()->spells)
|
||||||
spells.insert(spellID);
|
spells.insert(spellID);
|
||||||
}
|
}
|
||||||
else //remove placeholder
|
else //remove placeholder
|
||||||
@ -341,7 +354,7 @@ void CGHeroInstance::initHero(vstd::RNG & rand)
|
|||||||
if(!vstd::contains(spells, SpellID::SPELLBOOK_PRESET))
|
if(!vstd::contains(spells, SpellID::SPELLBOOK_PRESET))
|
||||||
{
|
{
|
||||||
// hero starts with default spellbook presence status
|
// hero starts with default spellbook presence status
|
||||||
if(!getArt(ArtifactPosition::SPELLBOOK) && type->haveSpellBook)
|
if(!getArt(ArtifactPosition::SPELLBOOK) && getHeroType()->haveSpellBook)
|
||||||
{
|
{
|
||||||
auto artifact = ArtifactUtils::createArtifact(ArtifactID::SPELLBOOK);
|
auto artifact = ArtifactUtils::createArtifact(ArtifactID::SPELLBOOK);
|
||||||
putArtifact(ArtifactPosition::SPELLBOOK, artifact);
|
putArtifact(ArtifactPosition::SPELLBOOK, artifact);
|
||||||
@ -360,14 +373,14 @@ void CGHeroInstance::initHero(vstd::RNG & rand)
|
|||||||
{
|
{
|
||||||
for(int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
|
for(int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
|
||||||
{
|
{
|
||||||
pushPrimSkill(static_cast<PrimarySkill>(g), type->heroClass->primarySkillInitial[g]);
|
pushPrimSkill(static_cast<PrimarySkill>(g), getHeroClass()->primarySkillInitial[g]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(secSkills.size() == 1 && secSkills[0] == std::pair<SecondarySkill,ui8>(SecondarySkill::NONE, -1)) //set secondary skills to default
|
if(secSkills.size() == 1 && secSkills[0] == std::pair<SecondarySkill,ui8>(SecondarySkill::NONE, -1)) //set secondary skills to default
|
||||||
secSkills = type->secSkillsInit;
|
secSkills = getHeroType()->secSkillsInit;
|
||||||
|
|
||||||
if (gender == EHeroGender::DEFAULT)
|
if (gender == EHeroGender::DEFAULT)
|
||||||
gender = type->gender;
|
gender = getHeroType()->gender;
|
||||||
|
|
||||||
setFormation(EArmyFormation::LOOSE);
|
setFormation(EArmyFormation::LOOSE);
|
||||||
if (!stacksCount()) //standard army//initial army
|
if (!stacksCount()) //standard army//initial army
|
||||||
@ -403,9 +416,9 @@ void CGHeroInstance::initHero(vstd::RNG & rand)
|
|||||||
addNewBonus(bonus);
|
addNewBonus(bonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cb->getSettings().getBoolean(EGameSettings::MODULE_COMMANDERS) && !commander && type->heroClass->commander.hasValue())
|
if (cb->getSettings().getBoolean(EGameSettings::MODULE_COMMANDERS) && !commander && getHeroClass()->commander.hasValue())
|
||||||
{
|
{
|
||||||
commander = new CCommanderInstance(type->heroClass->commander);
|
commander = new CCommanderInstance(getHeroClass()->commander);
|
||||||
commander->setArmyObj (castToArmyObj()); //TODO: separate function for setting commanders
|
commander->setArmyObj (castToArmyObj()); //TODO: separate function for setting commanders
|
||||||
commander->giveStackExp (exp); //after our exp is set
|
commander->giveStackExp (exp); //after our exp is set
|
||||||
}
|
}
|
||||||
@ -413,7 +426,7 @@ void CGHeroInstance::initHero(vstd::RNG & rand)
|
|||||||
skillsInfo = SecondarySkillsInfo();
|
skillsInfo = SecondarySkillsInfo();
|
||||||
|
|
||||||
//copy active (probably growing) bonuses from hero prototype to hero object
|
//copy active (probably growing) bonuses from hero prototype to hero object
|
||||||
for(const std::shared_ptr<Bonus> & b : type->specialty)
|
for(const std::shared_ptr<Bonus> & b : getHeroType()->specialty)
|
||||||
addNewBonus(b);
|
addNewBonus(b);
|
||||||
|
|
||||||
//initialize bonuses
|
//initialize bonuses
|
||||||
@ -433,14 +446,14 @@ void CGHeroInstance::initArmy(vstd::RNG & rand, IArmyDescriptor * dst)
|
|||||||
auto stacksCountChances = cb->getSettings().getVector(EGameSettings::HEROES_STARTING_STACKS_CHANCES);
|
auto stacksCountChances = cb->getSettings().getVector(EGameSettings::HEROES_STARTING_STACKS_CHANCES);
|
||||||
int stacksCountInitRandomNumber = rand.nextInt(1, 100);
|
int stacksCountInitRandomNumber = rand.nextInt(1, 100);
|
||||||
|
|
||||||
size_t maxStacksCount = std::min(stacksCountChances.size(), type->initialArmy.size());
|
size_t maxStacksCount = std::min(stacksCountChances.size(), getHeroType()->initialArmy.size());
|
||||||
|
|
||||||
for(int stackNo=0; stackNo < maxStacksCount; stackNo++)
|
for(int stackNo=0; stackNo < maxStacksCount; stackNo++)
|
||||||
{
|
{
|
||||||
if (stacksCountInitRandomNumber > stacksCountChances[stackNo])
|
if (stacksCountInitRandomNumber > stacksCountChances[stackNo])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto & stack = type->initialArmy[stackNo];
|
auto & stack = getHeroType()->initialArmy[stackNo];
|
||||||
|
|
||||||
int count = rand.nextInt(stack.minAmount, stack.maxAmount);
|
int count = rand.nextInt(stack.minAmount, stack.maxAmount);
|
||||||
|
|
||||||
@ -588,11 +601,11 @@ std::string CGHeroInstance::getMovementPointsTextIfOwner(PlayerColor player) con
|
|||||||
|
|
||||||
ui8 CGHeroInstance::maxlevelsToMagicSchool() const
|
ui8 CGHeroInstance::maxlevelsToMagicSchool() const
|
||||||
{
|
{
|
||||||
return type->heroClass->isMagicHero() ? 3 : 4;
|
return getHeroClass()->isMagicHero() ? 3 : 4;
|
||||||
}
|
}
|
||||||
ui8 CGHeroInstance::maxlevelsToWisdom() const
|
ui8 CGHeroInstance::maxlevelsToWisdom() const
|
||||||
{
|
{
|
||||||
return type->heroClass->isMagicHero() ? 3 : 6;
|
return getHeroClass()->isMagicHero() ? 3 : 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGHeroInstance::SecondarySkillsInfo::SecondarySkillsInfo():
|
CGHeroInstance::SecondarySkillsInfo::SecondarySkillsInfo():
|
||||||
@ -617,11 +630,8 @@ void CGHeroInstance::pickRandomObject(vstd::RNG & rand)
|
|||||||
{
|
{
|
||||||
ID = Obj::HERO;
|
ID = Obj::HERO;
|
||||||
subID = cb->gameState()->pickNextHeroType(getOwner());
|
subID = cb->gameState()->pickNextHeroType(getOwner());
|
||||||
type = getHeroType().toHeroType();
|
randomizeArmy(getHeroClass()->faction);
|
||||||
randomizeArmy(type->heroClass->faction);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
type = getHeroType().toHeroType();
|
|
||||||
|
|
||||||
auto oldSubID = subID;
|
auto oldSubID = subID;
|
||||||
|
|
||||||
@ -629,7 +639,7 @@ void CGHeroInstance::pickRandomObject(vstd::RNG & rand)
|
|||||||
// after setType subID used to store unique hero identify id. Check issue 2277 for details
|
// after setType subID used to store unique hero identify id. Check issue 2277 for details
|
||||||
// exclude prisons which should use appearance as set in map, via map editor or RMG
|
// exclude prisons which should use appearance as set in map, via map editor or RMG
|
||||||
if (ID != Obj::PRISON)
|
if (ID != Obj::PRISON)
|
||||||
setType(ID, type->heroClass->getIndex());
|
setType(ID, getHeroClass()->getIndex());
|
||||||
|
|
||||||
this->subID = oldSubID;
|
this->subID = oldSubID;
|
||||||
}
|
}
|
||||||
@ -1064,7 +1074,7 @@ si32 CGHeroInstance::getManaNewTurn() const
|
|||||||
|
|
||||||
BoatId CGHeroInstance::getBoatType() const
|
BoatId CGHeroInstance::getBoatType() const
|
||||||
{
|
{
|
||||||
return BoatId(VLC->townh->getById(type->heroClass->faction)->getBoatType());
|
return BoatId(VLC->townh->getById(getHeroClass()->faction)->getBoatType());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGHeroInstance::getOutOffsets(std::vector<int3> &offsets) const
|
void CGHeroInstance::getOutOffsets(std::vector<int3> &offsets) const
|
||||||
@ -1103,7 +1113,7 @@ void CGHeroInstance::pushPrimSkill( PrimarySkill which, int val )
|
|||||||
|
|
||||||
EAlignment CGHeroInstance::getAlignment() const
|
EAlignment CGHeroInstance::getAlignment() const
|
||||||
{
|
{
|
||||||
return type->heroClass->getAlignment();
|
return getHeroClass()->getAlignment();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGHeroInstance::initExp(vstd::RNG & rand)
|
void CGHeroInstance::initExp(vstd::RNG & rand)
|
||||||
@ -1127,12 +1137,12 @@ HeroTypeID CGHeroInstance::getPortraitSource() const
|
|||||||
if (customPortraitSource.isValid())
|
if (customPortraitSource.isValid())
|
||||||
return customPortraitSource;
|
return customPortraitSource;
|
||||||
else
|
else
|
||||||
return getHeroType();
|
return getHeroTypeID();
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t CGHeroInstance::getIconIndex() const
|
int32_t CGHeroInstance::getIconIndex() const
|
||||||
{
|
{
|
||||||
return VLC->heroTypes()->getById(getPortraitSource())->getIconIndex();
|
return getPortraitSource().toEntity(VLC)->getIconIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CGHeroInstance::getNameTranslated() const
|
std::string CGHeroInstance::getNameTranslated() const
|
||||||
@ -1149,15 +1159,15 @@ std::string CGHeroInstance::getClassNameTextID() const
|
|||||||
{
|
{
|
||||||
if (isCampaignGem())
|
if (isCampaignGem())
|
||||||
return "core.genrltxt.735";
|
return "core.genrltxt.735";
|
||||||
return type->heroClass->getNameTextID();
|
return getHeroClass()->getNameTextID();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CGHeroInstance::getNameTextID() const
|
std::string CGHeroInstance::getNameTextID() const
|
||||||
{
|
{
|
||||||
if (!nameCustomTextId.empty())
|
if (!nameCustomTextId.empty())
|
||||||
return nameCustomTextId;
|
return nameCustomTextId;
|
||||||
if (type)
|
if (getHeroTypeID().hasValue())
|
||||||
return type->getNameTextID();
|
return getHeroType()->getNameTextID();
|
||||||
|
|
||||||
// FIXME: called by logging from some specialties (mods?) before type is set on deserialization
|
// FIXME: called by logging from some specialties (mods?) before type is set on deserialization
|
||||||
// assert(0);
|
// assert(0);
|
||||||
@ -1173,8 +1183,8 @@ std::string CGHeroInstance::getBiographyTextID() const
|
|||||||
{
|
{
|
||||||
if (!biographyCustomTextId.empty())
|
if (!biographyCustomTextId.empty())
|
||||||
return biographyCustomTextId;
|
return biographyCustomTextId;
|
||||||
if (type)
|
if (getHeroTypeID().hasValue())
|
||||||
return type->getBiographyTextID();
|
return getHeroType()->getBiographyTextID();
|
||||||
|
|
||||||
return ""; //for random hero
|
return ""; //for random hero
|
||||||
}
|
}
|
||||||
@ -1372,11 +1382,11 @@ std::vector<SecondarySkill> CGHeroInstance::getLevelUpProposedSecondarySkills(vs
|
|||||||
SecondarySkill selection;
|
SecondarySkill selection;
|
||||||
|
|
||||||
if (selectWisdom)
|
if (selectWisdom)
|
||||||
selection = type->heroClass->chooseSecSkill(intersect(options, wisdomList), rand);
|
selection = getHeroClass()->chooseSecSkill(intersect(options, wisdomList), rand);
|
||||||
else if (selectSchool)
|
else if (selectSchool)
|
||||||
selection = type->heroClass->chooseSecSkill(intersect(options, schoolList), rand);
|
selection = getHeroClass()->chooseSecSkill(intersect(options, schoolList), rand);
|
||||||
else
|
else
|
||||||
selection = type->heroClass->chooseSecSkill(options, rand);
|
selection = getHeroClass()->chooseSecSkill(options, rand);
|
||||||
|
|
||||||
skills.push_back(selection);
|
skills.push_back(selection);
|
||||||
options.erase(selection);
|
options.erase(selection);
|
||||||
@ -1407,7 +1417,7 @@ PrimarySkill CGHeroInstance::nextPrimarySkill(vstd::RNG & rand) const
|
|||||||
{
|
{
|
||||||
assert(gainsLevel());
|
assert(gainsLevel());
|
||||||
const auto isLowLevelHero = level < GameConstants::HERO_HIGH_LEVEL;
|
const auto isLowLevelHero = level < GameConstants::HERO_HIGH_LEVEL;
|
||||||
const auto & skillChances = isLowLevelHero ? type->heroClass->primarySkillLowLevel : type->heroClass->primarySkillHighLevel;
|
const auto & skillChances = isLowLevelHero ? getHeroClass()->primarySkillLowLevel : getHeroClass()->primarySkillHighLevel;
|
||||||
|
|
||||||
if (isCampaignYog())
|
if (isCampaignYog())
|
||||||
{
|
{
|
||||||
@ -1537,35 +1547,25 @@ bool CGHeroInstance::hasVisions(const CGObjectInstance * target, BonusSubtypeID
|
|||||||
if (visionsMultiplier > 0)
|
if (visionsMultiplier > 0)
|
||||||
vstd::amax(visionsRange, 3); //minimum range is 3 tiles, but only if VISIONS bonus present
|
vstd::amax(visionsRange, 3); //minimum range is 3 tiles, but only if VISIONS bonus present
|
||||||
|
|
||||||
const int distance = static_cast<int>(target->pos.dist2d(visitablePos()));
|
const int distance = static_cast<int>(target->anchorPos().dist2d(visitablePos()));
|
||||||
|
|
||||||
//logGlobal->debug(boost::str(boost::format("Visions: dist %d, mult %d, range %d") % distance % visionsMultiplier % visionsRange));
|
//logGlobal->debug(boost::str(boost::format("Visions: dist %d, mult %d, range %d") % distance % visionsMultiplier % visionsRange));
|
||||||
|
|
||||||
return (distance < visionsRange) && (target->pos.z == pos.z);
|
return (distance < visionsRange) && (target->anchorPos().z == anchorPos().z);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CGHeroInstance::getHeroTypeName() const
|
std::string CGHeroInstance::getHeroTypeName() const
|
||||||
{
|
{
|
||||||
if(ID == Obj::HERO || ID == Obj::PRISON)
|
if(ID == Obj::HERO || ID == Obj::PRISON)
|
||||||
{
|
return getHeroType()->getJsonKey();
|
||||||
if(type)
|
|
||||||
{
|
|
||||||
return type->getJsonKey();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return getHeroType().toEntity(VLC)->getJsonKey();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGHeroInstance::afterAddToMap(CMap * map)
|
void CGHeroInstance::afterAddToMap(CMap * map)
|
||||||
{
|
{
|
||||||
if(ID != Obj::PRISON)
|
if(ID != Obj::PRISON)
|
||||||
{
|
|
||||||
map->heroesOnMap.emplace_back(this);
|
map->heroesOnMap.emplace_back(this);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void CGHeroInstance::afterRemoveFromMap(CMap* map)
|
void CGHeroInstance::afterRemoveFromMap(CMap* map)
|
||||||
{
|
{
|
||||||
@ -1752,8 +1752,7 @@ void CGHeroInstance::serializeJsonOptions(JsonSerializeFormat & handler)
|
|||||||
if(!appearance)
|
if(!appearance)
|
||||||
{
|
{
|
||||||
// crossoverDeserialize
|
// crossoverDeserialize
|
||||||
type = getHeroType().toHeroType();
|
appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, getHeroClassID())->getTemplates().front();
|
||||||
appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, type->heroClass->getIndex())->getTemplates().front();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1840,7 +1839,7 @@ bool CGHeroInstance::isCampaignYog() const
|
|||||||
if (!boost::starts_with(campaign, "DATA/YOG")) // "Birth of a Barbarian"
|
if (!boost::starts_with(campaign, "DATA/YOG")) // "Birth of a Barbarian"
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (getHeroType() != HeroTypeID::SOLMYR) // Yog (based on Solmyr)
|
if (getHeroTypeID() != HeroTypeID::SOLMYR) // Yog (based on Solmyr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1858,7 +1857,7 @@ bool CGHeroInstance::isCampaignGem() const
|
|||||||
if (!boost::starts_with(campaign, "DATA/GEM") && !boost::starts_with(campaign, "DATA/FINAL")) // "New Beginning" and "Unholy Alliance"
|
if (!boost::starts_with(campaign, "DATA/GEM") && !boost::starts_with(campaign, "DATA/FINAL")) // "New Beginning" and "Unholy Alliance"
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (getHeroType() != HeroTypeID::GEM) // Yog (based on Solmyr)
|
if (getHeroTypeID() != HeroTypeID::GEM) // Yog (based on Solmyr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -72,7 +72,6 @@ public:
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
const CHero * type;
|
|
||||||
TExpType exp; //experience points
|
TExpType exp; //experience points
|
||||||
ui32 level; //current level of hero
|
ui32 level; //current level of hero
|
||||||
|
|
||||||
@ -171,7 +170,7 @@ public:
|
|||||||
const IOwnableObject * asOwnable() const final;
|
const IOwnableObject * asOwnable() const final;
|
||||||
|
|
||||||
//INativeTerrainProvider
|
//INativeTerrainProvider
|
||||||
FactionID getFaction() const override;
|
FactionID getFactionID() const override;
|
||||||
TerrainId getNativeTerrain() const override;
|
TerrainId getNativeTerrain() const override;
|
||||||
int getLowestCreatureSpeed() const;
|
int getLowestCreatureSpeed() const;
|
||||||
si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day
|
si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day
|
||||||
@ -237,7 +236,11 @@ public:
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
HeroTypeID getHeroType() const;
|
const CHeroClass * getHeroClass() const;
|
||||||
|
HeroClassID getHeroClassID() const;
|
||||||
|
|
||||||
|
const CHero * getHeroType() const;
|
||||||
|
HeroTypeID getHeroTypeID() const;
|
||||||
void setHeroType(HeroTypeID type);
|
void setHeroType(HeroTypeID type);
|
||||||
|
|
||||||
void initHero(vstd::RNG & rand);
|
void initHero(vstd::RNG & rand);
|
||||||
@ -354,7 +357,11 @@ public:
|
|||||||
h & skillsInfo;
|
h & skillsInfo;
|
||||||
h & visitedTown;
|
h & visitedTown;
|
||||||
h & boat;
|
h & boat;
|
||||||
h & type;
|
if (h.version < Handler::Version::REMOVE_TOWN_PTR)
|
||||||
|
{
|
||||||
|
CHero * type = nullptr;
|
||||||
|
h & type;
|
||||||
|
}
|
||||||
h & commander;
|
h & commander;
|
||||||
h & visitedObjects;
|
h & visitedObjects;
|
||||||
BONUS_TREE_DESERIALIZATION_FIX
|
BONUS_TREE_DESERIALIZATION_FIX
|
||||||
|
@ -54,14 +54,14 @@ MapObjectSubID CGObjectInstance::getObjTypeIndex() const
|
|||||||
return subID;
|
return subID;
|
||||||
}
|
}
|
||||||
|
|
||||||
int3 CGObjectInstance::getPosition() const
|
int3 CGObjectInstance::anchorPos() const
|
||||||
{
|
{
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
int3 CGObjectInstance::getTopVisiblePos() const
|
int3 CGObjectInstance::getTopVisiblePos() const
|
||||||
{
|
{
|
||||||
return pos - appearance->getTopVisibleOffset();
|
return anchorPos() - appearance->getTopVisibleOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGObjectInstance::setOwner(const PlayerColor & ow)
|
void CGObjectInstance::setOwner(const PlayerColor & ow)
|
||||||
@ -69,6 +69,11 @@ void CGObjectInstance::setOwner(const PlayerColor & ow)
|
|||||||
tempOwner = ow;
|
tempOwner = ow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGObjectInstance::setAnchorPos(int3 newPos)
|
||||||
|
{
|
||||||
|
pos = newPos;
|
||||||
|
}
|
||||||
|
|
||||||
int CGObjectInstance::getWidth() const
|
int CGObjectInstance::getWidth() const
|
||||||
{
|
{
|
||||||
return appearance->getWidth();
|
return appearance->getWidth();
|
||||||
@ -79,32 +84,19 @@ int CGObjectInstance::getHeight() const
|
|||||||
return appearance->getHeight();
|
return appearance->getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGObjectInstance::visitableAt(int x, int y) const
|
|
||||||
{
|
|
||||||
return appearance->isVisitableAt(pos.x - x, pos.y - y);
|
|
||||||
}
|
|
||||||
bool CGObjectInstance::blockingAt(int x, int y) const
|
|
||||||
{
|
|
||||||
return appearance->isBlockedAt(pos.x - x, pos.y - y);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CGObjectInstance::coveringAt(int x, int y) const
|
|
||||||
{
|
|
||||||
return appearance->isVisibleAt(pos.x - x, pos.y - y);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CGObjectInstance::visitableAt(const int3 & testPos) const
|
bool CGObjectInstance::visitableAt(const int3 & testPos) const
|
||||||
{
|
{
|
||||||
return pos.z == testPos.z && appearance->isVisitableAt(pos.x - testPos.x, pos.y - testPos.y);
|
return anchorPos().z == testPos.z && appearance->isVisitableAt(anchorPos().x - testPos.x, anchorPos().y - testPos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGObjectInstance::blockingAt(const int3 & testPos) const
|
bool CGObjectInstance::blockingAt(const int3 & testPos) const
|
||||||
{
|
{
|
||||||
return pos.z == testPos.z && appearance->isBlockedAt(pos.x - testPos.x, pos.y - testPos.y);
|
return anchorPos().z == testPos.z && appearance->isBlockedAt(anchorPos().x - testPos.x, anchorPos().y - testPos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGObjectInstance::coveringAt(const int3 & testPos) const
|
bool CGObjectInstance::coveringAt(const int3 & testPos) const
|
||||||
{
|
{
|
||||||
return pos.z == testPos.z && appearance->isVisibleAt(pos.x - testPos.x, pos.y - testPos.y);
|
return anchorPos().z == testPos.z && appearance->isVisibleAt(anchorPos().x - testPos.x, anchorPos().y - testPos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<int3> CGObjectInstance::getBlockedPos() const
|
std::set<int3> CGObjectInstance::getBlockedPos() const
|
||||||
@ -115,7 +107,7 @@ std::set<int3> CGObjectInstance::getBlockedPos() const
|
|||||||
for(int h=0; h<getHeight(); ++h)
|
for(int h=0; h<getHeight(); ++h)
|
||||||
{
|
{
|
||||||
if(appearance->isBlockedAt(w, h))
|
if(appearance->isBlockedAt(w, h))
|
||||||
ret.insert(int3(pos.x - w, pos.y - h, pos.z));
|
ret.insert(int3(anchorPos().x - w, anchorPos().y - h, anchorPos().z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -215,6 +207,8 @@ int CGObjectInstance::getSightRadius() const
|
|||||||
|
|
||||||
int3 CGObjectInstance::getVisitableOffset() const
|
int3 CGObjectInstance::getVisitableOffset() const
|
||||||
{
|
{
|
||||||
|
if (!isVisitable())
|
||||||
|
throw std::runtime_error("Attempt to access visitable offset of a non-visitable object!");
|
||||||
return appearance->getVisitableOffset();
|
return appearance->getVisitableOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,6 +307,9 @@ void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const
|
|||||||
|
|
||||||
int3 CGObjectInstance::visitablePos() const
|
int3 CGObjectInstance::visitablePos() const
|
||||||
{
|
{
|
||||||
|
if (!isVisitable())
|
||||||
|
throw std::runtime_error("Attempt to access visitable position on a non-visitable object!");
|
||||||
|
|
||||||
return pos - getVisitableOffset();
|
return pos - getVisitableOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,8 +28,6 @@ using TObjectTypeHandler = std::shared_ptr<AObjectTypeHandler>;
|
|||||||
class DLL_LINKAGE CGObjectInstance : public IObjectInterface
|
class DLL_LINKAGE CGObjectInstance : public IObjectInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Position of bottom-right corner of object on map
|
|
||||||
int3 pos;
|
|
||||||
/// Type of object, e.g. town, hero, creature.
|
/// Type of object, e.g. town, hero, creature.
|
||||||
MapObjectID ID;
|
MapObjectID ID;
|
||||||
/// Subtype of object, depends on type
|
/// Subtype of object, depends on type
|
||||||
@ -41,6 +39,9 @@ public:
|
|||||||
/// Defines appearance of object on map (animation, blocked tiles, blit order, etc)
|
/// Defines appearance of object on map (animation, blocked tiles, blit order, etc)
|
||||||
std::shared_ptr<const ObjectTemplate> appearance;
|
std::shared_ptr<const ObjectTemplate> appearance;
|
||||||
|
|
||||||
|
/// Position of bottom-right corner of object on map
|
||||||
|
int3 pos;
|
||||||
|
|
||||||
std::string instanceName;
|
std::string instanceName;
|
||||||
std::string typeName;
|
std::string typeName;
|
||||||
std::string subTypeName;
|
std::string subTypeName;
|
||||||
@ -62,21 +63,19 @@ public:
|
|||||||
return this->tempOwner;
|
return this->tempOwner;
|
||||||
}
|
}
|
||||||
void setOwner(const PlayerColor & ow);
|
void setOwner(const PlayerColor & ow);
|
||||||
|
void setAnchorPos(int3 pos);
|
||||||
|
|
||||||
/** APPEARANCE ACCESSORS **/
|
/** APPEARANCE ACCESSORS **/
|
||||||
|
|
||||||
int getWidth() const; //returns width of object graphic in tiles
|
int getWidth() const; //returns width of object graphic in tiles
|
||||||
int getHeight() const; //returns height of object graphic in tiles
|
int getHeight() const; //returns height of object graphic in tiles
|
||||||
int3 visitablePos() const override;
|
int3 visitablePos() const override;
|
||||||
int3 getPosition() const override;
|
int3 anchorPos() const override;
|
||||||
int3 getTopVisiblePos() const;
|
int3 getTopVisiblePos() const;
|
||||||
bool visitableAt(int x, int y) const; //returns true if object is visitable at location (x, y) (h3m pos)
|
|
||||||
bool blockingAt(int x, int y) const; //returns true if object is blocking location (x, y) (h3m pos)
|
|
||||||
bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos)
|
|
||||||
|
|
||||||
bool visitableAt(const int3 & pos) const; //returns true if object is visitable at location (x, y) (h3m pos)
|
bool visitableAt(const int3 & pos) const; //returns true if object is visitable at location
|
||||||
bool blockingAt (const int3 & pos) const; //returns true if object is blocking location (x, y) (h3m pos)
|
bool blockingAt (const int3 & pos) const; //returns true if object is blocking location
|
||||||
bool coveringAt (const int3 & pos) const; //returns true if object covers with picture location (x, y) (h3m pos)
|
bool coveringAt (const int3 & pos) const; //returns true if object covers with picture location
|
||||||
|
|
||||||
std::set<int3> getBlockedPos() const; //returns set of positions blocked by this object
|
std::set<int3> getBlockedPos() const; //returns set of positions blocked by this object
|
||||||
const std::set<int3> & getBlockedOffsets() const; //returns set of relative positions blocked by this object
|
const std::set<int3> & getBlockedOffsets() const; //returns set of relative positions blocked by this object
|
||||||
|
@ -45,7 +45,7 @@ int CGTownInstance::getSightRadius() const //returns sight distance
|
|||||||
|
|
||||||
for(const auto & bid : builtBuildings)
|
for(const auto & bid : builtBuildings)
|
||||||
{
|
{
|
||||||
auto height = town->buildings.at(bid)->height;
|
auto height = getTown()->buildings.at(bid)->height;
|
||||||
if(ret < height)
|
if(ret < height)
|
||||||
ret = height;
|
ret = height;
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ int CGTownInstance::mageGuildLevel() const
|
|||||||
|
|
||||||
int CGTownInstance::getHordeLevel(const int & HID) const//HID - 0 or 1; returns creature level or -1 if that horde structure is not present
|
int CGTownInstance::getHordeLevel(const int & HID) const//HID - 0 or 1; returns creature level or -1 if that horde structure is not present
|
||||||
{
|
{
|
||||||
return town->hordeLvl.at(HID);
|
return getTown()->hordeLvl.at(HID);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CGTownInstance::creatureGrowth(const int & level) const
|
int CGTownInstance::creatureGrowth(const int & level) const
|
||||||
@ -127,7 +127,7 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
|
|||||||
{
|
{
|
||||||
GrowthInfo ret;
|
GrowthInfo ret;
|
||||||
|
|
||||||
if (level<0 || level >=town->creatures.size())
|
if (level<0 || level >=getTown()->creatures.size())
|
||||||
return ret;
|
return ret;
|
||||||
if (creatures[level].second.empty())
|
if (creatures[level].second.empty())
|
||||||
return ret; //no dwelling
|
return ret; //no dwelling
|
||||||
@ -151,11 +151,11 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
|
|||||||
else if (hasBuilt(BuildingID::CITADEL))
|
else if (hasBuilt(BuildingID::CITADEL))
|
||||||
ret.entries.emplace_back(subID, BuildingID::CITADEL, castleBonus = base / 2);
|
ret.entries.emplace_back(subID, BuildingID::CITADEL, castleBonus = base / 2);
|
||||||
|
|
||||||
if(town->hordeLvl.at(0) == level)//horde 1
|
if(getTown()->hordeLvl.at(0) == level)//horde 1
|
||||||
if(hasBuilt(BuildingID::HORDE_1))
|
if(hasBuilt(BuildingID::HORDE_1))
|
||||||
ret.entries.emplace_back(subID, BuildingID::HORDE_1, creature->getHorde());
|
ret.entries.emplace_back(subID, BuildingID::HORDE_1, creature->getHorde());
|
||||||
|
|
||||||
if(town->hordeLvl.at(1) == level)//horde 2
|
if(getTown()->hordeLvl.at(1) == level)//horde 2
|
||||||
if(hasBuilt(BuildingID::HORDE_2))
|
if(hasBuilt(BuildingID::HORDE_2))
|
||||||
ret.entries.emplace_back(subID, BuildingID::HORDE_2, creature->getHorde());
|
ret.entries.emplace_back(subID, BuildingID::HORDE_2, creature->getHorde());
|
||||||
|
|
||||||
@ -209,11 +209,11 @@ int CGTownInstance::getDwellingBonus(const std::vector<CreatureID>& creatureIds,
|
|||||||
TResources CGTownInstance::dailyIncome() const
|
TResources CGTownInstance::dailyIncome() const
|
||||||
{
|
{
|
||||||
TResources ret;
|
TResources ret;
|
||||||
for(const auto & p : town->buildings)
|
for(const auto & p : getTown()->buildings)
|
||||||
{
|
{
|
||||||
BuildingID buildingUpgrade;
|
BuildingID buildingUpgrade;
|
||||||
|
|
||||||
for(const auto & p2 : town->buildings)
|
for(const auto & p2 : getTown()->buildings)
|
||||||
{
|
{
|
||||||
if (p2.second->upgrade == p.first)
|
if (p2.second->upgrade == p.first)
|
||||||
{
|
{
|
||||||
@ -251,10 +251,10 @@ bool CGTownInstance::hasCapitol() const
|
|||||||
|
|
||||||
TownFortifications CGTownInstance::fortificationsLevel() const
|
TownFortifications CGTownInstance::fortificationsLevel() const
|
||||||
{
|
{
|
||||||
auto result = town->fortifications;
|
auto result = getTown()->fortifications;
|
||||||
|
|
||||||
for (auto const & buildingID : builtBuildings)
|
for (auto const & buildingID : builtBuildings)
|
||||||
result += town->buildings.at(buildingID)->fortifications;
|
result += getTown()->buildings.at(buildingID)->fortifications;
|
||||||
|
|
||||||
if (result.wallsHealth == 0)
|
if (result.wallsHealth == 0)
|
||||||
return TownFortifications();
|
return TownFortifications();
|
||||||
@ -264,7 +264,6 @@ TownFortifications CGTownInstance::fortificationsLevel() const
|
|||||||
|
|
||||||
CGTownInstance::CGTownInstance(IGameCallback *cb):
|
CGTownInstance::CGTownInstance(IGameCallback *cb):
|
||||||
CGDwelling(cb),
|
CGDwelling(cb),
|
||||||
town(nullptr),
|
|
||||||
built(0),
|
built(0),
|
||||||
destroyed(0),
|
destroyed(0),
|
||||||
identifier(0),
|
identifier(0),
|
||||||
@ -379,17 +378,17 @@ void CGTownInstance::onHeroLeave(const CGHeroInstance * h) const
|
|||||||
|
|
||||||
std::string CGTownInstance::getObjectName() const
|
std::string CGTownInstance::getObjectName() const
|
||||||
{
|
{
|
||||||
return getNameTranslated() + ", " + town->faction->getNameTranslated();
|
return getNameTranslated() + ", " + getTown()->faction->getNameTranslated();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGTownInstance::townEnvisagesBuilding(BuildingSubID::EBuildingSubID subId) const
|
bool CGTownInstance::townEnvisagesBuilding(BuildingSubID::EBuildingSubID subId) const
|
||||||
{
|
{
|
||||||
return town->getBuildingType(subId) != BuildingID::NONE;
|
return getTown()->getBuildingType(subId) != BuildingID::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGTownInstance::initializeConfigurableBuildings(vstd::RNG & rand)
|
void CGTownInstance::initializeConfigurableBuildings(vstd::RNG & rand)
|
||||||
{
|
{
|
||||||
for(const auto & kvp : town->buildings)
|
for(const auto & kvp : getTown()->buildings)
|
||||||
{
|
{
|
||||||
if(!kvp.second->rewardableObjectInfo.getParameters().isNull())
|
if(!kvp.second->rewardableObjectInfo.getParameters().isNull())
|
||||||
rewardableBuildings[kvp.first] = new TownRewardableBuildingInstance(this, kvp.second->bid, rand);
|
rewardableBuildings[kvp.first] = new TownRewardableBuildingInstance(this, kvp.second->bid, rand);
|
||||||
@ -457,8 +456,7 @@ void CGTownInstance::pickRandomObject(vstd::RNG & rand)
|
|||||||
|
|
||||||
assert(ID == Obj::TOWN); // just in case
|
assert(ID == Obj::TOWN); // just in case
|
||||||
setType(ID, subID);
|
setType(ID, subID);
|
||||||
town = (*VLC->townh)[getFaction()]->town;
|
randomizeArmy(getFactionID());
|
||||||
randomizeArmy(getFaction());
|
|
||||||
updateAppearance();
|
updateAppearance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,19 +465,19 @@ void CGTownInstance::initObj(vstd::RNG & rand) ///initialize town structures
|
|||||||
blockVisit = true;
|
blockVisit = true;
|
||||||
|
|
||||||
if(townEnvisagesBuilding(BuildingSubID::PORTAL_OF_SUMMONING)) //Dungeon for example
|
if(townEnvisagesBuilding(BuildingSubID::PORTAL_OF_SUMMONING)) //Dungeon for example
|
||||||
creatures.resize(town->creatures.size() + 1);
|
creatures.resize(getTown()->creatures.size() + 1);
|
||||||
else
|
else
|
||||||
creatures.resize(town->creatures.size());
|
creatures.resize(getTown()->creatures.size());
|
||||||
|
|
||||||
for (int level = 0; level < town->creatures.size(); level++)
|
for (int level = 0; level < getTown()->creatures.size(); level++)
|
||||||
{
|
{
|
||||||
BuildingID buildID = BuildingID(BuildingID::getDwellingFromLevel(level, 0));
|
BuildingID buildID = BuildingID(BuildingID::getDwellingFromLevel(level, 0));
|
||||||
int upgradeNum = 0;
|
int upgradeNum = 0;
|
||||||
|
|
||||||
for (; town->buildings.count(buildID); upgradeNum++, BuildingID::advanceDwelling(buildID))
|
for (; getTown()->buildings.count(buildID); upgradeNum++, BuildingID::advanceDwelling(buildID))
|
||||||
{
|
{
|
||||||
if (hasBuilt(buildID) && town->creatures.at(level).size() > upgradeNum)
|
if (hasBuilt(buildID) && getTown()->creatures.at(level).size() > upgradeNum)
|
||||||
creatures[level].second.push_back(town->creatures[level][upgradeNum]);
|
creatures[level].second.push_back(getTown()->creatures[level][upgradeNum]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initializeConfigurableBuildings(rand);
|
initializeConfigurableBuildings(rand);
|
||||||
@ -623,9 +621,9 @@ void CGTownInstance::removeCapitols(const PlayerColor & owner) const
|
|||||||
if (hasCapitol()) // search if there's an older capitol
|
if (hasCapitol()) // search if there's an older capitol
|
||||||
{
|
{
|
||||||
PlayerState* state = cb->gameState()->getPlayerState(owner); //get all towns owned by player
|
PlayerState* state = cb->gameState()->getPlayerState(owner); //get all towns owned by player
|
||||||
for (const auto & town : state->getTowns())
|
for (const auto & otherTown : state->getTowns())
|
||||||
{
|
{
|
||||||
if (town != this && town->hasCapitol())
|
if (otherTown != this && otherTown->hasCapitol())
|
||||||
{
|
{
|
||||||
RazeStructures rs;
|
RazeStructures rs;
|
||||||
rs.tid = id;
|
rs.tid = id;
|
||||||
@ -648,7 +646,7 @@ void CGTownInstance::clearArmy() const
|
|||||||
|
|
||||||
BoatId CGTownInstance::getBoatType() const
|
BoatId CGTownInstance::getBoatType() const
|
||||||
{
|
{
|
||||||
return town->faction->boatType;
|
return getTown()->faction->boatType;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CGTownInstance::getMarketEfficiency() const
|
int CGTownInstance::getMarketEfficiency() const
|
||||||
@ -703,7 +701,7 @@ void CGTownInstance::updateAppearance()
|
|||||||
|
|
||||||
std::string CGTownInstance::nodeName() const
|
std::string CGTownInstance::nodeName() const
|
||||||
{
|
{
|
||||||
return "Town (" + (town ? town->faction->getNameTranslated() : "unknown") + ") of " + getNameTranslated();
|
return "Town (" + getTown()->faction->getNameTranslated() + ") of " + getNameTranslated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGTownInstance::deserializationFix()
|
void CGTownInstance::deserializationFix()
|
||||||
@ -752,7 +750,7 @@ void CGTownInstance::recreateBuildingsBonuses()
|
|||||||
|
|
||||||
for(const auto & upgradeID : builtBuildings)
|
for(const auto & upgradeID : builtBuildings)
|
||||||
{
|
{
|
||||||
const auto & upgrade = town->buildings.at(upgradeID);
|
const auto & upgrade = getTown()->buildings.at(upgradeID);
|
||||||
if (upgrade->getBase() == bid && upgrade->upgradeReplacesBonuses)
|
if (upgrade->getBase() == bid && upgrade->upgradeReplacesBonuses)
|
||||||
bonusesReplacedByUpgrade = true;
|
bonusesReplacedByUpgrade = true;
|
||||||
}
|
}
|
||||||
@ -761,7 +759,7 @@ void CGTownInstance::recreateBuildingsBonuses()
|
|||||||
if (bonusesReplacedByUpgrade)
|
if (bonusesReplacedByUpgrade)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto building = town->buildings.at(bid);
|
auto building = getTown()->buildings.at(bid);
|
||||||
|
|
||||||
if(building->buildingBonuses.empty())
|
if(building->buildingBonuses.empty())
|
||||||
continue;
|
continue;
|
||||||
@ -828,21 +826,6 @@ bool CGTownInstance::armedGarrison() const
|
|||||||
return !stacks.empty() || garrisonHero;
|
return !stacks.empty() || garrisonHero;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CTown * CGTownInstance::getTown() const
|
|
||||||
{
|
|
||||||
if(ID == Obj::RANDOM_TOWN)
|
|
||||||
return VLC->townh->randomTown;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(nullptr == town)
|
|
||||||
{
|
|
||||||
return (*VLC->townh)[getFaction()]->town;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return town;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int CGTownInstance::getTownLevel() const
|
int CGTownInstance::getTownLevel() const
|
||||||
{
|
{
|
||||||
// count all buildings that are not upgrades
|
// count all buildings that are not upgrades
|
||||||
@ -850,7 +833,7 @@ int CGTownInstance::getTownLevel() const
|
|||||||
|
|
||||||
for(const auto & bid : builtBuildings)
|
for(const auto & bid : builtBuildings)
|
||||||
{
|
{
|
||||||
if(town->buildings.at(bid)->upgrade == BuildingID::NONE)
|
if(getTown()->buildings.at(bid)->upgrade == BuildingID::NONE)
|
||||||
level++;
|
level++;
|
||||||
}
|
}
|
||||||
return level;
|
return level;
|
||||||
@ -892,7 +875,7 @@ bool CGTownInstance::hasBuilt(BuildingSubID::EBuildingSubID buildingID) const
|
|||||||
{
|
{
|
||||||
for(const auto & bid : builtBuildings)
|
for(const auto & bid : builtBuildings)
|
||||||
{
|
{
|
||||||
if(town->buildings.at(bid)->subId == buildingID)
|
if(getTown()->buildings.at(bid)->subId == buildingID)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -905,7 +888,7 @@ bool CGTownInstance::hasBuilt(const BuildingID & buildingID) const
|
|||||||
|
|
||||||
bool CGTownInstance::hasBuilt(const BuildingID & buildingID, FactionID townID) const
|
bool CGTownInstance::hasBuilt(const BuildingID & buildingID, FactionID townID) const
|
||||||
{
|
{
|
||||||
if (townID == town->faction->getId() || townID == FactionID::ANY)
|
if (townID == getTown()->faction->getId() || townID == FactionID::ANY)
|
||||||
return hasBuilt(buildingID);
|
return hasBuilt(buildingID);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -923,7 +906,7 @@ std::set<EMarketMode> CGTownInstance::availableModes() const
|
|||||||
std::set<EMarketMode> result;
|
std::set<EMarketMode> result;
|
||||||
for (const auto & buildingID : builtBuildings)
|
for (const auto & buildingID : builtBuildings)
|
||||||
{
|
{
|
||||||
const auto * buildingPtr = town->buildings.at(buildingID).get();
|
const auto * buildingPtr = getTown()->buildings.at(buildingID).get();
|
||||||
result.insert(buildingPtr->marketModes.begin(), buildingPtr->marketModes.end());
|
result.insert(buildingPtr->marketModes.begin(), buildingPtr->marketModes.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -950,11 +933,11 @@ std::set<BuildingID> CGTownInstance::getBuildings() const
|
|||||||
|
|
||||||
TResources CGTownInstance::getBuildingCost(const BuildingID & buildingID) const
|
TResources CGTownInstance::getBuildingCost(const BuildingID & buildingID) const
|
||||||
{
|
{
|
||||||
if (vstd::contains(town->buildings, buildingID))
|
if (vstd::contains(getTown()->buildings, buildingID))
|
||||||
return town->buildings.at(buildingID)->resources;
|
return getTown()->buildings.at(buildingID)->resources;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logGlobal->error("Town %s at %s has no possible building %d!", getNameTranslated(), pos.toString(), buildingID.toEnum());
|
logGlobal->error("Town %s at %s has no possible building %d!", getNameTranslated(), anchorPos().toString(), buildingID.toEnum());
|
||||||
return TResources();
|
return TResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -962,7 +945,7 @@ TResources CGTownInstance::getBuildingCost(const BuildingID & buildingID) const
|
|||||||
|
|
||||||
CBuilding::TRequired CGTownInstance::genBuildingRequirements(const BuildingID & buildID, bool deep) const
|
CBuilding::TRequired CGTownInstance::genBuildingRequirements(const BuildingID & buildID, bool deep) const
|
||||||
{
|
{
|
||||||
const CBuilding * building = town->buildings.at(buildID);
|
const CBuilding * building = getTown()->buildings.at(buildID);
|
||||||
|
|
||||||
//TODO: find better solution to prevent infinite loops
|
//TODO: find better solution to prevent infinite loops
|
||||||
std::set<BuildingID> processed;
|
std::set<BuildingID> processed;
|
||||||
@ -970,13 +953,13 @@ CBuilding::TRequired CGTownInstance::genBuildingRequirements(const BuildingID &
|
|||||||
std::function<CBuilding::TRequired::Variant(const BuildingID &)> dependTest =
|
std::function<CBuilding::TRequired::Variant(const BuildingID &)> dependTest =
|
||||||
[&](const BuildingID & id) -> CBuilding::TRequired::Variant
|
[&](const BuildingID & id) -> CBuilding::TRequired::Variant
|
||||||
{
|
{
|
||||||
if (town->buildings.count(id) == 0)
|
if (getTown()->buildings.count(id) == 0)
|
||||||
{
|
{
|
||||||
logMod->error("Invalid building ID %d in building dependencies!", id.getNum());
|
logMod->error("Invalid building ID %d in building dependencies!", id.getNum());
|
||||||
return CBuilding::TRequired::OperatorAll();
|
return CBuilding::TRequired::OperatorAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CBuilding * build = town->buildings.at(id);
|
const CBuilding * build = getTown()->buildings.at(id);
|
||||||
CBuilding::TRequired::OperatorAll requirements;
|
CBuilding::TRequired::OperatorAll requirements;
|
||||||
|
|
||||||
if (!hasBuilt(id))
|
if (!hasBuilt(id))
|
||||||
@ -1001,7 +984,7 @@ CBuilding::TRequired CGTownInstance::genBuildingRequirements(const BuildingID &
|
|||||||
CBuilding::TRequired::OperatorAll requirements;
|
CBuilding::TRequired::OperatorAll requirements;
|
||||||
if (building->upgrade != BuildingID::NONE)
|
if (building->upgrade != BuildingID::NONE)
|
||||||
{
|
{
|
||||||
const CBuilding * upgr = town->buildings.at(building->upgrade);
|
const CBuilding * upgr = getTown()->buildings.at(building->upgrade);
|
||||||
|
|
||||||
requirements.expressions.push_back(dependTest(upgr->bid));
|
requirements.expressions.push_back(dependTest(upgr->bid));
|
||||||
processed.clear();
|
processed.clear();
|
||||||
@ -1151,14 +1134,27 @@ void CGTownInstance::serializeJsonOptions(JsonSerializeFormat & handler)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FactionID CGTownInstance::getFaction() const
|
const CFaction * CGTownInstance::getFaction() const
|
||||||
{
|
{
|
||||||
return FactionID(subID.getNum());
|
return getFactionID().toFaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
const CTown * CGTownInstance::getTown() const
|
||||||
|
{
|
||||||
|
if(ID == Obj::RANDOM_TOWN)
|
||||||
|
return VLC->townh->randomTown;
|
||||||
|
|
||||||
|
return getFaction()->town;
|
||||||
|
}
|
||||||
|
|
||||||
|
FactionID CGTownInstance::getFactionID() const
|
||||||
|
{
|
||||||
|
return FactionID(subID.getNum());
|
||||||
}
|
}
|
||||||
|
|
||||||
TerrainId CGTownInstance::getNativeTerrain() const
|
TerrainId CGTownInstance::getNativeTerrain() const
|
||||||
{
|
{
|
||||||
return town->faction->getNativeTerrain();
|
return getTown()->faction->getNativeTerrain();
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtifactID CGTownInstance::getWarMachineInBuilding(BuildingID building) const
|
ArtifactID CGTownInstance::getWarMachineInBuilding(BuildingID building) const
|
||||||
@ -1166,21 +1162,21 @@ ArtifactID CGTownInstance::getWarMachineInBuilding(BuildingID building) const
|
|||||||
if (builtBuildings.count(building) == 0)
|
if (builtBuildings.count(building) == 0)
|
||||||
return ArtifactID::NONE;
|
return ArtifactID::NONE;
|
||||||
|
|
||||||
if (building == BuildingID::BLACKSMITH && town->warMachineDeprecated.hasValue())
|
if (building == BuildingID::BLACKSMITH && getTown()->warMachineDeprecated.hasValue())
|
||||||
return town->warMachineDeprecated.toCreature()->warMachine;
|
return getTown()->warMachineDeprecated.toCreature()->warMachine;
|
||||||
|
|
||||||
return town->buildings.at(building)->warMachine;
|
return getTown()->buildings.at(building)->warMachine;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGTownInstance::isWarMachineAvailable(ArtifactID warMachine) const
|
bool CGTownInstance::isWarMachineAvailable(ArtifactID warMachine) const
|
||||||
{
|
{
|
||||||
for (auto const & buildingID : builtBuildings)
|
for (auto const & buildingID : builtBuildings)
|
||||||
if (town->buildings.at(buildingID)->warMachine == warMachine)
|
if (getTown()->buildings.at(buildingID)->warMachine == warMachine)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (builtBuildings.count(BuildingID::BLACKSMITH) &&
|
if (builtBuildings.count(BuildingID::BLACKSMITH) &&
|
||||||
town->warMachineDeprecated.hasValue() &&
|
getTown()->warMachineDeprecated.hasValue() &&
|
||||||
town->warMachineDeprecated.toCreature()->warMachine == warMachine)
|
getTown()->warMachineDeprecated.toCreature()->warMachine == warMachine)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -1200,7 +1196,7 @@ GrowthInfo::Entry::Entry(int subID, const BuildingID & building, int _count): co
|
|||||||
{
|
{
|
||||||
MetaString formatter;
|
MetaString formatter;
|
||||||
formatter.appendRawString("%s %+d");
|
formatter.appendRawString("%s %+d");
|
||||||
formatter.replaceRawString((*VLC->townh)[subID]->town->buildings.at(building)->getNameTranslated());
|
formatter.replaceRawString(FactionID(subID).toFaction()->town->buildings.at(building)->getNameTranslated());
|
||||||
formatter.replacePositiveNumber(count);
|
formatter.replacePositiveNumber(count);
|
||||||
|
|
||||||
description = formatter.toString();
|
description = formatter.toString();
|
||||||
|
@ -50,18 +50,16 @@ struct DLL_LINKAGE GrowthInfo
|
|||||||
|
|
||||||
class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public IMarket, public INativeTerrainProvider, public ICreatureUpgrader
|
class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public IMarket, public INativeTerrainProvider, public ICreatureUpgrader
|
||||||
{
|
{
|
||||||
|
friend class CTownInstanceConstructor;
|
||||||
std::string nameTextId; // name of town
|
std::string nameTextId; // name of town
|
||||||
|
|
||||||
std::map<BuildingID, TownRewardableBuildingInstance*> convertOldBuildings(std::vector<TownRewardableBuildingInstance*> oldVector);
|
std::map<BuildingID, TownRewardableBuildingInstance*> convertOldBuildings(std::vector<TownRewardableBuildingInstance*> oldVector);
|
||||||
std::set<BuildingID> builtBuildings;
|
std::set<BuildingID> builtBuildings;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using CGDwelling::getPosition;
|
|
||||||
|
|
||||||
enum EFortLevel {NONE = 0, FORT = 1, CITADEL = 2, CASTLE = 3};
|
enum EFortLevel {NONE = 0, FORT = 1, CITADEL = 2, CASTLE = 3};
|
||||||
|
|
||||||
CTownAndVisitingHero townAndVis;
|
CTownAndVisitingHero townAndVis;
|
||||||
const CTown * town;
|
|
||||||
si32 built; //how many buildings has been built this turn
|
si32 built; //how many buildings has been built this turn
|
||||||
si32 destroyed; //how many buildings has been destroyed this turn
|
si32 destroyed; //how many buildings has been destroyed this turn
|
||||||
ConstTransitivePtr<CGHeroInstance> garrisonHero, visitingHero;
|
ConstTransitivePtr<CGHeroInstance> garrisonHero, visitingHero;
|
||||||
@ -114,16 +112,21 @@ public:
|
|||||||
rewardableBuildings = convertOldBuildings(oldVector);
|
rewardableBuildings = convertOldBuildings(oldVector);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h.saving)
|
if (h.version < Handler::Version::REMOVE_TOWN_PTR)
|
||||||
{
|
{
|
||||||
CFaction * faction = town ? town->faction : nullptr;
|
CTown * town = nullptr;
|
||||||
h & faction;
|
|
||||||
}
|
if (h.saving)
|
||||||
else
|
{
|
||||||
{
|
CFaction * faction = town ? town->faction : nullptr;
|
||||||
CFaction * faction = nullptr;
|
h & faction;
|
||||||
h & faction;
|
}
|
||||||
town = faction ? faction->town : nullptr;
|
else
|
||||||
|
{
|
||||||
|
CFaction * faction = nullptr;
|
||||||
|
h & faction;
|
||||||
|
town = faction ? faction->town : nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h & townAndVis;
|
h & townAndVis;
|
||||||
@ -215,9 +218,10 @@ public:
|
|||||||
DamageRange getKeepDamageRange() const;
|
DamageRange getKeepDamageRange() const;
|
||||||
|
|
||||||
const CTown * getTown() const;
|
const CTown * getTown() const;
|
||||||
|
const CFaction * getFaction() const;
|
||||||
|
|
||||||
/// INativeTerrainProvider
|
/// INativeTerrainProvider
|
||||||
FactionID getFaction() const override;
|
FactionID getFactionID() const override;
|
||||||
TerrainId getNativeTerrain() const override;
|
TerrainId getNativeTerrain() const override;
|
||||||
|
|
||||||
/// Returns ID of war machine that is produced by specified building or NONE if this is not built or if building does not produce war machines
|
/// Returns ID of war machine that is produced by specified building or NONE if this is not built or if building does not produce war machines
|
||||||
|
@ -431,7 +431,7 @@ void CGSeerHut::setObjToKill()
|
|||||||
|
|
||||||
if(getCreatureToKill(true))
|
if(getCreatureToKill(true))
|
||||||
{
|
{
|
||||||
quest->stackToKill = getCreatureToKill(false)->getCreature();
|
quest->stackToKill = getCreatureToKill(false)->getCreatureID();
|
||||||
assert(quest->stackToKill != CreatureID::NONE);
|
assert(quest->stackToKill != CreatureID::NONE);
|
||||||
quest->stackDirection = checkDirection();
|
quest->stackDirection = checkDirection();
|
||||||
}
|
}
|
||||||
@ -614,7 +614,7 @@ void CGSeerHut::onHeroVisit(const CGHeroInstance * h) const
|
|||||||
|
|
||||||
int CGSeerHut::checkDirection() const
|
int CGSeerHut::checkDirection() const
|
||||||
{
|
{
|
||||||
int3 cord = getCreatureToKill(false)->pos;
|
int3 cord = getCreatureToKill(false)->visitablePos();
|
||||||
if(static_cast<double>(cord.x) / static_cast<double>(cb->getMapSize().x) < 0.34) //north
|
if(static_cast<double>(cord.x) / static_cast<double>(cb->getMapSize().x) < 0.34) //north
|
||||||
{
|
{
|
||||||
if(static_cast<double>(cord.y) / static_cast<double>(cb->getMapSize().y) < 0.34) //northwest
|
if(static_cast<double>(cord.y) / static_cast<double>(cb->getMapSize().y) < 0.34) //northwest
|
||||||
|
@ -145,7 +145,7 @@ void IBoatGenerator::getProblemText(MetaString &out, const CGHeroInstance *visit
|
|||||||
out.appendLocalString(EMetaText::ADVOB_TXT, 189);
|
out.appendLocalString(EMetaText::ADVOB_TXT, 189);
|
||||||
break;
|
break;
|
||||||
case NO_WATER:
|
case NO_WATER:
|
||||||
logGlobal->error("Shipyard without water at tile %s! ", getObject()->getPosition().toString());
|
logGlobal->error("Shipyard without water at tile %s! ", getObject()->anchorPos().toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ public:
|
|||||||
|
|
||||||
virtual PlayerColor getOwner() const = 0;
|
virtual PlayerColor getOwner() const = 0;
|
||||||
virtual int3 visitablePos() const = 0;
|
virtual int3 visitablePos() const = 0;
|
||||||
virtual int3 getPosition() const = 0;
|
virtual int3 anchorPos() const = 0;
|
||||||
|
|
||||||
virtual void onHeroVisit(const CGHeroInstance * h) const;
|
virtual void onHeroVisit(const CGHeroInstance * h) const;
|
||||||
virtual void onHeroLeave(const CGHeroInstance * h) const;
|
virtual void onHeroLeave(const CGHeroInstance * h) const;
|
||||||
|
@ -111,7 +111,7 @@ void CGMine::initObj(vstd::RNG & rand)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logGlobal->error("Abandoned mine at (%s) has no valid resource candidates!", pos.toString());
|
logGlobal->error("Abandoned mine at (%s) has no valid resource candidates!", anchorPos().toString());
|
||||||
producedResource = GameResID::GOLD;
|
producedResource = GameResID::GOLD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -510,11 +510,11 @@ void CGMonolith::onHeroVisit( const CGHeroInstance * h ) const
|
|||||||
|
|
||||||
if(cb->isTeleportChannelImpassable(channel))
|
if(cb->isTeleportChannelImpassable(channel))
|
||||||
{
|
{
|
||||||
logGlobal->debug("Cannot find corresponding exit monolith for %d at %s", id.getNum(), pos.toString());
|
logGlobal->debug("Cannot find corresponding exit monolith for %d at %s", id.getNum(), anchorPos().toString());
|
||||||
td.impassable = true;
|
td.impassable = true;
|
||||||
}
|
}
|
||||||
else if(getRandomExit(h) == ObjectInstanceID())
|
else if(getRandomExit(h) == ObjectInstanceID())
|
||||||
logGlobal->debug("All exits blocked for monolith %d at %s", id.getNum(), pos.toString());
|
logGlobal->debug("All exits blocked for monolith %d at %s", id.getNum(), anchorPos().toString());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
h->showInfoDialog(70);
|
h->showInfoDialog(70);
|
||||||
@ -574,7 +574,7 @@ void CGSubterraneanGate::onHeroVisit( const CGHeroInstance * h ) const
|
|||||||
if(cb->isTeleportChannelImpassable(channel))
|
if(cb->isTeleportChannelImpassable(channel))
|
||||||
{
|
{
|
||||||
h->showInfoDialog(153);//Just inside the entrance you find a large pile of rubble blocking the tunnel. You leave discouraged.
|
h->showInfoDialog(153);//Just inside the entrance you find a large pile of rubble blocking the tunnel. You leave discouraged.
|
||||||
logGlobal->debug("Cannot find exit subterranean gate for %d at %s", id.getNum(), pos.toString());
|
logGlobal->debug("Cannot find exit subterranean gate for %d at %s", id.getNum(), anchorPos().toString());
|
||||||
td.impassable = true;
|
td.impassable = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -657,11 +657,11 @@ void CGWhirlpool::onHeroVisit( const CGHeroInstance * h ) const
|
|||||||
TeleportDialog td(h->id, channel);
|
TeleportDialog td(h->id, channel);
|
||||||
if(cb->isTeleportChannelImpassable(channel))
|
if(cb->isTeleportChannelImpassable(channel))
|
||||||
{
|
{
|
||||||
logGlobal->debug("Cannot find exit whirlpool for %d at %s", id.getNum(), pos.toString());
|
logGlobal->debug("Cannot find exit whirlpool for %d at %s", id.getNum(), anchorPos().toString());
|
||||||
td.impassable = true;
|
td.impassable = true;
|
||||||
}
|
}
|
||||||
else if(getRandomExit(h) == ObjectInstanceID())
|
else if(getRandomExit(h) == ObjectInstanceID())
|
||||||
logGlobal->debug("All exits are blocked for whirlpool %d at %s", id.getNum(), pos.toString());
|
logGlobal->debug("All exits are blocked for whirlpool %d at %s", id.getNum(), anchorPos().toString());
|
||||||
|
|
||||||
if(!isProtected(h))
|
if(!isProtected(h))
|
||||||
{
|
{
|
||||||
@ -1086,9 +1086,9 @@ void CGMagi::onHeroVisit(const CGHeroInstance * h) const
|
|||||||
|
|
||||||
for(const auto & eye : eyes)
|
for(const auto & eye : eyes)
|
||||||
{
|
{
|
||||||
cb->getTilesInRange (fw.tiles, eye->pos, 10, ETileVisibility::HIDDEN, h->tempOwner);
|
cb->getTilesInRange (fw.tiles, eye->visitablePos(), 10, ETileVisibility::HIDDEN, h->tempOwner);
|
||||||
cb->sendAndApply(fw);
|
cb->sendAndApply(fw);
|
||||||
cv.pos = eye->pos;
|
cv.pos = eye->visitablePos();
|
||||||
|
|
||||||
cb->sendAndApply(cv);
|
cb->sendAndApply(cv);
|
||||||
}
|
}
|
||||||
|
@ -56,9 +56,9 @@ int3 TownBuildingInstance::visitablePos() const
|
|||||||
return town->visitablePos();
|
return town->visitablePos();
|
||||||
}
|
}
|
||||||
|
|
||||||
int3 TownBuildingInstance::getPosition() const
|
int3 TownBuildingInstance::anchorPos() const
|
||||||
{
|
{
|
||||||
return town->getPosition();
|
return town->anchorPos();
|
||||||
}
|
}
|
||||||
|
|
||||||
TownRewardableBuildingInstance::TownRewardableBuildingInstance(IGameCallback *cb)
|
TownRewardableBuildingInstance::TownRewardableBuildingInstance(IGameCallback *cb)
|
||||||
@ -73,14 +73,14 @@ TownRewardableBuildingInstance::TownRewardableBuildingInstance(CGTownInstance *
|
|||||||
|
|
||||||
void TownRewardableBuildingInstance::initObj(vstd::RNG & rand)
|
void TownRewardableBuildingInstance::initObj(vstd::RNG & rand)
|
||||||
{
|
{
|
||||||
assert(town && town->town);
|
assert(town && town->getTown());
|
||||||
configuration = generateConfiguration(rand);
|
configuration = generateConfiguration(rand);
|
||||||
}
|
}
|
||||||
|
|
||||||
Rewardable::Configuration TownRewardableBuildingInstance::generateConfiguration(vstd::RNG & rand) const
|
Rewardable::Configuration TownRewardableBuildingInstance::generateConfiguration(vstd::RNG & rand) const
|
||||||
{
|
{
|
||||||
Rewardable::Configuration result;
|
Rewardable::Configuration result;
|
||||||
auto building = town->town->buildings.at(getBuildingType());
|
auto building = town->getTown()->buildings.at(getBuildingType());
|
||||||
|
|
||||||
building->rewardableObjectInfo.configureObject(result, rand, cb);
|
building->rewardableObjectInfo.configureObject(result, rand, cb);
|
||||||
for(auto & rewardInfo : result.info)
|
for(auto & rewardInfo : result.info)
|
||||||
|
@ -38,7 +38,7 @@ public:
|
|||||||
const IOwnableObject * asOwnable() const override;
|
const IOwnableObject * asOwnable() const override;
|
||||||
|
|
||||||
int3 visitablePos() const override;
|
int3 visitablePos() const override;
|
||||||
int3 getPosition() const override;
|
int3 anchorPos() const override;
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h)
|
template <typename Handler> void serialize(Handler &h)
|
||||||
{
|
{
|
||||||
|
@ -232,22 +232,22 @@ CMap::~CMap()
|
|||||||
|
|
||||||
void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total)
|
void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total)
|
||||||
{
|
{
|
||||||
const int zVal = obj->pos.z;
|
const int zVal = obj->anchorPos().z;
|
||||||
for(int fx = 0; fx < obj->getWidth(); ++fx)
|
for(int fx = 0; fx < obj->getWidth(); ++fx)
|
||||||
{
|
{
|
||||||
int xVal = obj->pos.x - fx;
|
int xVal = obj->anchorPos().x - fx;
|
||||||
for(int fy = 0; fy < obj->getHeight(); ++fy)
|
for(int fy = 0; fy < obj->getHeight(); ++fy)
|
||||||
{
|
{
|
||||||
int yVal = obj->pos.y - fy;
|
int yVal = obj->anchorPos().y - fy;
|
||||||
if(xVal>=0 && xVal < width && yVal>=0 && yVal < height)
|
if(xVal>=0 && xVal < width && yVal>=0 && yVal < height)
|
||||||
{
|
{
|
||||||
TerrainTile & curt = terrain[zVal][xVal][yVal];
|
TerrainTile & curt = terrain[zVal][xVal][yVal];
|
||||||
if(total || obj->visitableAt(xVal, yVal))
|
if(total || obj->visitableAt(int3(xVal, yVal, zVal)))
|
||||||
{
|
{
|
||||||
curt.visitableObjects -= obj;
|
curt.visitableObjects -= obj;
|
||||||
curt.visitable = curt.visitableObjects.size();
|
curt.visitable = curt.visitableObjects.size();
|
||||||
}
|
}
|
||||||
if(total || obj->blockingAt(xVal, yVal))
|
if(total || obj->blockingAt(int3(xVal, yVal, zVal)))
|
||||||
{
|
{
|
||||||
curt.blockingObjects -= obj;
|
curt.blockingObjects -= obj;
|
||||||
curt.blocked = curt.blockingObjects.size();
|
curt.blocked = curt.blockingObjects.size();
|
||||||
@ -259,22 +259,22 @@ void CMap::removeBlockVisTiles(CGObjectInstance * obj, bool total)
|
|||||||
|
|
||||||
void CMap::addBlockVisTiles(CGObjectInstance * obj)
|
void CMap::addBlockVisTiles(CGObjectInstance * obj)
|
||||||
{
|
{
|
||||||
const int zVal = obj->pos.z;
|
const int zVal = obj->anchorPos().z;
|
||||||
for(int fx = 0; fx < obj->getWidth(); ++fx)
|
for(int fx = 0; fx < obj->getWidth(); ++fx)
|
||||||
{
|
{
|
||||||
int xVal = obj->pos.x - fx;
|
int xVal = obj->anchorPos().x - fx;
|
||||||
for(int fy = 0; fy < obj->getHeight(); ++fy)
|
for(int fy = 0; fy < obj->getHeight(); ++fy)
|
||||||
{
|
{
|
||||||
int yVal = obj->pos.y - fy;
|
int yVal = obj->anchorPos().y - fy;
|
||||||
if(xVal>=0 && xVal < width && yVal >= 0 && yVal < height)
|
if(xVal>=0 && xVal < width && yVal >= 0 && yVal < height)
|
||||||
{
|
{
|
||||||
TerrainTile & curt = terrain[zVal][xVal][yVal];
|
TerrainTile & curt = terrain[zVal][xVal][yVal];
|
||||||
if(obj->visitableAt(xVal, yVal))
|
if(obj->visitableAt(int3(xVal, yVal, zVal)))
|
||||||
{
|
{
|
||||||
curt.visitableObjects.push_back(obj);
|
curt.visitableObjects.push_back(obj);
|
||||||
curt.visitable = true;
|
curt.visitable = true;
|
||||||
}
|
}
|
||||||
if(obj->blockingAt(xVal, yVal))
|
if(obj->blockingAt(int3(xVal, yVal, zVal)))
|
||||||
{
|
{
|
||||||
curt.blockingObjects.push_back(obj);
|
curt.blockingObjects.push_back(obj);
|
||||||
curt.blocked = true;
|
curt.blocked = true;
|
||||||
@ -302,7 +302,7 @@ void CMap::calculateGuardingGreaturePositions()
|
|||||||
CGHeroInstance * CMap::getHero(HeroTypeID heroID)
|
CGHeroInstance * CMap::getHero(HeroTypeID heroID)
|
||||||
{
|
{
|
||||||
for(auto & elem : heroesOnMap)
|
for(auto & elem : heroesOnMap)
|
||||||
if(elem->getHeroType() == heroID)
|
if(elem->getHeroTypeID() == heroID)
|
||||||
return elem;
|
return elem;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -444,14 +444,14 @@ const CGObjectInstance * CMap::getObjectiveObjectFrom(const int3 & pos, Obj type
|
|||||||
bestMatch = object;
|
bestMatch = object;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (object->pos.dist2dSQ(pos) < bestMatch->pos.dist2dSQ(pos))
|
if (object->anchorPos().dist2dSQ(pos) < bestMatch->anchorPos().dist2dSQ(pos))
|
||||||
bestMatch = object;// closer than one we already found
|
bestMatch = object;// closer than one we already found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(bestMatch != nullptr); // if this happens - victory conditions or map itself is very, very broken
|
assert(bestMatch != nullptr); // if this happens - victory conditions or map itself is very, very broken
|
||||||
|
|
||||||
logGlobal->error("Will use %s from %s", bestMatch->getObjectName(), bestMatch->pos.toString());
|
logGlobal->error("Will use %s from %s", bestMatch->getObjectName(), bestMatch->anchorPos().toString());
|
||||||
return bestMatch;
|
return bestMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -635,7 +635,7 @@ void CMap::addNewObject(CGObjectInstance * obj)
|
|||||||
void CMap::moveObject(CGObjectInstance * obj, const int3 & pos)
|
void CMap::moveObject(CGObjectInstance * obj, const int3 & pos)
|
||||||
{
|
{
|
||||||
removeBlockVisTiles(obj);
|
removeBlockVisTiles(obj);
|
||||||
obj->pos = pos;
|
obj->setAnchorPos(pos);
|
||||||
addBlockVisTiles(obj);
|
addBlockVisTiles(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -803,7 +803,7 @@ void CMap::reindexObjects()
|
|||||||
if (lhs->isRemovable() && !rhs->isRemovable())
|
if (lhs->isRemovable() && !rhs->isRemovable())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return lhs->pos.y < rhs->pos.y;
|
return lhs->anchorPos().y < rhs->anchorPos().y;
|
||||||
});
|
});
|
||||||
|
|
||||||
// instanceNames don't change
|
// instanceNames don't change
|
||||||
|
@ -615,7 +615,7 @@ std::string CInsertObjectOperation::getLabel() const
|
|||||||
CMoveObjectOperation::CMoveObjectOperation(CMap* map, CGObjectInstance* obj, const int3& targetPosition)
|
CMoveObjectOperation::CMoveObjectOperation(CMap* map, CGObjectInstance* obj, const int3& targetPosition)
|
||||||
: CMapOperation(map),
|
: CMapOperation(map),
|
||||||
obj(obj),
|
obj(obj),
|
||||||
initialPos(obj->pos),
|
initialPos(obj->anchorPos()),
|
||||||
targetPos(targetPosition)
|
targetPos(targetPosition)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user