mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-02 00:10:22 +02:00
Merge remote-tracking branch 'upstream/develop' into cpp-map-editor
# Conflicts: # lib/CHeroHandler.cpp # lib/mapObjects/CObjectClassesHandler.cpp # lib/mapObjects/CObjectClassesHandler.h # lib/mapObjects/ObjectTemplate.cpp # lib/mapObjects/ObjectTemplate.h # lib/mapping/CCampaignHandler.h # lib/mapping/CMap.h # lib/mapping/CMapEditManager.cpp # lib/mapping/CMapEditManager.h # lib/rmg/CMapGenerator.cpp # lib/rmg/CMapGenerator.h # lib/rmg/ConnectionsPlacer.cpp # lib/rmg/ObjectManager.cpp # lib/rmg/ObstaclePlacer.cpp # lib/rmg/ObstaclePlacer.h # lib/rmg/RiverPlacer.cpp # lib/rmg/RmgArea.h # lib/rmg/RmgMap.cpp # lib/rmg/RmgMap.h # lib/rmg/RmgObject.cpp # lib/rmg/TownPlacer.cpp # lib/rmg/TreasurePlacer.cpp # lib/rmg/TreasurePlacer.h # lib/rmg/WaterProxy.cpp # lib/rmg/Zone.cpp # lib/rmg/Zone.h # lib/serializer/CSerializer.h # lib/spells/CSpellHandler.cpp
This commit is contained in:
commit
5ce0f7c4e0
@ -92,6 +92,8 @@ int32_t estimateTownIncome(CCallback * cb, const CGObjectInstance * target, cons
|
||||
|
||||
TResources getCreatureBankResources(const CGObjectInstance * target, const CGHeroInstance * hero)
|
||||
{
|
||||
//Fixme: unused variable hero
|
||||
|
||||
auto objectInfo = VLC->objtypeh->getHandlerFor(target->ID, target->subID)->getObjectInfo(target->appearance);
|
||||
CBankInfo * bankInfo = dynamic_cast<CBankInfo *>(objectInfo.get());
|
||||
auto resources = bankInfo->getPossibleResourcesReward();
|
||||
@ -114,11 +116,33 @@ uint64_t getCreatureBankArmyReward(const CGObjectInstance * target, const CGHero
|
||||
auto creatures = bankInfo->getPossibleCreaturesReward();
|
||||
uint64_t result = 0;
|
||||
|
||||
for(auto c : creatures)
|
||||
const auto& slots = hero->Slots();
|
||||
ui64 weakestStackPower = 0;
|
||||
if (slots.size() >= GameConstants::ARMY_SIZE)
|
||||
{
|
||||
result += c.data.type->AIValue * c.data.count * c.chance / 100;
|
||||
//No free slot, we might discard our weakest stack
|
||||
weakestStackPower = std::numeric_limits<ui64>().max();
|
||||
for (const auto stack : slots)
|
||||
{
|
||||
vstd::amin(weakestStackPower, stack.second->getPower());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto c : creatures)
|
||||
{
|
||||
//Only if hero has slot for this creature in the army
|
||||
if (hero->getSlotFor(c.data.type).validSlot())
|
||||
{
|
||||
result += (c.data.type->AIValue * c.data.count) * c.chance;
|
||||
}
|
||||
else
|
||||
{
|
||||
//we will need to discard the weakest stack
|
||||
result += (c.data.type->AIValue * c.data.count - weakestStackPower) * c.chance;
|
||||
}
|
||||
}
|
||||
result /= 100; //divide by total chance
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -168,13 +192,13 @@ uint64_t evaluateArtifactArmyValue(CArtifactInstance * art)
|
||||
return 1500;
|
||||
|
||||
auto statsValue =
|
||||
4 * art->valOfBonuses(Bonus::LAND_MOVEMENT)
|
||||
10 * art->valOfBonuses(Bonus::LAND_MOVEMENT)
|
||||
+ 1200 * art->valOfBonuses(Bonus::STACKS_SPEED)
|
||||
+ 700 * art->valOfBonuses(Bonus::MORALE)
|
||||
+ 700 * art->getAttack(false)
|
||||
+ 700 * art->getDefense(false)
|
||||
+ 700 * art->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::KNOWLEDGE)
|
||||
+ 700 * art->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::SPELL_POWER)
|
||||
+ 700 * art->getDefense(false)
|
||||
+ 500 * art->valOfBonuses(Bonus::LUCK);
|
||||
|
||||
auto classValue = 0;
|
||||
@ -234,6 +258,8 @@ uint64_t RewardEvaluator::getArmyReward(
|
||||
return ai->cb->getPlayerRelations(target->tempOwner, ai->playerID) == PlayerRelations::ENEMIES
|
||||
? enemyArmyEliminationRewardRatio * dynamic_cast<const CGHeroInstance *>(target)->getArmyStrength()
|
||||
: 0;
|
||||
case Obj::PANDORAS_BOX:
|
||||
return 5000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -273,7 +299,14 @@ float RewardEvaluator::getEnemyHeroStrategicalValue(const CGHeroInstance * enemy
|
||||
vstd::amax(objectValue, getStrategicalValue(obj));
|
||||
}
|
||||
|
||||
return objectValue / 2.0f + enemy->level / 15.0f;
|
||||
/*
|
||||
1. If an enemy hero can attack nearby object, it's not useful to capture the object on our own.
|
||||
Killing the hero is almost as important (0.9) as capturing the object itself.
|
||||
|
||||
2. The formula quickly approaches 1.0 as hero level increases,
|
||||
but higher level always means higher value and the minimal value for level 1 hero is 0.5
|
||||
*/
|
||||
return std::min(1.0f, objectValue * 0.9f + (1.0f - (1.0f / (1 + enemy->level))));
|
||||
}
|
||||
|
||||
float RewardEvaluator::getResourceRequirementStrength(int resType) const
|
||||
@ -322,13 +355,28 @@ float RewardEvaluator::getStrategicalValue(const CGObjectInstance * target) cons
|
||||
case Obj::RESOURCE:
|
||||
return target->subID == Res::GOLD ? 0 : 0.1f * getResourceRequirementStrength(target->subID);
|
||||
|
||||
case Obj::CREATURE_BANK:
|
||||
{
|
||||
auto resourceReward = getCreatureBankResources(target, nullptr);
|
||||
float sum = 0.0f;
|
||||
for (TResources::nziterator it (resourceReward); it.valid(); it++)
|
||||
{
|
||||
//Evaluate resources used for construction. Gold is evaluated separately.
|
||||
if (it->resType != Res::GOLD)
|
||||
{
|
||||
sum += 0.1f * getResourceRequirementStrength(it->resType);
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
case Obj::TOWN:
|
||||
if(ai->buildAnalyzer->getDevelopmentInfo().empty())
|
||||
return 1;
|
||||
|
||||
return dynamic_cast<const CGTownInstance *>(target)->hasFort()
|
||||
? (target->tempOwner == PlayerColor::NEUTRAL ? 0.8f : 1.0f)
|
||||
: 0.5f;
|
||||
: 0.7f;
|
||||
|
||||
case Obj::HERO:
|
||||
return ai->cb->getPlayerRelations(target->tempOwner, ai->playerID) == PlayerRelations::ENEMIES
|
||||
@ -385,6 +433,9 @@ float RewardEvaluator::getSkillReward(const CGObjectInstance * target, const CGH
|
||||
return 8;
|
||||
case Obj::WITCH_HUT:
|
||||
return evaluateWitchHutSkillScore(dynamic_cast<const CGWitchHut *>(target), hero, role);
|
||||
case Obj::PANDORAS_BOX:
|
||||
//Can contains experience, spells, or skills (only on custom maps)
|
||||
return 2.5f;
|
||||
case Obj::HERO:
|
||||
return ai->cb->getPlayerRelations(target->tempOwner, ai->playerID) == PlayerRelations::ENEMIES
|
||||
? enemyHeroEliminationSkillRewardRatio * dynamic_cast<const CGHeroInstance *>(target)->level
|
||||
@ -464,6 +515,11 @@ int32_t RewardEvaluator::getGoldReward(const CGObjectInstance * target, const CG
|
||||
return 10000;
|
||||
case Obj::SEA_CHEST:
|
||||
return 1500;
|
||||
case Obj::PANDORAS_BOX:
|
||||
return 5000;
|
||||
case Obj::PRISON:
|
||||
//Objectively saves us 2500 to hire hero
|
||||
return GameConstants::HERO_GOLD_COST;
|
||||
case Obj::HERO:
|
||||
return ai->cb->getPlayerRelations(target->tempOwner, ai->playerID) == PlayerRelations::ENEMIES
|
||||
? heroEliminationBonus + enemyArmyEliminationGoldRewardRatio * getArmyCost(dynamic_cast<const CGHeroInstance *>(target))
|
||||
|
@ -47,6 +47,10 @@
|
||||
|
||||
#include <vcmi/events/EventBus.h>
|
||||
|
||||
#ifdef VCMI_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
template<typename T> class CApplyOnLobby;
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
@ -694,7 +698,23 @@ void CServerHandler::threadRunServer()
|
||||
}
|
||||
comm += " > \"" + logName + '\"';
|
||||
|
||||
#ifdef VCMI_WINDOWS
|
||||
int result = -1;
|
||||
const auto bufSize = ::MultiByteToWideChar(CP_UTF8, 0, comm.c_str(), comm.size(), nullptr, 0);
|
||||
if(bufSize > 0)
|
||||
{
|
||||
std::wstring wComm(bufSize, {});
|
||||
const auto convertResult = ::MultiByteToWideChar(CP_UTF8, 0, comm.c_str(), comm.size(), &wComm[0], bufSize);
|
||||
if(convertResult > 0)
|
||||
result = ::_wsystem(wComm.c_str());
|
||||
else
|
||||
logNetwork->error("Error " + std::to_string(GetLastError()) + ": failed to convert server launch command to wide string: " + comm);
|
||||
}
|
||||
else
|
||||
logNetwork->error("Error " + std::to_string(GetLastError()) + ": failed to obtain buffer length to convert server launch command to wide string : " + comm);
|
||||
#else
|
||||
int result = std::system(comm.c_str());
|
||||
#endif
|
||||
if (result == 0)
|
||||
{
|
||||
logNetwork->info("Server closed correctly");
|
||||
|
@ -173,8 +173,8 @@ void Graphics::loadHeroAnimations()
|
||||
{
|
||||
for (auto & templ : VLC->objtypeh->getHandlerFor(Obj::HERO, elem->getIndex())->getTemplates())
|
||||
{
|
||||
if (!heroAnimations.count(templ.animationFile))
|
||||
heroAnimations[templ.animationFile] = loadHeroAnimation(templ.animationFile);
|
||||
if (!heroAnimations.count(templ->animationFile))
|
||||
heroAnimations[templ->animationFile] = loadHeroAnimation(templ->animationFile);
|
||||
}
|
||||
}
|
||||
|
||||
@ -381,21 +381,21 @@ std::shared_ptr<CAnimation> Graphics::getAnimation(const CGObjectInstance* obj)
|
||||
return getAnimation(obj->appearance);
|
||||
}
|
||||
|
||||
std::shared_ptr<CAnimation> Graphics::getAnimation(const ObjectTemplate & info)
|
||||
std::shared_ptr<CAnimation> Graphics::getAnimation(std::shared_ptr<const ObjectTemplate> info)
|
||||
{
|
||||
//the only(?) invisible object
|
||||
if(info.id == Obj::EVENT)
|
||||
if(info->id == Obj::EVENT)
|
||||
{
|
||||
return std::shared_ptr<CAnimation>();
|
||||
}
|
||||
|
||||
if(info.animationFile.empty())
|
||||
if(info->animationFile.empty())
|
||||
{
|
||||
logGlobal->warn("Def name for obj (%d,%d) is empty!", info.id, info.subid);
|
||||
logGlobal->warn("Def name for obj (%d,%d) is empty!", info->id, info->subid);
|
||||
return std::shared_ptr<CAnimation>();
|
||||
}
|
||||
|
||||
std::shared_ptr<CAnimation> ret = mapObjectAnimations[info.animationFile];
|
||||
std::shared_ptr<CAnimation> ret = mapObjectAnimations[info->animationFile];
|
||||
|
||||
//already loaded
|
||||
if(ret)
|
||||
@ -404,8 +404,8 @@ std::shared_ptr<CAnimation> Graphics::getAnimation(const ObjectTemplate & info)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = std::make_shared<CAnimation>(info.animationFile);
|
||||
mapObjectAnimations[info.animationFile] = ret;
|
||||
ret = std::make_shared<CAnimation>(info->animationFile);
|
||||
mapObjectAnimations[info->animationFile] = ret;
|
||||
|
||||
ret->preload();
|
||||
return ret;
|
||||
|
@ -98,7 +98,7 @@ public:
|
||||
void blueToPlayersAdv(SDL_Surface * sur, PlayerColor player); //replaces blue interface colour with a color of player
|
||||
|
||||
std::shared_ptr<CAnimation> getAnimation(const CGObjectInstance * obj);
|
||||
std::shared_ptr<CAnimation> getAnimation(const ObjectTemplate & info);
|
||||
std::shared_ptr<CAnimation> getAnimation(std::shared_ptr<const ObjectTemplate> info);
|
||||
};
|
||||
|
||||
extern Graphics * graphics;
|
||||
|
@ -502,13 +502,14 @@ void CBattleInterface::activate()
|
||||
bWait->activate();
|
||||
bDefence->activate();
|
||||
|
||||
for (auto hex : bfield)
|
||||
hex->activate();
|
||||
|
||||
if (attackingHero)
|
||||
attackingHero->activate();
|
||||
if (defendingHero)
|
||||
defendingHero->activate();
|
||||
|
||||
for (auto hex : bfield)
|
||||
hex->activate();
|
||||
|
||||
if (settings["battle"]["showQueue"].Bool())
|
||||
queue->activate();
|
||||
|
||||
|
@ -979,7 +979,7 @@ CMapHandler::AnimBitmapHolder CMapHandler::CMapBlitter::findHeroBitmap(const CGH
|
||||
if (hero->boat)
|
||||
animation = graphics->boatAnimations[hero->boat->subID];
|
||||
else
|
||||
animation = graphics->heroAnimations[hero->appearance.animationFile];
|
||||
animation = graphics->heroAnimations[hero->appearance->animationFile];
|
||||
|
||||
bool moving = !hero->isStanding;
|
||||
int group = getHeroFrameGroup(hero->moveDir, moving);
|
||||
@ -1486,8 +1486,8 @@ bool CMapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObj
|
||||
return true;
|
||||
if (!b)
|
||||
return false;
|
||||
if (a->appearance.printPriority != b->appearance.printPriority)
|
||||
return a->appearance.printPriority > b->appearance.printPriority;
|
||||
if (a->appearance->printPriority != b->appearance->printPriority)
|
||||
return a->appearance->printPriority > b->appearance->printPriority;
|
||||
|
||||
if(a->pos.y != b->pos.y)
|
||||
return a->pos.y < b->pos.y;
|
||||
|
@ -29,20 +29,20 @@ void QuickRecruitmentWindow::setButtons()
|
||||
|
||||
void QuickRecruitmentWindow::setCancelButton()
|
||||
{
|
||||
cancelButton = std::make_shared<CButton>(Point((pos.w / 2) + 48, 418), "ICN6432.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_RETURN);
|
||||
cancelButton = std::make_shared<CButton>(Point((pos.w / 2) + 48, 418), "ICN6432.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_ESCAPE);
|
||||
cancelButton->setImageOrder(0, 1, 2, 3);
|
||||
}
|
||||
|
||||
void QuickRecruitmentWindow::setBuyButton()
|
||||
{
|
||||
buyButton = std::make_shared<CButton>(Point((pos.w/2)-32, 418), "IBY6432.DEF", CButton::tooltip(), [&](){ purhaseUnits(); });
|
||||
buyButton = std::make_shared<CButton>(Point((pos.w/2)-32, 418), "IBY6432.DEF", CButton::tooltip(), [&](){ purhaseUnits(); }, SDLK_RETURN);
|
||||
cancelButton->assignedKeys.insert(SDLK_ESCAPE);
|
||||
buyButton->setImageOrder(0, 1, 2, 3);
|
||||
}
|
||||
|
||||
void QuickRecruitmentWindow::setMaxButton()
|
||||
{
|
||||
maxButton = std::make_shared<CButton>(Point((pos.w/2)-112, 418), "IRCBTNS.DEF", CButton::tooltip(), [&](){ maxAllCards(cards); });
|
||||
maxButton = std::make_shared<CButton>(Point((pos.w/2)-112, 418), "IRCBTNS.DEF", CButton::tooltip(), [&](){ maxAllCards(cards); }, SDLK_m);
|
||||
maxButton->setImageOrder(0, 1, 2, 3);
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,11 @@ bool CModEntry::isUpdateable() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CModEntry::isEssential() const
|
||||
{
|
||||
return getValue("storedLocaly").toBool();
|
||||
}
|
||||
|
||||
bool CModEntry::isInstalled() const
|
||||
{
|
||||
return !localData.isEmpty();
|
||||
@ -152,6 +157,10 @@ QVariantMap CModList::copyField(QVariantMap data, QString from, QString to)
|
||||
return renamed;
|
||||
}
|
||||
|
||||
void CModList::reloadRepositories()
|
||||
{
|
||||
}
|
||||
|
||||
void CModList::resetRepositories()
|
||||
{
|
||||
repositories.clear();
|
||||
@ -176,7 +185,7 @@ void CModList::modChanged(QString modID)
|
||||
{
|
||||
}
|
||||
|
||||
static QVariant getValue(QVariantMap input, QString path)
|
||||
static QVariant getValue(QVariant input, QString path)
|
||||
{
|
||||
if(path.size() > 1)
|
||||
{
|
||||
@ -184,7 +193,7 @@ static QVariant getValue(QVariantMap input, QString path)
|
||||
QString remainder = "/" + path.section('/', 2, -1);
|
||||
|
||||
entryName.remove(0, 1);
|
||||
return getValue(input.value(entryName).toMap(), remainder);
|
||||
return getValue(input.toMap().value(entryName), remainder);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -208,11 +217,29 @@ CModEntry CModList::getMod(QString modname) const
|
||||
}
|
||||
else
|
||||
{
|
||||
if(conf.canConvert<QVariantMap>())
|
||||
if(!conf.toMap().isEmpty())
|
||||
{
|
||||
settings = conf.toMap();
|
||||
if(settings.value("active").isNull())
|
||||
settings["active"] = true; // default
|
||||
}
|
||||
else
|
||||
settings.insert("active", conf);
|
||||
}
|
||||
|
||||
if(settings["active"].toBool())
|
||||
{
|
||||
QString rootPath = path.section('/', 0, 1);
|
||||
if(path != rootPath)
|
||||
{
|
||||
conf = getValue(modSettings, rootPath);
|
||||
const auto confMap = conf.toMap();
|
||||
if(!conf.isNull() && !confMap["active"].isNull() && !confMap["active"].toBool())
|
||||
{
|
||||
settings = confMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto entry : repositories)
|
||||
{
|
||||
|
@ -49,6 +49,8 @@ public:
|
||||
bool isUpdateable() const;
|
||||
// installed
|
||||
bool isInstalled() const;
|
||||
// vcmi essential files
|
||||
bool isEssential() const;
|
||||
|
||||
// see ModStatus enum
|
||||
int getModStatus() const;
|
||||
@ -74,6 +76,7 @@ class CModList
|
||||
|
||||
public:
|
||||
virtual void resetRepositories();
|
||||
virtual void reloadRepositories();
|
||||
virtual void addRepository(QVariantMap data);
|
||||
virtual void setLocalModList(QVariantMap data);
|
||||
virtual void setModSettings(QVariant data);
|
||||
|
@ -160,6 +160,12 @@ QVariant CModListModel::headerData(int section, Qt::Orientation orientation, int
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void CModListModel::reloadRepositories()
|
||||
{
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void CModListModel::resetRepositories()
|
||||
{
|
||||
beginResetModel();
|
||||
|
@ -61,6 +61,7 @@ public:
|
||||
|
||||
/// CModListContainer overrides
|
||||
void resetRepositories() override;
|
||||
void reloadRepositories() override;
|
||||
void addRepository(QVariantMap data) override;
|
||||
void modChanged(QString modID) override;
|
||||
|
||||
|
@ -310,10 +310,10 @@ void CModListView::selectMod(const QModelIndex & index)
|
||||
// Block buttons if action is not allowed at this time
|
||||
// TODO: automate handling of some of these cases instead of forcing player
|
||||
// to resolve all conflicts manually.
|
||||
ui->disableButton->setEnabled(!hasDependentMods);
|
||||
ui->disableButton->setEnabled(!hasDependentMods && !mod.isEssential());
|
||||
ui->enableButton->setEnabled(!hasBlockingMods && !hasInvalidDeps);
|
||||
ui->installButton->setEnabled(!hasInvalidDeps);
|
||||
ui->uninstallButton->setEnabled(!hasDependentMods);
|
||||
ui->uninstallButton->setEnabled(!hasDependentMods && !mod.isEssential());
|
||||
ui->updateButton->setEnabled(!hasInvalidDeps && !hasDependentMods);
|
||||
|
||||
loadScreenshots();
|
||||
@ -522,6 +522,9 @@ void CModListView::downloadFile(QString file, QString url, QString description)
|
||||
|
||||
connect(dlManager, SIGNAL(finished(QStringList,QStringList,QStringList)),
|
||||
this, SLOT(downloadFinished(QStringList,QStringList,QStringList)));
|
||||
|
||||
|
||||
connect(modModel, &CModListModel::dataChanged, filterModel, &QAbstractItemModel::dataChanged);
|
||||
|
||||
|
||||
QString progressBarFormat = "Downloading %s%. %p% (%v KB out of %m KB) finished";
|
||||
@ -658,7 +661,7 @@ void CModListView::installMods(QStringList archives)
|
||||
auto mod = modModel->getMod(modName);
|
||||
if(mod.isInstalled() && !mod.getValue("keepDisabled").toBool())
|
||||
{
|
||||
if(manager->enableMod(modName))
|
||||
if(mod.isDisabled() && manager->enableMod(modName))
|
||||
{
|
||||
for(QString child : modModel->getChildren(modName))
|
||||
enableMod(child);
|
||||
|
@ -74,6 +74,7 @@ void CModManager::loadMods()
|
||||
CModHandler handler;
|
||||
handler.loadMods();
|
||||
auto installedMods = handler.getAllMods();
|
||||
localMods.clear();
|
||||
|
||||
for(auto modname : installedMods)
|
||||
{
|
||||
@ -82,6 +83,13 @@ void CModManager::loadMods()
|
||||
{
|
||||
boost::filesystem::path name = *CResourceHandler::get()->getResourceName(resID);
|
||||
auto mod = JsonUtils::JsonFromFile(pathToQString(name));
|
||||
if(!name.is_absolute())
|
||||
{
|
||||
auto json = JsonUtils::toJson(mod);
|
||||
json["storedLocaly"].Bool() = true;
|
||||
mod = JsonUtils::toVariant(json);
|
||||
}
|
||||
|
||||
localMods.insert(QString::fromUtf8(modname.c_str()).toLower(), mod);
|
||||
}
|
||||
}
|
||||
@ -269,12 +277,10 @@ bool CModManager::doInstallMod(QString modname, QString archivePath)
|
||||
QString upperLevel = modDirName.section('/', 0, 0);
|
||||
if(upperLevel != modDirName)
|
||||
removeModDir(destDir + upperLevel);
|
||||
|
||||
QVariantMap json = JsonUtils::JsonFromFile(destDir + modname + "/mod.json").toMap();
|
||||
|
||||
localMods.insert(modname, json);
|
||||
modList->setLocalModList(localMods);
|
||||
modList->modChanged(modname);
|
||||
|
||||
CResourceHandler::get("initial")->updateFilteredFiles([](const std::string &) { return true; });
|
||||
loadMods();
|
||||
modList->reloadRepositories();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -288,16 +294,13 @@ bool CModManager::doUninstallMod(QString modname)
|
||||
if(!QDir(modDir).exists())
|
||||
return addError(modname, "Data with this mod was not found");
|
||||
|
||||
if(!localMods.contains(modname))
|
||||
return addError(modname, "Data with this mod was not found");
|
||||
|
||||
QDir modFullDir(modDir);
|
||||
if(!removeModDir(modDir))
|
||||
return addError(modname, "Mod is located in protected directory, plase remove it manually:\n" + modFullDir.absolutePath());
|
||||
|
||||
localMods.remove(modname);
|
||||
modList->setLocalModList(localMods);
|
||||
modList->modChanged(modname);
|
||||
CResourceHandler::get("initial")->updateFilteredFiles([](const std::string &){ return true; });
|
||||
loadMods();
|
||||
modList->reloadRepositories();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -842,10 +842,22 @@ void CHeroHandler::loadObstacles()
|
||||
allConfigs.insert(allConfigs.begin(), "core");
|
||||
for(auto & mod : allConfigs)
|
||||
{
|
||||
if(!CResourceHandler::get(mod)->existsResource(ResourceID("config/obstacles.json")))
|
||||
ISimpleResourceLoader * modResourceLoader;
|
||||
try
|
||||
{
|
||||
modResourceLoader = CResourceHandler::get(mod);
|
||||
}
|
||||
catch(const std::out_of_range &)
|
||||
{
|
||||
logMod->warn("Mod '%1%' doesn't exist! Its obstacles won't be loaded!", mod);
|
||||
continue;
|
||||
}
|
||||
|
||||
const ResourceID obstaclesResource{"config/obstacles.json"};
|
||||
if(!modResourceLoader->existsResource(obstaclesResource))
|
||||
continue;
|
||||
|
||||
const JsonNode config(mod, ResourceID("config/obstacles.json"));
|
||||
const JsonNode config(mod, obstaclesResource);
|
||||
loadObstacles(config["obstacles"], false, obstacles);
|
||||
loadObstacles(config["absoluteObstacles"], true, absoluteObstacles);
|
||||
}
|
||||
|
@ -16,9 +16,10 @@
|
||||
namespace bfs = boost::filesystem;
|
||||
|
||||
CFilesystemLoader::CFilesystemLoader(std::string _mountPoint, bfs::path baseDirectory, size_t depth, bool initial):
|
||||
baseDirectory(std::move(baseDirectory)),
|
||||
mountPoint(std::move(_mountPoint)),
|
||||
fileList(listFiles(mountPoint, depth, initial))
|
||||
baseDirectory(std::move(baseDirectory)),
|
||||
mountPoint(std::move(_mountPoint)),
|
||||
fileList(listFiles(mountPoint, depth, initial)),
|
||||
recursiveDepth(depth)
|
||||
{
|
||||
logGlobal->trace("File system loaded, %d files found", fileList.size());
|
||||
}
|
||||
@ -52,7 +53,7 @@ void CFilesystemLoader::updateFilteredFiles(std::function<bool(const std::string
|
||||
{
|
||||
if (filter(mountPoint))
|
||||
{
|
||||
fileList = listFiles(mountPoint, 1, false);
|
||||
fileList = listFiles(mountPoint, recursiveDepth, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,8 @@ private:
|
||||
boost::filesystem::path baseDirectory;
|
||||
|
||||
std::string mountPoint;
|
||||
|
||||
size_t recursiveDepth;
|
||||
|
||||
/** A list of files in the directory
|
||||
* key = ResourceID for resource loader
|
||||
|
@ -450,9 +450,8 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const
|
||||
{
|
||||
int txt_id;
|
||||
|
||||
if (cb->getHeroCount(h->tempOwner, false) < VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER)//GameConstants::MAX_HEROES_PER_PLAYER) //free hero slot
|
||||
if (cb->getHeroCount(h->tempOwner, false) < VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER)//free hero slot
|
||||
{
|
||||
cb->changeObjPos(id,pos+int3(1,0,0),0);
|
||||
//update hero parameters
|
||||
SetMovePoints smp;
|
||||
smp.hid = id;
|
||||
@ -534,7 +533,7 @@ void CGHeroInstance::initObj(CRandomGenerator & rand)
|
||||
{
|
||||
auto customApp = VLC->objtypeh->getHandlerFor(ID, type->heroClass->getIndex())->getOverride(cb->gameState()->getTile(visitablePos())->terType, this);
|
||||
if (customApp)
|
||||
appearance = customApp.get();
|
||||
appearance = customApp;
|
||||
}
|
||||
|
||||
//copy active (probably growing) bonuses from hero prototype to hero object
|
||||
@ -1418,7 +1417,9 @@ void CGHeroInstance::setHeroTypeName(const std::string & identifier)
|
||||
if(rawId)
|
||||
subID = rawId.get();
|
||||
else
|
||||
subID = 0; //fallback to Orrin, throw error instead?
|
||||
{
|
||||
throw std::runtime_error("Couldn't resolve hero identifier " + identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1133,7 +1133,7 @@ void CGTownInstance::updateAppearance()
|
||||
//FIXME: not the best way to do this
|
||||
auto app = VLC->objtypeh->getHandlerFor(ID, subID)->getOverride(cb->gameState()->getTile(visitablePos())->terType, this);
|
||||
if (app)
|
||||
appearance = app.get();
|
||||
appearance = app;
|
||||
}
|
||||
|
||||
std::string CGTownInstance::nodeName() const
|
||||
|
@ -117,11 +117,11 @@ std::vector<JsonNode> CObjectClassesHandler::loadLegacyData(size_t dataSize)
|
||||
|
||||
for (size_t i=0; i<totalNumber; i++)
|
||||
{
|
||||
ObjectTemplate templ;
|
||||
templ.readTxt(parser);
|
||||
auto templ = new ObjectTemplate;
|
||||
templ->readTxt(parser);
|
||||
parser.endLine();
|
||||
std::pair<si32, si32> key(templ.id.num, templ.subid);
|
||||
legacyTemplates.insert(std::make_pair(key, templ));
|
||||
std::pair<si32, si32> key(templ->id.num, templ->subid);
|
||||
legacyTemplates.insert(std::make_pair(key, std::shared_ptr<const ObjectTemplate>(templ)));
|
||||
}
|
||||
|
||||
std::vector<JsonNode> ret(dataSize);// create storage for 256 objects
|
||||
@ -448,7 +448,6 @@ AObjectTypeHandler::AObjectTypeHandler():
|
||||
|
||||
AObjectTypeHandler::~AObjectTypeHandler()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AObjectTypeHandler::setType(si32 type, si32 subtype)
|
||||
@ -488,12 +487,12 @@ void AObjectTypeHandler::init(const JsonNode & input, boost::optional<std::strin
|
||||
entry.second.setType(JsonNode::JsonType::DATA_STRUCT);
|
||||
JsonUtils::inherit(entry.second, base);
|
||||
|
||||
ObjectTemplate tmpl;
|
||||
tmpl.id = Obj(type);
|
||||
tmpl.subid = subtype;
|
||||
tmpl.stringID = entry.first; // FIXME: create "fullID" - type.object.template?
|
||||
tmpl.readJson(entry.second);
|
||||
templates.push_back(tmpl);
|
||||
auto tmpl = new ObjectTemplate;
|
||||
tmpl->id = Obj(type);
|
||||
tmpl->subid = subtype;
|
||||
tmpl->stringID = entry.first; // FIXME: create "fullID" - type.object.template?
|
||||
tmpl->readJson(entry.second);
|
||||
templates.push_back(std::shared_ptr<const ObjectTemplate>(tmpl));
|
||||
}
|
||||
|
||||
if (input["name"].isNull())
|
||||
@ -523,7 +522,7 @@ void AObjectTypeHandler::init(const JsonNode & input, boost::optional<std::strin
|
||||
initTypeData(input);
|
||||
}
|
||||
|
||||
bool AObjectTypeHandler::objectFilter(const CGObjectInstance *, const ObjectTemplate &) const
|
||||
bool AObjectTypeHandler::objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const
|
||||
{
|
||||
return false; // by default there are no overrides
|
||||
}
|
||||
@ -551,26 +550,28 @@ SObjectSounds AObjectTypeHandler::getSounds() const
|
||||
return sounds;
|
||||
}
|
||||
|
||||
void AObjectTypeHandler::addTemplate(const ObjectTemplate & templ)
|
||||
void AObjectTypeHandler::addTemplate(std::shared_ptr<const ObjectTemplate> templ)
|
||||
{
|
||||
//Otherwise the template remains constant
|
||||
auto ptr = const_cast<ObjectTemplate*>(templ.get());
|
||||
ptr->id = Obj(type);
|
||||
ptr->subid = subtype;
|
||||
templates.push_back(templ);
|
||||
templates.back().id = Obj(type);
|
||||
templates.back().subid = subtype;
|
||||
}
|
||||
|
||||
void AObjectTypeHandler::addTemplate(JsonNode config)
|
||||
{
|
||||
config.setType(JsonNode::JsonType::DATA_STRUCT); // ensure that input is not null
|
||||
JsonUtils::inherit(config, base);
|
||||
ObjectTemplate tmpl;
|
||||
tmpl.id = Obj(type);
|
||||
tmpl.subid = subtype;
|
||||
tmpl.stringID = ""; // TODO?
|
||||
tmpl.readJson(config);
|
||||
templates.push_back(tmpl);
|
||||
auto tmpl = new ObjectTemplate;
|
||||
tmpl->id = Obj(type);
|
||||
tmpl->subid = subtype;
|
||||
tmpl->stringID = ""; // TODO?
|
||||
tmpl->readJson(config);
|
||||
templates.emplace_back(tmpl);
|
||||
}
|
||||
|
||||
std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates() const
|
||||
std::vector<std::shared_ptr<const ObjectTemplate>> AObjectTypeHandler::getTemplates() const
|
||||
{
|
||||
return templates;
|
||||
}
|
||||
@ -580,14 +581,14 @@ BattleField AObjectTypeHandler::getBattlefield() const
|
||||
return battlefield ? BattleField::fromString(battlefield.get()) : BattleField::NONE;
|
||||
}
|
||||
|
||||
std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates(const Terrain & terrainType) const
|
||||
std::vector<std::shared_ptr<const ObjectTemplate>>AObjectTypeHandler::getTemplates(const Terrain & terrainType) const
|
||||
{
|
||||
std::vector<ObjectTemplate> templates = getTemplates();
|
||||
std::vector<ObjectTemplate> filtered;
|
||||
std::vector<std::shared_ptr<const ObjectTemplate>> templates = getTemplates();
|
||||
std::vector<std::shared_ptr<const ObjectTemplate>> filtered;
|
||||
|
||||
std::copy_if(templates.begin(), templates.end(), std::back_inserter(filtered), [&](const ObjectTemplate & obj)
|
||||
std::copy_if(templates.begin(), templates.end(), std::back_inserter(filtered), [&](std::shared_ptr<const ObjectTemplate> obj)
|
||||
{
|
||||
return obj.canBePlacedAt(terrainType);
|
||||
return obj->canBePlacedAt(terrainType);
|
||||
});
|
||||
// H3 defines allowed terrains in a weird way - artifacts, monsters and resources have faulty masks here
|
||||
// Perhaps we should re-define faulty templates and remove this workaround (already done for resources)
|
||||
@ -597,15 +598,15 @@ std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates(const Terrain & ter
|
||||
return filtered;
|
||||
}
|
||||
|
||||
boost::optional<ObjectTemplate> AObjectTypeHandler::getOverride(const Terrain & terrainType, const CGObjectInstance * object) const
|
||||
std::shared_ptr<const ObjectTemplate> AObjectTypeHandler::getOverride(const Terrain & terrainType, const CGObjectInstance * object) const
|
||||
{
|
||||
std::vector<ObjectTemplate> ret = getTemplates(terrainType);
|
||||
for (auto & tmpl : ret)
|
||||
std::vector<std::shared_ptr<const ObjectTemplate>> ret = getTemplates(terrainType);
|
||||
for (const auto & tmpl: ret)
|
||||
{
|
||||
if (objectFilter(object, tmpl))
|
||||
return tmpl;
|
||||
}
|
||||
return boost::optional<ObjectTemplate>();
|
||||
return std::shared_ptr<const ObjectTemplate>(); //empty
|
||||
}
|
||||
|
||||
const RandomMapInfo & AObjectTypeHandler::getRMGInfo()
|
||||
|
@ -144,7 +144,7 @@ class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable
|
||||
|
||||
JsonNode base; /// describes base template
|
||||
|
||||
std::vector<ObjectTemplate> templates;
|
||||
std::vector<std::shared_ptr<const ObjectTemplate>> templates;
|
||||
|
||||
SObjectSounds sounds;
|
||||
|
||||
@ -154,7 +154,7 @@ class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable
|
||||
|
||||
protected:
|
||||
void preInitObject(CGObjectInstance * obj) const;
|
||||
virtual bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const;
|
||||
virtual bool objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const;
|
||||
|
||||
/// initialization for classes that inherit this one
|
||||
virtual void initTypeData(const JsonNode & input);
|
||||
@ -177,17 +177,21 @@ public:
|
||||
boost::optional<std::string> getCustomName() const;
|
||||
SObjectSounds getSounds() const;
|
||||
|
||||
void addTemplate(const ObjectTemplate & templ);
|
||||
void addTemplate(std::shared_ptr<const ObjectTemplate> templ);
|
||||
void addTemplate(JsonNode config);
|
||||
|
||||
/// returns all templates matching parameters
|
||||
std::vector<ObjectTemplate> getTemplates() const;
|
||||
std::vector<ObjectTemplate> getTemplates(const Terrain & terrainType) const;
|
||||
std::vector<std::shared_ptr<const ObjectTemplate>> getTemplates() const;
|
||||
std::vector<std::shared_ptr<const ObjectTemplate>> getTemplates(const Terrain & terrainType) const;
|
||||
|
||||
/// returns preferred template for this object, if present (e.g. one of 3 possible templates for town - village, fort and castle)
|
||||
/// note that appearance will not be changed - this must be done separately (either by assignment or via pack from server)
|
||||
std::shared_ptr<const ObjectTemplate> getOverride(const Terrain & terrainType, const CGObjectInstance * object) const;
|
||||
|
||||
BattleField getBattlefield() const;
|
||||
|
||||
/// returns preferred template for this object, if present (e.g. one of 3 possible templates for town - village, fort and castle)
|
||||
/// note that appearance will not be changed - this must be done separately (either by assignment or via pack from server)
|
||||
boost::optional<ObjectTemplate> getOverride(const Terrain & terrainType, const CGObjectInstance * object) const;
|
||||
|
||||
const RandomMapInfo & getRMGInfo();
|
||||
|
||||
@ -199,14 +203,14 @@ public:
|
||||
|
||||
/// Creates object and set up core properties (like ID/subID). Object is NOT initialized
|
||||
/// to allow creating objects before game start (e.g. map loading)
|
||||
virtual CGObjectInstance * create(const ObjectTemplate & tmpl) const = 0;
|
||||
virtual CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const = 0;
|
||||
|
||||
/// Configures object properties. Should be re-entrable, resetting state of the object if necessarily
|
||||
/// This should set remaining properties, including randomized or depending on map
|
||||
virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const = 0;
|
||||
|
||||
/// Returns object configuration, if available. Otherwise returns NULL
|
||||
virtual std::unique_ptr<IObjectInfo> getObjectInfo(const ObjectTemplate & tmpl) const = 0;
|
||||
virtual std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const = 0;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
@ -264,7 +268,7 @@ class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase
|
||||
std::map<std::string, std::function<TObjectTypeHandler()> > handlerConstructors;
|
||||
|
||||
/// container with H3 templates, used only during loading, no need to serialize it
|
||||
typedef std::multimap<std::pair<si32, si32>, ObjectTemplate> TTemplatesContainer;
|
||||
typedef std::multimap<std::pair<si32, si32>, std::shared_ptr<const ObjectTemplate>> TTemplatesContainer;
|
||||
TTemplatesContainer legacyTemplates;
|
||||
|
||||
/// contains list of custom names for H3 objects (e.g. Dwellings), used to load H3 data
|
||||
|
@ -152,24 +152,24 @@ void CGObjectInstance::setOwner(PlayerColor ow)
|
||||
}
|
||||
int CGObjectInstance::getWidth() const//returns width of object graphic in tiles
|
||||
{
|
||||
return appearance.getWidth();
|
||||
return appearance->getWidth();
|
||||
}
|
||||
int CGObjectInstance::getHeight() const //returns height of object graphic in tiles
|
||||
{
|
||||
return appearance.getHeight();
|
||||
return appearance->getHeight();
|
||||
}
|
||||
bool CGObjectInstance::visitableAt(int x, int y) const //returns true if object is visitable at location (x, y) form left top tile of image (x, y in tiles)
|
||||
{
|
||||
return appearance.isVisitableAt(pos.x - x, pos.y - y);
|
||||
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);
|
||||
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);
|
||||
return appearance->isVisibleAt(pos.x - x, pos.y - y);
|
||||
}
|
||||
|
||||
std::set<int3> CGObjectInstance::getBlockedPos() const
|
||||
@ -179,7 +179,7 @@ std::set<int3> CGObjectInstance::getBlockedPos() const
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
@ -188,7 +188,7 @@ std::set<int3> CGObjectInstance::getBlockedPos() const
|
||||
|
||||
std::set<int3> CGObjectInstance::getBlockedOffsets() const
|
||||
{
|
||||
return appearance.getBlockedOffsets();
|
||||
return appearance->getBlockedOffsets();
|
||||
}
|
||||
|
||||
void CGObjectInstance::setType(si32 ID, si32 subID)
|
||||
@ -210,6 +210,11 @@ void CGObjectInstance::setType(si32 ID, si32 subID)
|
||||
appearance = handler->getTemplates(tile.terType)[0];
|
||||
else
|
||||
appearance = handler->getTemplates()[0]; // get at least some appearance since alternative is crash
|
||||
if (ID == Obj::HERO)
|
||||
{
|
||||
//adjust for the prison offset
|
||||
pos = visitablePos();
|
||||
}
|
||||
cb->gameState()->map->addBlockVisTiles(this);
|
||||
}
|
||||
|
||||
@ -259,7 +264,7 @@ int CGObjectInstance::getSightRadius() const
|
||||
|
||||
int3 CGObjectInstance::getVisitableOffset() const
|
||||
{
|
||||
return appearance.getVisitableOffset();
|
||||
return appearance->getVisitableOffset();
|
||||
}
|
||||
|
||||
void CGObjectInstance::giveDummyBonus(ObjectInstanceID heroID, ui8 duration) const
|
||||
@ -345,7 +350,7 @@ int3 CGObjectInstance::visitablePos() const
|
||||
|
||||
bool CGObjectInstance::isVisitable() const
|
||||
{
|
||||
return appearance.isVisitable();
|
||||
return appearance->isVisitable();
|
||||
}
|
||||
|
||||
bool CGObjectInstance::passableFor(PlayerColor color) const
|
||||
@ -370,7 +375,7 @@ void CGObjectInstance::serializeJson(JsonSerializeFormat & handler)
|
||||
handler.serializeInt("y", pos.y);
|
||||
handler.serializeInt("l", pos.z);
|
||||
JsonNode app;
|
||||
appearance.writeJson(app, false);
|
||||
appearance->writeJson(app, false);
|
||||
handler.serializeRaw("template",app, boost::none);
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ public:
|
||||
/// Index of object in map's list of objects
|
||||
ObjectInstanceID id;
|
||||
/// Defines appearance of object on map (animation, blocked tiles, blit order, etc)
|
||||
ObjectTemplate appearance;
|
||||
std::shared_ptr<const ObjectTemplate> appearance;
|
||||
/// If true hero can visit this object only from neighbouring tiles and can't stand on this object
|
||||
bool blockVisit;
|
||||
|
||||
|
@ -183,7 +183,7 @@ void CRewardableConstructor::initTypeData(const JsonNode & config)
|
||||
objectInfo.init(config);
|
||||
}
|
||||
|
||||
CGObjectInstance * CRewardableConstructor::create(const ObjectTemplate & tmpl) const
|
||||
CGObjectInstance * CRewardableConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
{
|
||||
auto ret = new CRewardableObject();
|
||||
preInitObject(ret);
|
||||
@ -196,7 +196,7 @@ void CRewardableConstructor::configureObject(CGObjectInstance * object, CRandomG
|
||||
objectInfo.configureObject(dynamic_cast<CRewardableObject*>(object), rng);
|
||||
}
|
||||
|
||||
std::unique_ptr<IObjectInfo> CRewardableConstructor::getObjectInfo(const ObjectTemplate & tmpl) const
|
||||
std::unique_ptr<IObjectInfo> CRewardableConstructor::getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
{
|
||||
return std::unique_ptr<IObjectInfo>(new CRandomRewardObjectInfo(objectInfo));
|
||||
}
|
||||
|
@ -49,9 +49,9 @@ class DLL_LINKAGE CRewardableConstructor : public AObjectTypeHandler
|
||||
public:
|
||||
CRewardableConstructor();
|
||||
|
||||
CGObjectInstance * create(const ObjectTemplate & tmpl) const override;
|
||||
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
|
||||
|
||||
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
|
||||
|
||||
std::unique_ptr<IObjectInfo> getObjectInfo(const ObjectTemplate & tmpl) const override;
|
||||
std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const override;
|
||||
};
|
||||
|
@ -1122,7 +1122,7 @@ std::vector<int3> CGMagicSpring::getVisitableOffsets() const
|
||||
|
||||
for(int y = 0; y < 6; y++)
|
||||
for (int x = 0; x < 8; x++) //starting from left
|
||||
if (appearance.isVisitableAt(x, y))
|
||||
if (appearance->isVisitableAt(x, y))
|
||||
visitableTiles.push_back (int3(x, y , 0));
|
||||
|
||||
return visitableTiles;
|
||||
|
@ -56,7 +56,7 @@ void CTownInstanceConstructor::afterLoadFinalization()
|
||||
}
|
||||
}
|
||||
|
||||
bool CTownInstanceConstructor::objectFilter(const CGObjectInstance * object, const ObjectTemplate & templ) const
|
||||
bool CTownInstanceConstructor::objectFilter(const CGObjectInstance * object, std::shared_ptr<const ObjectTemplate> templ) const
|
||||
{
|
||||
auto town = dynamic_cast<const CGTownInstance *>(object);
|
||||
|
||||
@ -65,10 +65,10 @@ bool CTownInstanceConstructor::objectFilter(const CGObjectInstance * object, con
|
||||
return town->hasBuilt(id);
|
||||
};
|
||||
|
||||
return filters.count(templ.stringID) != 0 && filters.at(templ.stringID).test(buildTest);
|
||||
return filters.count(templ->stringID) != 0 && filters.at(templ->stringID).test(buildTest);
|
||||
}
|
||||
|
||||
CGObjectInstance * CTownInstanceConstructor::create(const ObjectTemplate & tmpl) const
|
||||
CGObjectInstance * CTownInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
{
|
||||
CGTownInstance * obj = createTyped(tmpl);
|
||||
obj->town = faction->town;
|
||||
@ -80,7 +80,7 @@ void CTownInstanceConstructor::configureObject(CGObjectInstance * object, CRando
|
||||
{
|
||||
auto templ = getOverride(object->cb->getTile(object->pos)->terType, object);
|
||||
if(templ)
|
||||
object->appearance = templ.get();
|
||||
object->appearance = templ;
|
||||
}
|
||||
|
||||
CHeroInstanceConstructor::CHeroInstanceConstructor()
|
||||
@ -110,7 +110,7 @@ void CHeroInstanceConstructor::afterLoadFinalization()
|
||||
}
|
||||
}
|
||||
|
||||
bool CHeroInstanceConstructor::objectFilter(const CGObjectInstance * object, const ObjectTemplate & templ) const
|
||||
bool CHeroInstanceConstructor::objectFilter(const CGObjectInstance * object, std::shared_ptr<const ObjectTemplate> templ) const
|
||||
{
|
||||
auto hero = dynamic_cast<const CGHeroInstance *>(object);
|
||||
|
||||
@ -119,14 +119,14 @@ bool CHeroInstanceConstructor::objectFilter(const CGObjectInstance * object, con
|
||||
return hero->type->ID == id;
|
||||
};
|
||||
|
||||
if(filters.count(templ.stringID))
|
||||
if(filters.count(templ->stringID))
|
||||
{
|
||||
return filters.at(templ.stringID).test(heroTest);
|
||||
return filters.at(templ->stringID).test(heroTest);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CGObjectInstance * CHeroInstanceConstructor::create(const ObjectTemplate & tmpl) const
|
||||
CGObjectInstance * CHeroInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
{
|
||||
CGHeroInstance * obj = createTyped(tmpl);
|
||||
obj->type = nullptr; //FIXME: set to valid value. somehow.
|
||||
@ -167,12 +167,12 @@ void CDwellingInstanceConstructor::initTypeData(const JsonNode & input)
|
||||
guards = input["guards"];
|
||||
}
|
||||
|
||||
bool CDwellingInstanceConstructor::objectFilter(const CGObjectInstance *, const ObjectTemplate &) const
|
||||
bool CDwellingInstanceConstructor::objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CGObjectInstance * CDwellingInstanceConstructor::create(const ObjectTemplate & tmpl) const
|
||||
CGObjectInstance * CDwellingInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
{
|
||||
CGDwelling * obj = createTyped(tmpl);
|
||||
|
||||
@ -272,7 +272,7 @@ void CBankInstanceConstructor::initTypeData(const JsonNode & input)
|
||||
bankResetDuration = static_cast<si32>(input["resetDuration"].Float());
|
||||
}
|
||||
|
||||
CGObjectInstance *CBankInstanceConstructor::create(const ObjectTemplate & tmpl) const
|
||||
CGObjectInstance *CBankInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
{
|
||||
return createTyped(tmpl);
|
||||
}
|
||||
@ -494,7 +494,7 @@ bool CBankInfo::givesSpells() const
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<IObjectInfo> CBankInstanceConstructor::getObjectInfo(const ObjectTemplate & tmpl) const
|
||||
std::unique_ptr<IObjectInfo> CBankInstanceConstructor::getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
{
|
||||
return std::unique_ptr<IObjectInfo>(new CBankInfo(levels));
|
||||
}
|
||||
|
@ -26,17 +26,31 @@ template<class ObjectType>
|
||||
class CDefaultObjectTypeHandler : public AObjectTypeHandler
|
||||
{
|
||||
protected:
|
||||
ObjectType * createTyped(const ObjectTemplate & tmpl) const
|
||||
ObjectType * createTyped(std::shared_ptr<const ObjectTemplate> tmpl /* = nullptr */) const
|
||||
{
|
||||
auto obj = new ObjectType();
|
||||
preInitObject(obj);
|
||||
obj->appearance = tmpl;
|
||||
|
||||
if (tmpl)
|
||||
{
|
||||
obj->appearance = tmpl;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto templates = getTemplates();
|
||||
if (templates.empty())
|
||||
{
|
||||
throw std::runtime_error("No handler for created object");
|
||||
}
|
||||
obj->appearance = templates.front(); //just any template for now, will be initialized later
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
public:
|
||||
CDefaultObjectTypeHandler() {}
|
||||
|
||||
CGObjectInstance * create(const ObjectTemplate & tmpl) const override
|
||||
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override
|
||||
{
|
||||
return createTyped(tmpl);
|
||||
}
|
||||
@ -45,7 +59,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<IObjectInfo> getObjectInfo(const ObjectTemplate & tmpl) const override
|
||||
virtual std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@ -62,7 +76,7 @@ class CTownInstanceConstructor : public CDefaultObjectTypeHandler<CGTownInstance
|
||||
{
|
||||
JsonNode filtersJson;
|
||||
protected:
|
||||
bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const override;
|
||||
bool objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const override;
|
||||
void initTypeData(const JsonNode & input) override;
|
||||
|
||||
public:
|
||||
@ -70,7 +84,7 @@ public:
|
||||
std::map<std::string, LogicalExpression<BuildingID>> filters;
|
||||
|
||||
CTownInstanceConstructor();
|
||||
CGObjectInstance * create(const ObjectTemplate & tmpl) const override;
|
||||
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
|
||||
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
|
||||
void afterLoadFinalization() override;
|
||||
|
||||
@ -87,7 +101,7 @@ class CHeroInstanceConstructor : public CDefaultObjectTypeHandler<CGHeroInstance
|
||||
{
|
||||
JsonNode filtersJson;
|
||||
protected:
|
||||
bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const override;
|
||||
bool objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const override;
|
||||
void initTypeData(const JsonNode & input) override;
|
||||
|
||||
public:
|
||||
@ -95,7 +109,7 @@ public:
|
||||
std::map<std::string, LogicalExpression<HeroTypeID>> filters;
|
||||
|
||||
CHeroInstanceConstructor();
|
||||
CGObjectInstance * create(const ObjectTemplate & tmpl) const override;
|
||||
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
|
||||
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
|
||||
void afterLoadFinalization() override;
|
||||
|
||||
@ -115,13 +129,13 @@ class CDwellingInstanceConstructor : public CDefaultObjectTypeHandler<CGDwelling
|
||||
JsonNode guards;
|
||||
|
||||
protected:
|
||||
bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const override;
|
||||
bool objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate> tmpl) const override;
|
||||
void initTypeData(const JsonNode & input) override;
|
||||
|
||||
public:
|
||||
|
||||
CDwellingInstanceConstructor();
|
||||
CGObjectInstance * create(const ObjectTemplate & tmpl) const override;
|
||||
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
|
||||
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
|
||||
|
||||
bool producesCreature(const CCreature * crea) const;
|
||||
@ -207,10 +221,10 @@ public:
|
||||
|
||||
CBankInstanceConstructor();
|
||||
|
||||
CGObjectInstance * create(const ObjectTemplate & tmpl) const override;
|
||||
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
|
||||
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
|
||||
|
||||
std::unique_ptr<IObjectInfo> getObjectInfo(const ObjectTemplate & tmpl) const override;
|
||||
std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
|
@ -53,7 +53,9 @@ ObjectTemplate::ObjectTemplate():
|
||||
id(Obj::NO_OBJ),
|
||||
subid(0),
|
||||
printPriority(0),
|
||||
stringID("")
|
||||
width(0),
|
||||
height(0),
|
||||
visitable(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -65,7 +67,13 @@ ObjectTemplate::ObjectTemplate(const ObjectTemplate& other):
|
||||
printPriority(other.printPriority),
|
||||
animationFile(other.animationFile),
|
||||
editorAnimationFile(other.editorAnimationFile),
|
||||
stringID(other.stringID)
|
||||
stringID(other.stringID),
|
||||
width(other.width),
|
||||
height(other.height),
|
||||
visitable(other.visitable),
|
||||
blockedOffsets(other.blockedOffsets),
|
||||
blockMapOffset(other.blockMapOffset),
|
||||
visitableOffset(other.visitableOffset)
|
||||
{
|
||||
//default copy constructor is failing with usedTiles this for unknown reason
|
||||
|
||||
@ -84,11 +92,18 @@ ObjectTemplate & ObjectTemplate::operator=(const ObjectTemplate & rhs)
|
||||
animationFile = rhs.animationFile;
|
||||
editorAnimationFile = rhs.editorAnimationFile;
|
||||
stringID = rhs.stringID;
|
||||
width = rhs.width;
|
||||
height = rhs.height;
|
||||
visitable = rhs.visitable;
|
||||
blockedOffsets = rhs.blockedOffsets;
|
||||
blockMapOffset = rhs.blockMapOffset;
|
||||
visitableOffset = rhs.visitableOffset;
|
||||
|
||||
usedTiles.clear();
|
||||
usedTiles.resize(rhs.usedTiles.size());
|
||||
for(size_t i = 0; i < usedTiles.size(); i++)
|
||||
std::copy(rhs.usedTiles[i].begin(), rhs.usedTiles[i].end(), std::back_inserter(usedTiles[i]));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -121,9 +136,9 @@ void ObjectTemplate::readTxt(CLegacyConfigParser & parser)
|
||||
assert(visitStr.size() == 6*8);
|
||||
|
||||
setSize(8, 6);
|
||||
for (size_t i=0; i<6; i++) // 6 rows
|
||||
for(size_t i = 0; i < 6; i++) // 6 rows
|
||||
{
|
||||
for (size_t j=0; j<8; j++) // 8 columns
|
||||
for(size_t j = 0; j < 8; j++) // 8 columns
|
||||
{
|
||||
auto & tile = usedTiles[i][j];
|
||||
tile |= VISIBLE; // assume that all tiles are visible
|
||||
@ -141,7 +156,7 @@ void ObjectTemplate::readTxt(CLegacyConfigParser & parser)
|
||||
std::string & terrStr = strings[4]; // allowed terrains, 1 = object can be placed on this terrain
|
||||
|
||||
assert(terrStr.size() == 9); // all terrains but rock
|
||||
for (size_t i=0; i<9; i++)
|
||||
for(size_t i = 0; i < 9; i++)
|
||||
{
|
||||
if (terrStr[8-i] == '1')
|
||||
allowedTerrains.insert(Terrain::createTerrainTypeH3M(i));
|
||||
@ -168,6 +183,7 @@ void ObjectTemplate::readTxt(CLegacyConfigParser & parser)
|
||||
visitDir = (8|16|32|64|128);
|
||||
|
||||
readMsk();
|
||||
recalculate();
|
||||
}
|
||||
|
||||
void ObjectTemplate::readMsk()
|
||||
@ -197,9 +213,9 @@ void ObjectTemplate::readMap(CBinaryReader & reader)
|
||||
for(auto & byte : visitMask)
|
||||
byte = reader.readUInt8();
|
||||
|
||||
for (size_t i=0; i<6; i++) // 6 rows
|
||||
for(size_t i = 0; i < 6; i++) // 6 rows
|
||||
{
|
||||
for (size_t j=0; j<8; j++) // 8 columns
|
||||
for(size_t j = 0; j < 8; j++) // 8 columns
|
||||
{
|
||||
auto & tile = usedTiles[5 - i][7 - j];
|
||||
tile |= VISIBLE; // assume that all tiles are visible
|
||||
@ -213,7 +229,7 @@ void ObjectTemplate::readMap(CBinaryReader & reader)
|
||||
|
||||
reader.readUInt16();
|
||||
ui16 terrMask = reader.readUInt16();
|
||||
for (size_t i=0; i<9; i++)
|
||||
for(size_t i = 0; i < 9; i++)
|
||||
{
|
||||
if (((terrMask >> i) & 1 ) != 0)
|
||||
allowedTerrains.insert(Terrain::createTerrainTypeH3M(i));
|
||||
@ -243,6 +259,7 @@ void ObjectTemplate::readMap(CBinaryReader & reader)
|
||||
readMsk();
|
||||
|
||||
afterLoadFixup();
|
||||
recalculate();
|
||||
}
|
||||
|
||||
void ObjectTemplate::readJson(const JsonNode &node, const bool withTerrain)
|
||||
@ -288,16 +305,16 @@ void ObjectTemplate::readJson(const JsonNode &node, const bool withTerrain)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case ' ' : return 0;
|
||||
case '0' : return 0;
|
||||
case 'V' : return VISIBLE;
|
||||
case 'B' : return VISIBLE | BLOCKED;
|
||||
case 'H' : return BLOCKED;
|
||||
case 'A' : return VISIBLE | BLOCKED | VISITABLE;
|
||||
case 'T' : return BLOCKED | VISITABLE;
|
||||
default:
|
||||
logGlobal->error("Unrecognized char %s in template mask", ch);
|
||||
return 0;
|
||||
case ' ' : return 0;
|
||||
case '0' : return 0;
|
||||
case 'V' : return VISIBLE;
|
||||
case 'B' : return VISIBLE | BLOCKED;
|
||||
case 'H' : return BLOCKED;
|
||||
case 'A' : return VISIBLE | BLOCKED | VISITABLE;
|
||||
case 'T' : return BLOCKED | VISITABLE;
|
||||
default:
|
||||
logGlobal->error("Unrecognized char %s in template mask", ch);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
@ -320,6 +337,7 @@ void ObjectTemplate::readJson(const JsonNode &node, const bool withTerrain)
|
||||
printPriority = static_cast<si32>(node["zIndex"].Float());
|
||||
|
||||
afterLoadFixup();
|
||||
recalculate();
|
||||
}
|
||||
|
||||
void ObjectTemplate::writeJson(JsonNode & node, const bool withTerrain) const
|
||||
@ -413,38 +431,42 @@ void ObjectTemplate::writeJson(JsonNode & node, const bool withTerrain) const
|
||||
node["zIndex"].Float() = printPriority;
|
||||
}
|
||||
|
||||
ui32 ObjectTemplate::getWidth() const
|
||||
void ObjectTemplate::calculateWidth()
|
||||
{
|
||||
//TODO: Use 2D array
|
||||
//TODO: better precalculate and store constant value
|
||||
ui32 ret = 0;
|
||||
for (const auto &row : usedTiles) //copy is expensive
|
||||
for(const auto& row : usedTiles) //copy is expensive
|
||||
{
|
||||
ret = std::max<ui32>(ret, (ui32)row.size());
|
||||
width = std::max<ui32>(width, (ui32)row.size());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ui32 ObjectTemplate::getHeight() const
|
||||
void ObjectTemplate::calculateHeight()
|
||||
{
|
||||
//TODO: Use 2D array
|
||||
return static_cast<ui32>(usedTiles.size());
|
||||
height = static_cast<ui32>(usedTiles.size());
|
||||
}
|
||||
|
||||
void ObjectTemplate::setSize(ui32 width, ui32 height)
|
||||
{
|
||||
usedTiles.resize(height);
|
||||
for (auto & line : usedTiles)
|
||||
for(auto & line : usedTiles)
|
||||
line.resize(width, 0);
|
||||
}
|
||||
|
||||
bool ObjectTemplate::isVisitable() const
|
||||
void ObjectTemplate::calculateVsitable()
|
||||
{
|
||||
for (auto & line : usedTiles)
|
||||
for (auto & tile : line)
|
||||
for(auto& line : usedTiles)
|
||||
{
|
||||
for(auto& tile : line)
|
||||
{
|
||||
if (tile & VISITABLE)
|
||||
return true;
|
||||
return false;
|
||||
{
|
||||
visitable = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
visitable = false;
|
||||
}
|
||||
|
||||
bool ObjectTemplate::isWithin(si32 X, si32 Y) const
|
||||
@ -469,31 +491,33 @@ bool ObjectTemplate::isBlockedAt(si32 X, si32 Y) const
|
||||
return isWithin(X, Y) && usedTiles[Y][X] & BLOCKED;
|
||||
}
|
||||
|
||||
std::set<int3> ObjectTemplate::getBlockedOffsets() const
|
||||
void ObjectTemplate::calculateBlockedOffsets()
|
||||
{
|
||||
std::set<int3> ret;
|
||||
blockedOffsets.clear();
|
||||
for(int w = 0; w < (int)getWidth(); ++w)
|
||||
{
|
||||
for(int h = 0; h < (int)getHeight(); ++h)
|
||||
{
|
||||
if (isBlockedAt(w, h))
|
||||
ret.insert(int3(-w, -h, 0));
|
||||
blockedOffsets.insert(int3(-w, -h, 0));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int3 ObjectTemplate::getBlockMapOffset() const
|
||||
void ObjectTemplate::calculateBlockMapOffset()
|
||||
{
|
||||
for(int w = 0; w < (int)getWidth(); ++w)
|
||||
{
|
||||
for(int h = 0; h < (int)getHeight(); ++h)
|
||||
{
|
||||
if (isBlockedAt(w, h))
|
||||
return int3(w, h, 0);
|
||||
{
|
||||
blockMapOffset = int3(w, h, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return int3(0,0,0);
|
||||
blockMapOffset = int3(0, 0, 0);
|
||||
}
|
||||
|
||||
bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const
|
||||
@ -502,6 +526,7 @@ bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const
|
||||
// 1 2 3
|
||||
// 8 4
|
||||
// 7 6 5
|
||||
//TODO: static? cached?
|
||||
int dirMap[3][3] =
|
||||
{
|
||||
{ visitDir & 1, visitDir & 2, visitDir & 4 },
|
||||
@ -515,22 +540,20 @@ bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const
|
||||
return dirMap[dy][dx] != 0;
|
||||
}
|
||||
|
||||
int3 ObjectTemplate::getVisitableOffset() const
|
||||
void ObjectTemplate::calculateVisitableOffset()
|
||||
{
|
||||
for(int y = 0; y < (int)getHeight(); y++)
|
||||
for (int x = 0; x < (int)getWidth(); x++)
|
||||
{
|
||||
for(int x = 0; x < (int)getWidth(); x++)
|
||||
{
|
||||
if (isVisitableAt(x, y))
|
||||
return int3(x,y,0);
|
||||
|
||||
//logGlobal->warn("Warning: getVisitableOffset called on non-visitable obj!");
|
||||
return int3(0,0,0);
|
||||
}
|
||||
|
||||
bool ObjectTemplate::isVisitableFromTop() const
|
||||
{
|
||||
return visitDir & 2;
|
||||
//for some reason the line below is never called :?
|
||||
//return isVisitableFrom (0, 1);
|
||||
{
|
||||
visitableOffset = int3(x, y, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
visitableOffset = int3(0, 0, 0);
|
||||
}
|
||||
|
||||
bool ObjectTemplate::canBePlacedAt(Terrain terrain) const
|
||||
@ -538,3 +561,14 @@ bool ObjectTemplate::canBePlacedAt(Terrain terrain) const
|
||||
return allowedTerrains.count(terrain) != 0;
|
||||
}
|
||||
|
||||
void ObjectTemplate::recalculate()
|
||||
{
|
||||
calculateWidth();
|
||||
calculateHeight();
|
||||
calculateVsitable();
|
||||
//The lines below use width and height
|
||||
calculateBlockedOffsets();
|
||||
calculateBlockMapOffset();
|
||||
calculateVisitableOffset();
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../GameConstants.h"
|
||||
#include "../int3.h"
|
||||
|
||||
class CBinaryReader;
|
||||
class CLegacyConfigParser;
|
||||
@ -50,11 +51,22 @@ public:
|
||||
/// string ID, equals to def base name for h3m files (lower case, no extension) or specified in mod data
|
||||
std::string stringID;
|
||||
|
||||
ui32 getWidth() const;
|
||||
ui32 getHeight() const;
|
||||
inline ui32 getWidth() const
|
||||
{
|
||||
return width;
|
||||
};
|
||||
|
||||
inline ui32 getHeight() const
|
||||
{
|
||||
return height;
|
||||
};
|
||||
|
||||
void setSize(ui32 width, ui32 height);
|
||||
|
||||
bool isVisitable() const;
|
||||
inline bool isVisitable() const
|
||||
{
|
||||
return visitable;
|
||||
};
|
||||
|
||||
// Checks object used tiles
|
||||
// Position is relative to bottom-right corner of the object, can not be negative
|
||||
@ -62,13 +74,29 @@ public:
|
||||
bool isVisitableAt(si32 X, si32 Y) const;
|
||||
bool isVisibleAt(si32 X, si32 Y) const;
|
||||
bool isBlockedAt(si32 X, si32 Y) const;
|
||||
std::set<int3> getBlockedOffsets() const;
|
||||
int3 getBlockMapOffset() const; //bottom-right corner when firts blocked tile is
|
||||
|
||||
inline std::set<int3> getBlockedOffsets() const
|
||||
{
|
||||
return blockedOffsets;
|
||||
};
|
||||
|
||||
inline int3 getBlockMapOffset() const
|
||||
{
|
||||
return blockMapOffset;
|
||||
};
|
||||
|
||||
// Checks if object is visitable from certain direction. X and Y must be between -1..+1
|
||||
bool isVisitableFrom(si8 X, si8 Y) const;
|
||||
int3 getVisitableOffset() const;
|
||||
bool isVisitableFromTop() const;
|
||||
inline int3 getVisitableOffset() const
|
||||
{
|
||||
//logGlobal->warn("Warning: getVisitableOffset called on non-visitable obj!");
|
||||
return visitableOffset;
|
||||
};
|
||||
|
||||
inline bool isVisitableFromTop() const
|
||||
{
|
||||
return visitDir & 2;
|
||||
};
|
||||
|
||||
// Checks if object can be placed on specific terrain
|
||||
bool canBePlacedAt(Terrain terrain) const;
|
||||
@ -87,6 +115,25 @@ public:
|
||||
|
||||
bool operator==(const ObjectTemplate& ot) const { return (id == ot.id && subid == ot.subid); }
|
||||
|
||||
private:
|
||||
ui32 width;
|
||||
ui32 height;
|
||||
bool visitable;
|
||||
|
||||
std::set<int3> blockedOffsets;
|
||||
int3 blockMapOffset;
|
||||
int3 visitableOffset;
|
||||
|
||||
void recalculate();
|
||||
|
||||
void calculateWidth();
|
||||
void calculateHeight();
|
||||
void calculateVsitable();
|
||||
void calculateBlockedOffsets();
|
||||
void calculateBlockMapOffset();
|
||||
void calculateVisitableOffset();
|
||||
|
||||
public:
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & usedTiles;
|
||||
@ -98,6 +145,11 @@ public:
|
||||
h & printPriority;
|
||||
h & visitDir;
|
||||
h & editorAnimationFile;
|
||||
|
||||
if (!h.saving)
|
||||
{
|
||||
recalculate();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -146,7 +146,7 @@ public:
|
||||
// FIXME: due to usage of JsonNode I can't make these methods const
|
||||
const CGHeroInstance * strongestHero(PlayerColor owner);
|
||||
std::vector<CGHeroInstance *> getLostCrossoverHeroes(); /// returns a list of crossover heroes which started the scenario, but didn't complete it
|
||||
|
||||
|
||||
CCampaignScenario();
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int formatVersion)
|
||||
|
@ -418,7 +418,7 @@ bool CMap::checkForVisitableDir(const int3 & src, const TerrainTile *pom, const
|
||||
if(!vstd::contains(pom->blockingObjects, obj)) //this visitable object is not blocking, ignore
|
||||
continue;
|
||||
|
||||
if (!obj->appearance.isVisitableFrom(src.x - dst.x, src.y - dst.y))
|
||||
if (!obj->appearance->isVisitableFrom(src.x - dst.x, src.y - dst.y))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -491,14 +491,5 @@ public:
|
||||
h & CGTownInstance::universitySkills;
|
||||
|
||||
h & instanceNames;
|
||||
|
||||
if (!h.saving && formatVersion < 804)
|
||||
{
|
||||
uidCounter = objects.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
h & uidCounter;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -198,4 +198,3 @@ CObjectSelection & CMapEditManager::getObjectSelection()
|
||||
CMapUndoManager & CMapEditManager::getUndoManager()
|
||||
{
|
||||
return undoManager;
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "../GameConstants.h"
|
||||
#include "CMapOperation.h"
|
||||
#include "Terrain.h"
|
||||
|
||||
class CGObjectInstance;
|
||||
class CTerrainViewPatternConfig;
|
||||
|
@ -958,9 +958,9 @@ void CMapLoaderH3M::readDefInfo()
|
||||
// Read custom defs
|
||||
for(int idd = 0; idd < defAmount; ++idd)
|
||||
{
|
||||
ObjectTemplate tmpl;
|
||||
tmpl.readMap(reader);
|
||||
templates.push_back(tmpl);
|
||||
auto tmpl = new ObjectTemplate;
|
||||
tmpl->readMap(reader);
|
||||
templates.push_back(std::shared_ptr<const ObjectTemplate>(tmpl));
|
||||
}
|
||||
}
|
||||
|
||||
@ -977,10 +977,10 @@ void CMapLoaderH3M::readObjects()
|
||||
int defnum = reader.readUInt32();
|
||||
ObjectInstanceID idToBeGiven = ObjectInstanceID((si32)map->objects.size());
|
||||
|
||||
ObjectTemplate & objTempl = templates.at(defnum);
|
||||
std::shared_ptr<const ObjectTemplate> objTempl = templates.at(defnum);
|
||||
reader.skip(5);
|
||||
|
||||
switch(objTempl.id)
|
||||
switch(objTempl->id)
|
||||
{
|
||||
case Obj::EVENT:
|
||||
{
|
||||
@ -1212,15 +1212,15 @@ void CMapLoaderH3M::readObjects()
|
||||
|
||||
readMessageAndGuards(art->message, art);
|
||||
|
||||
if(objTempl.id == Obj::SPELL_SCROLL)
|
||||
if(objTempl->id == Obj::SPELL_SCROLL)
|
||||
{
|
||||
spellID = reader.readUInt32();
|
||||
artID = ArtifactID::SPELL_SCROLL;
|
||||
}
|
||||
else if(objTempl.id == Obj::ARTIFACT)
|
||||
else if(objTempl->id == Obj::ARTIFACT)
|
||||
{
|
||||
//specific artifact
|
||||
artID = objTempl.subid;
|
||||
artID = objTempl->subid;
|
||||
}
|
||||
|
||||
art->storedArtifact = CArtifactInstance::createArtifact(map, artID, spellID);
|
||||
@ -1235,7 +1235,7 @@ void CMapLoaderH3M::readObjects()
|
||||
readMessageAndGuards(res->message, res);
|
||||
|
||||
res->amount = reader.readUInt32();
|
||||
if(objTempl.subid == Res::GOLD)
|
||||
if(objTempl->subid == Res::GOLD)
|
||||
{
|
||||
// Gold is multiplied by 100.
|
||||
res->amount *= 100;
|
||||
@ -1246,7 +1246,7 @@ void CMapLoaderH3M::readObjects()
|
||||
case Obj::RANDOM_TOWN:
|
||||
case Obj::TOWN:
|
||||
{
|
||||
nobj = readTown(objTempl.subid);
|
||||
nobj = readTown(objTempl->subid);
|
||||
break;
|
||||
}
|
||||
case Obj::MINE:
|
||||
@ -1347,7 +1347,7 @@ void CMapLoaderH3M::readObjects()
|
||||
auto dwelling = new CGDwelling();
|
||||
nobj = dwelling;
|
||||
CSpecObjInfo * spec = nullptr;
|
||||
switch(objTempl.id)
|
||||
switch(objTempl->id)
|
||||
{
|
||||
case Obj::RANDOM_DWELLING:
|
||||
spec = new CCreGenLeveledCastleInfo();
|
||||
@ -1450,7 +1450,7 @@ void CMapLoaderH3M::readObjects()
|
||||
}
|
||||
case Obj::PYRAMID: //Pyramid of WoG object
|
||||
{
|
||||
if(objTempl.subid == 0)
|
||||
if(objTempl->subid == 0)
|
||||
{
|
||||
nobj = new CBank();
|
||||
}
|
||||
@ -1470,13 +1470,13 @@ void CMapLoaderH3M::readObjects()
|
||||
}
|
||||
default: //any other object
|
||||
{
|
||||
if (VLC->objtypeh->knownSubObjects(objTempl.id).count(objTempl.subid))
|
||||
if (VLC->objtypeh->knownSubObjects(objTempl->id).count(objTempl->subid))
|
||||
{
|
||||
nobj = VLC->objtypeh->getHandlerFor(objTempl.id, objTempl.subid)->create(objTempl);
|
||||
nobj = VLC->objtypeh->getHandlerFor(objTempl->id, objTempl->subid)->create(objTempl);
|
||||
}
|
||||
else
|
||||
{
|
||||
logGlobal->warn("Unrecognized object: %d:%d at %s on map %s", objTempl.id.toEnum(), objTempl.subid, objPos.toString(), map->name);
|
||||
logGlobal->warn("Unrecognized object: %d:%d at %s on map %s", objTempl->id.toEnum(), objTempl->subid, objPos.toString(), map->name);
|
||||
nobj = new CGObjectInstance();
|
||||
}
|
||||
break;
|
||||
@ -1484,11 +1484,11 @@ void CMapLoaderH3M::readObjects()
|
||||
}
|
||||
|
||||
nobj->pos = objPos;
|
||||
nobj->ID = objTempl.id;
|
||||
nobj->ID = objTempl->id;
|
||||
nobj->id = idToBeGiven;
|
||||
if(nobj->ID != Obj::HERO && nobj->ID != Obj::HERO_PLACEHOLDER && nobj->ID != Obj::PRISON)
|
||||
{
|
||||
nobj->subID = objTempl.subid;
|
||||
nobj->subID = objTempl->subid;
|
||||
}
|
||||
nobj->appearance = objTempl;
|
||||
assert(idToBeGiven == ObjectInstanceID((si32)map->objects.size()));
|
||||
|
@ -245,7 +245,7 @@ private:
|
||||
|
||||
/** List of templates loaded from the map, used on later stage to create
|
||||
* objects but not needed for fully functional CMap */
|
||||
std::vector<ObjectTemplate> templates;
|
||||
std::vector<std::shared_ptr<const ObjectTemplate>> templates;
|
||||
|
||||
/** ptr to the map object which gets filled by data from the buffer */
|
||||
CMap * map;
|
||||
|
@ -1110,13 +1110,14 @@ void CMapLoaderJson::MapObjectLoader::construct()
|
||||
|
||||
auto handler = VLC->objtypeh->getHandlerFor(typeName, subtypeName);
|
||||
|
||||
ObjectTemplate appearance;
|
||||
auto appearance = new ObjectTemplate;
|
||||
|
||||
appearance.id = Obj(handler->type);
|
||||
appearance.subid = handler->subtype;
|
||||
appearance.readJson(configuration["template"], false);
|
||||
appearance->id = Obj(handler->type);
|
||||
appearance->subid = handler->subtype;
|
||||
appearance->readJson(configuration["template"], false);
|
||||
|
||||
instance = handler->create(appearance);
|
||||
// Will be destroyed soon and replaced with shared template
|
||||
instance = handler->create(std::shared_ptr<const ObjectTemplate>(appearance));
|
||||
|
||||
instance->id = ObjectInstanceID((si32)owner->map->objects.size());
|
||||
instance->instanceName = jsonKey;
|
||||
|
@ -204,8 +204,8 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c
|
||||
auto & managerOther = *otherZone->getModificator<ObjectManager>();
|
||||
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SUBTERRANEAN_GATE, 0);
|
||||
auto gate1 = factory->create(ObjectTemplate());
|
||||
auto gate2 = factory->create(ObjectTemplate());
|
||||
auto gate1 = factory->create();
|
||||
auto gate2 = factory->create();
|
||||
rmg::Object rmgGate1(*gate1), rmgGate2(*gate2);
|
||||
rmgGate1.setTemplate(zone.getTerrainType());
|
||||
rmgGate2.setTemplate(otherZone->getTerrainType());
|
||||
@ -249,8 +249,8 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c
|
||||
if(!success)
|
||||
{
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::MONOLITH_TWO_WAY, generator.getNextMonlithIndex());
|
||||
auto teleport1 = factory->create(ObjectTemplate());
|
||||
auto teleport2 = factory->create(ObjectTemplate());
|
||||
auto teleport1 = factory->create();
|
||||
auto teleport2 = factory->create();
|
||||
|
||||
zone.getModificator<ObjectManager>()->addRequiredObject(teleport1, connection.getGuardStrength());
|
||||
otherZone->getModificator<ObjectManager>()->addRequiredObject(teleport2, connection.getGuardStrength());
|
||||
|
@ -367,7 +367,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
|
||||
objects.push_back(&instance->object());
|
||||
if(auto * m = zone.getModificator<RoadPlacer>())
|
||||
{
|
||||
if(instance->object().appearance.isVisitableFromTop())
|
||||
if(instance->object().appearance->isVisitableFromTop())
|
||||
m->areaForRoads().add(instance->getVisitablePosition());
|
||||
else
|
||||
{
|
||||
@ -449,7 +449,7 @@ CGCreature * ObjectManager::chooseGuard(si32 strength, bool zoneGuard)
|
||||
|
||||
auto guardFactory = VLC->objtypeh->getHandlerFor(Obj::MONSTER, creId);
|
||||
|
||||
auto guard = (CGCreature *) guardFactory->create(ObjectTemplate());
|
||||
auto guard = (CGCreature *) guardFactory->create();
|
||||
guard->character = CGCreature::HOSTILE;
|
||||
auto hlp = new CStackInstance(creId, amount);
|
||||
//will be set during initialization
|
||||
|
@ -216,7 +216,7 @@ void ObstaclePlacer::process()
|
||||
|
||||
auto * riverManager = zone.getModificator<RiverPlacer>();
|
||||
|
||||
typedef std::vector<ObjectTemplate> ObstacleVector;
|
||||
typedef std::vector<std::shared_ptr<const ObjectTemplate>> ObstacleVector;
|
||||
//obstacleVector possibleObstacles;
|
||||
|
||||
std::map<int, ObstacleVector> obstaclesBySize;
|
||||
@ -233,8 +233,8 @@ void ObstaclePlacer::process()
|
||||
{
|
||||
for(auto temp : handler->getTemplates())
|
||||
{
|
||||
if(temp.canBePlacedAt(zone.getTerrainType()) && temp.getBlockMapOffset().valid())
|
||||
obstaclesBySize[temp.getBlockedOffsets().size()].push_back(temp);
|
||||
if(temp->canBePlacedAt(zone.getTerrainType()) && temp->getBlockMapOffset().valid())
|
||||
obstaclesBySize[temp->getBlockedOffsets().size()].push_back(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -278,7 +278,7 @@ void ObstaclePlacer::process()
|
||||
|
||||
for(auto & temp : shuffledObstacles)
|
||||
{
|
||||
auto handler = VLC->objtypeh->getHandlerFor(temp.id, temp.subid);
|
||||
auto handler = VLC->objtypeh->getHandlerFor(temp->id, temp->subid);
|
||||
auto obj = handler->create(temp);
|
||||
allObjects.emplace_back(*obj);
|
||||
rmg::Object * rmgObject = &allObjects.back();
|
||||
|
@ -374,10 +374,10 @@ void RiverPlacer::connectRiver(const int3 & tile)
|
||||
auto handler = VLC->objtypeh->getHandlerFor(RIVER_DELTA_ID, RIVER_DELTA_SUBTYPE);
|
||||
assert(handler->isStaticObject());
|
||||
|
||||
std::vector<ObjectTemplate> tmplates;
|
||||
std::vector<std::shared_ptr<const ObjectTemplate>> tmplates;
|
||||
for(auto & temp : handler->getTemplates())
|
||||
{
|
||||
if(temp.canBePlacedAt(zone.getTerrainType()))
|
||||
if(temp->canBePlacedAt(zone.getTerrainType()))
|
||||
tmplates.push_back(temp);
|
||||
}
|
||||
|
||||
@ -389,7 +389,7 @@ void RiverPlacer::connectRiver(const int3 & tile)
|
||||
std::string targetTemplateName = RIVER_DELTA_TEMPLATE_NAME.at(river) + std::to_string(deltaOrientations[pos]) + ".def";
|
||||
for(auto & templ : tmplates)
|
||||
{
|
||||
if(templ.animationFile == targetTemplateName)
|
||||
if(templ->animationFile == targetTemplateName)
|
||||
{
|
||||
auto obj = handler->create(templ);
|
||||
rmg::Object deltaObj(*obj, deltaPositions[pos]);
|
||||
|
@ -105,7 +105,7 @@ void Object::Instance::setPositionRaw(const int3 & position)
|
||||
|
||||
void Object::Instance::setTemplate(const Terrain & terrain)
|
||||
{
|
||||
if(dObject.appearance.id == Obj::NO_OBJ)
|
||||
if(dObject.appearance->id == Obj::NO_OBJ)
|
||||
{
|
||||
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrain);
|
||||
if(templates.empty())
|
||||
@ -130,7 +130,7 @@ void Object::Instance::clear()
|
||||
bool Object::Instance::isVisitableFrom(const int3 & position) const
|
||||
{
|
||||
auto relPosition = position - getPosition(true);
|
||||
return dObject.appearance.isVisitableFrom(relPosition.x, relPosition.y);
|
||||
return dObject.appearance->isVisitableFrom(relPosition.x, relPosition.y);
|
||||
}
|
||||
|
||||
CGObjectInstance & Object::Instance::object()
|
||||
@ -286,7 +286,7 @@ void Object::Instance::finalize(RmgMap & map)
|
||||
throw rmgException(boost::to_string(boost::format("Tile %s of object %d at %s is outside the map") % tile.toString() % dObject.id % dObject.pos.toString()));
|
||||
}
|
||||
|
||||
if (dObject.appearance.id == Obj::NO_OBJ)
|
||||
if (dObject.appearance->id == Obj::NO_OBJ)
|
||||
{
|
||||
auto terrainType = map.map().getTile(getPosition(true)).terType;
|
||||
auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrainType);
|
||||
|
@ -69,7 +69,7 @@ void TownPlacer::placeTowns(ObjectManager & manager)
|
||||
|
||||
auto townFactory = VLC->objtypeh->getHandlerFor(Obj::TOWN, zone.getTownType());
|
||||
|
||||
CGTownInstance * town = (CGTownInstance *) townFactory->create(ObjectTemplate());
|
||||
CGTownInstance * town = (CGTownInstance *) townFactory->create();
|
||||
town->tempOwner = player;
|
||||
town->builtBuildings.insert(BuildingID::FORT);
|
||||
town->builtBuildings.insert(BuildingID::DEFAULT);
|
||||
@ -163,7 +163,7 @@ bool TownPlacer::placeMines(ObjectManager & manager)
|
||||
{
|
||||
auto mineHandler = VLC->objtypeh->getHandlerFor(Obj::MINE, res);
|
||||
auto & rmginfo = mineHandler->getRMGInfo();
|
||||
auto mine = (CGMine*)mineHandler->create(ObjectTemplate());
|
||||
auto mine = (CGMine*)mineHandler->create();
|
||||
mine->producedResource = res;
|
||||
mine->tempOwner = PlayerColor::NEUTRAL;
|
||||
mine->producedQuantity = mine->defaultResProduction();
|
||||
@ -184,7 +184,7 @@ bool TownPlacer::placeMines(ObjectManager & manager)
|
||||
{
|
||||
for(int rc = generator.rand.nextInt(1, extraRes); rc > 0; --rc)
|
||||
{
|
||||
auto resourse = (CGResource*) VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create(ObjectTemplate());
|
||||
auto resourse = (CGResource*) VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create();
|
||||
resourse->amount = CGResource::RANDOM_AMOUNT;
|
||||
manager.addNearbyObject(resourse, mine);
|
||||
}
|
||||
@ -225,7 +225,7 @@ void TownPlacer::addNewTowns(int count, bool hasFort, PlayerColor player, Object
|
||||
}
|
||||
|
||||
auto townFactory = VLC->objtypeh->getHandlerFor(Obj::TOWN, subType);
|
||||
auto town = (CGTownInstance *) townFactory->create(ObjectTemplate());
|
||||
auto town = (CGTownInstance *) townFactory->create();
|
||||
town->ID = Obj::TOWN;
|
||||
|
||||
town->tempOwner = player;
|
||||
|
@ -59,11 +59,11 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
{
|
||||
for(auto temp : handler->getTemplates())
|
||||
{
|
||||
if(temp.canBePlacedAt(zone.getTerrainType()))
|
||||
if(temp->canBePlacedAt(zone.getTerrainType()))
|
||||
{
|
||||
oi.generateObject = [temp]() -> CGObjectInstance *
|
||||
{
|
||||
return VLC->objtypeh->getHandlerFor(temp.id, temp.subid)->create(temp);
|
||||
return VLC->objtypeh->getHandlerFor(temp->id, temp->subid)->create(temp);
|
||||
};
|
||||
auto rmgInfo = handler->getRMGInfo();
|
||||
oi.value = rmgInfo.value;
|
||||
@ -97,7 +97,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
|
||||
auto hid = *RandomGeneratorUtil::nextItem(possibleHeroes, generator.rand);
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0);
|
||||
auto obj = (CGHeroInstance *) factory->create(ObjectTemplate());
|
||||
auto obj = (CGHeroInstance *) factory->create();
|
||||
|
||||
|
||||
obj->subID = hid; //will be initialized later
|
||||
@ -159,7 +159,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
|
||||
for(auto tmplate : dwellingHandler->getTemplates())
|
||||
{
|
||||
if(tmplate.canBePlacedAt(zone.getTerrainType()))
|
||||
if(tmplate->canBePlacedAt(zone.getTerrainType()))
|
||||
{
|
||||
oi.generateObject = [tmplate, secondaryID, dwellingType]() -> CGObjectInstance *
|
||||
{
|
||||
@ -181,7 +181,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
oi.generateObject = [i, this]() -> CGObjectInstance *
|
||||
{
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SPELL_SCROLL, 0);
|
||||
auto obj = (CGArtifact *) factory->create(ObjectTemplate());
|
||||
auto obj = (CGArtifact *) factory->create();
|
||||
std::vector<SpellID> out;
|
||||
|
||||
for(auto spell : VLC->spellh->objects) //spellh size appears to be greater (?)
|
||||
@ -207,7 +207,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
oi.generateObject = [i]() -> CGObjectInstance *
|
||||
{
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
|
||||
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
|
||||
auto obj = (CGPandoraBox *) factory->create();
|
||||
obj->resources[Res::GOLD] = i * 5000;
|
||||
return obj;
|
||||
};
|
||||
@ -223,7 +223,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
oi.generateObject = [i]() -> CGObjectInstance *
|
||||
{
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
|
||||
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
|
||||
auto obj = (CGPandoraBox *) factory->create();
|
||||
obj->gainedExp = i * 5000;
|
||||
return obj;
|
||||
};
|
||||
@ -275,7 +275,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
oi.generateObject = [creature, creaturesAmount]() -> CGObjectInstance *
|
||||
{
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
|
||||
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
|
||||
auto obj = (CGPandoraBox *) factory->create();
|
||||
auto stack = new CStackInstance(creature, creaturesAmount);
|
||||
obj->creatures.putStack(SlotID(0), stack);
|
||||
return obj;
|
||||
@ -292,7 +292,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
oi.generateObject = [i, this]() -> CGObjectInstance *
|
||||
{
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
|
||||
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
|
||||
auto obj = (CGPandoraBox *) factory->create();
|
||||
|
||||
std::vector <CSpell *> spells;
|
||||
for(auto spell : VLC->spellh->objects)
|
||||
@ -321,7 +321,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
oi.generateObject = [i, this]() -> CGObjectInstance *
|
||||
{
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
|
||||
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
|
||||
auto obj = (CGPandoraBox *) factory->create();
|
||||
|
||||
std::vector <CSpell *> spells;
|
||||
for(auto spell : VLC->spellh->objects)
|
||||
@ -349,7 +349,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
oi.generateObject = [this]() -> CGObjectInstance *
|
||||
{
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0);
|
||||
auto obj = (CGPandoraBox *) factory->create(ObjectTemplate());
|
||||
auto obj = (CGPandoraBox *) factory->create();
|
||||
|
||||
std::vector <CSpell *> spells;
|
||||
for(auto spell : VLC->spellh->objects)
|
||||
@ -421,7 +421,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
oi.generateObject = [creature, creaturesAmount, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
|
||||
{
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
||||
auto obj = (CGSeerHut *) factory->create(ObjectTemplate());
|
||||
auto obj = (CGSeerHut *) factory->create();
|
||||
obj->rewardType = CGSeerHut::CREATURE;
|
||||
obj->rID = creature->idNumber;
|
||||
obj->rVal = creaturesAmount;
|
||||
@ -457,7 +457,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
|
||||
{
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
||||
auto obj = (CGSeerHut *) factory->create(ObjectTemplate());
|
||||
auto obj = (CGSeerHut *) factory->create();
|
||||
|
||||
obj->rewardType = CGSeerHut::EXPERIENCE;
|
||||
obj->rID = 0; //unitialized?
|
||||
@ -481,7 +481,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
|
||||
{
|
||||
auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance);
|
||||
auto obj = (CGSeerHut *) factory->create(ObjectTemplate());
|
||||
auto obj = (CGSeerHut *) factory->create();
|
||||
obj->rewardType = CGSeerHut::RESOURCES;
|
||||
obj->rID = Res::GOLD;
|
||||
obj->rVal = generator.getConfig().questRewardValues[i];
|
||||
@ -525,7 +525,7 @@ std::vector<ObjectInfo*> TreasurePlacer::prepareTreasurePile(const CTreasureInfo
|
||||
if(!oi) //fail
|
||||
break;
|
||||
|
||||
if(oi->templ.isVisitableFromTop())
|
||||
if(oi->templ->isVisitableFromTop())
|
||||
{
|
||||
objectInfos.push_back(oi);
|
||||
}
|
||||
@ -599,7 +599,7 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*>
|
||||
auto instanceAccessibleArea = instance.getAccessibleArea();
|
||||
if(instance.getBlockedArea().getTilesVector().size() == 1)
|
||||
{
|
||||
if(instance.object().appearance.isVisitableFromTop() && instance.object().ID != Obj::CORPSE)
|
||||
if(instance.object().appearance->isVisitableFromTop() && instance.object().ID != Obj::CORPSE)
|
||||
instanceAccessibleArea.add(instance.getVisitablePosition());
|
||||
}
|
||||
|
||||
@ -632,7 +632,7 @@ ObjectInfo * TreasurePlacer::getRandomObject(ui32 desiredValue, ui32 currentValu
|
||||
if(oi.value > maxVal)
|
||||
break; //this assumes values are sorted in ascending order
|
||||
|
||||
if(!oi.templ.isVisitableFromTop() && !allowLargeObjects)
|
||||
if(!oi.templ->isVisitableFromTop() && !allowLargeObjects)
|
||||
continue;
|
||||
|
||||
if(oi.value >= minValue && oi.maxPerZone > 0)
|
||||
|
@ -19,7 +19,7 @@ class CMapGenerator;
|
||||
|
||||
struct ObjectInfo
|
||||
{
|
||||
ObjectTemplate templ;
|
||||
std::shared_ptr<const ObjectTemplate> templ;
|
||||
ui32 value = 0;
|
||||
ui16 probability = 0;
|
||||
ui32 maxPerZone = -1;
|
||||
|
@ -200,7 +200,7 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, RouteInfo & info)
|
||||
return false;
|
||||
|
||||
auto subObjects = VLC->objtypeh->knownSubObjects(Obj::BOAT);
|
||||
auto* boat = (CGBoat*)VLC->objtypeh->getHandlerFor(Obj::BOAT, *RandomGeneratorUtil::nextItem(subObjects, generator.rand))->create(ObjectTemplate());
|
||||
auto* boat = (CGBoat*)VLC->objtypeh->getHandlerFor(Obj::BOAT, *RandomGeneratorUtil::nextItem(subObjects, generator.rand))->create();
|
||||
|
||||
rmg::Object rmgObject(*boat);
|
||||
rmgObject.setTemplate(zone.getTerrainType());
|
||||
@ -259,7 +259,7 @@ bool WaterProxy::placeShipyard(Zone & land, const Lake & lake, si32 guard, Route
|
||||
return false;
|
||||
|
||||
int subtype = chooseRandomAppearance(generator.rand, Obj::SHIPYARD, land.getTerrainType());
|
||||
auto shipyard = (CGShipyard*) VLC->objtypeh->getHandlerFor(Obj::SHIPYARD, subtype)->create(ObjectTemplate());
|
||||
auto shipyard = (CGShipyard*) VLC->objtypeh->getHandlerFor(Obj::SHIPYARD, subtype)->create();
|
||||
shipyard->tempOwner = PlayerColor::NEUTRAL;
|
||||
|
||||
rmg::Object rmgObject(*shipyard);
|
||||
|
@ -382,6 +382,56 @@ public:
|
||||
else
|
||||
{
|
||||
auto hlp = std::shared_ptr<NonConstT>(internalPtr);
|
||||
data = hlp;
|
||||
loadedSharedPointers[internalPtrDerived] = typeList.castSharedToMostDerived(hlp);
|
||||
}
|
||||
}
|
||||
else
|
||||
data.reset();
|
||||
}
|
||||
template <typename T>
|
||||
void load(std::shared_ptr<const T> &data) //version of the above for const ptr
|
||||
{
|
||||
typedef typename std::remove_const<T>::type NonConstT;
|
||||
NonConstT *internalPtr;
|
||||
load(internalPtr);
|
||||
|
||||
void *internalPtrDerived = typeList.castToMostDerived(internalPtr);
|
||||
|
||||
if(internalPtr)
|
||||
{
|
||||
auto itr = loadedSharedPointers.find(internalPtrDerived);
|
||||
if(itr != loadedSharedPointers.end())
|
||||
{
|
||||
// This pointer is already loaded. The "data" needs to be pointed to it,
|
||||
// so their shared state is actually shared.
|
||||
try
|
||||
{
|
||||
auto actualType = typeList.getTypeInfo(internalPtr);
|
||||
auto typeWeNeedToReturn = typeList.getTypeInfo<T>();
|
||||
if(*actualType == *typeWeNeedToReturn)
|
||||
{
|
||||
// No casting needed, just unpack already stored shared_ptr and return it
|
||||
data = boost::any_cast<std::shared_ptr<const T>>(itr->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need to perform series of casts
|
||||
auto ret = typeList.castShared(itr->second, actualType, typeWeNeedToReturn);
|
||||
data = boost::any_cast<std::shared_ptr<const T>>(ret);
|
||||
}
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
logGlobal->error(e.what());
|
||||
logGlobal->error("Failed to cast stored shared ptr. Real type: %s. Needed type %s. FIXME FIXME FIXME", itr->second.type().name(), typeid(std::shared_ptr<T>).name());
|
||||
//TODO scenario with inheritance -> we can have stored ptr to base and load ptr to derived (or vice versa)
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto hlp = std::shared_ptr<const T>(internalPtr);
|
||||
data = hlp; //possibly adds const
|
||||
loadedSharedPointers[internalPtrDerived] = typeList.castSharedToMostDerived(hlp);
|
||||
}
|
||||
|
@ -245,6 +245,12 @@ public:
|
||||
save(internalPtr);
|
||||
}
|
||||
template <typename T>
|
||||
void save(const std::shared_ptr<const T> &data)
|
||||
{
|
||||
const T *internalPtr = data.get();
|
||||
save(internalPtr);
|
||||
}
|
||||
template <typename T>
|
||||
void save(const std::unique_ptr<T> &data)
|
||||
{
|
||||
T *internalPtr = data.get();
|
||||
|
@ -12,8 +12,8 @@
|
||||
#include "../ConstTransitivePtr.h"
|
||||
#include "../GameConstants.h"
|
||||
|
||||
const ui32 SERIALIZATION_VERSION = 804;
|
||||
const ui32 MINIMAL_SERIALIZATION_VERSION = 803;
|
||||
const ui32 SERIALIZATION_VERSION = 805;
|
||||
const ui32 MINIMAL_SERIALIZATION_VERSION = 805;
|
||||
const std::string SAVEGAME_MAGIC = "VCMISVG";
|
||||
|
||||
class CHero;
|
||||
|
@ -5572,13 +5572,18 @@ bool CGameHandler::isAllowedExchange(ObjectInstanceID id1, ObjectInstanceID id2)
|
||||
return true;
|
||||
}
|
||||
|
||||
//Ongoing garrison exchange
|
||||
if (auto dialog = std::dynamic_pointer_cast<CGarrisonDialogQuery>(queries.topQuery(o1->tempOwner)))
|
||||
//Ongoing garrison exchange - usually picking from top garison (from o1 to o2), but who knows
|
||||
auto dialog = std::dynamic_pointer_cast<CGarrisonDialogQuery>(queries.topQuery(o1->tempOwner));
|
||||
if (!dialog)
|
||||
{
|
||||
if (dialog->exchangingArmies.at(0) == o1 && dialog->exchangingArmies.at(1) == o2)
|
||||
return true;
|
||||
dialog = std::dynamic_pointer_cast<CGarrisonDialogQuery>(queries.topQuery(o2->tempOwner));
|
||||
}
|
||||
if (dialog)
|
||||
{
|
||||
auto topArmy = dialog->exchangingArmies.at(0);
|
||||
auto bottomArmy = dialog->exchangingArmies.at(1);
|
||||
|
||||
if (dialog->exchangingArmies.at(1) == o1 && dialog->exchangingArmies.at(0) == o2)
|
||||
if (topArmy == o1 && bottomArmy == o2 || bottomArmy == o1 && topArmy == o2)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user