mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-14 10:12:59 +02:00
Merge remote-tracking branch 'upstream/develop' into develop
This commit is contained in:
commit
27aed74397
@ -3,9 +3,9 @@
|
||||
"vcmi.adventureMap.monsterThreat.levels.0" : "Sem Esforço",
|
||||
"vcmi.adventureMap.monsterThreat.levels.1" : "Muito Fraca",
|
||||
"vcmi.adventureMap.monsterThreat.levels.2" : "Fraca",
|
||||
"vcmi.adventureMap.monsterThreat.levels.3" : "Um pouco mais fraca",
|
||||
"vcmi.adventureMap.monsterThreat.levels.3" : "Um Pouco Mais Fraca",
|
||||
"vcmi.adventureMap.monsterThreat.levels.4" : "Igual",
|
||||
"vcmi.adventureMap.monsterThreat.levels.5" : "Um pouco mais forte",
|
||||
"vcmi.adventureMap.monsterThreat.levels.5" : "Um Pouco Mais Forte",
|
||||
"vcmi.adventureMap.monsterThreat.levels.6" : "Forte",
|
||||
"vcmi.adventureMap.monsterThreat.levels.7" : "Muito Forte",
|
||||
"vcmi.adventureMap.monsterThreat.levels.8" : "Desafiante",
|
||||
@ -163,8 +163,8 @@
|
||||
"vcmi.systemOptions.townsGroup" : "Tela da Cidade",
|
||||
|
||||
"vcmi.statisticWindow.statistics" : "Estatísticas",
|
||||
"vcmi.statisticWindow.tsvCopy" : "Copiar dados",
|
||||
"vcmi.statisticWindow.selectView" : "Selecionar visualização",
|
||||
"vcmi.statisticWindow.tsvCopy" : "Para a área de transf.",
|
||||
"vcmi.statisticWindow.selectView" : "Selec. visualização",
|
||||
"vcmi.statisticWindow.value" : "Valor",
|
||||
"vcmi.statisticWindow.title.overview" : "Visão geral",
|
||||
"vcmi.statisticWindow.title.resources" : "Recursos",
|
||||
@ -178,7 +178,7 @@
|
||||
"vcmi.statisticWindow.title.experience" : "Experiência",
|
||||
"vcmi.statisticWindow.title.resourcesSpentArmy" : "Custo do exército",
|
||||
"vcmi.statisticWindow.title.resourcesSpentBuildings" : "Custo de construção",
|
||||
"vcmi.statisticWindow.title.mapExplored" : "Exploração do mapa",
|
||||
"vcmi.statisticWindow.title.mapExplored" : "Mapa explorado",
|
||||
"vcmi.statisticWindow.param.playerName" : "Nome do jogador",
|
||||
"vcmi.statisticWindow.param.daysSurvived" : "Dias sobrevividos",
|
||||
"vcmi.statisticWindow.param.maxHeroLevel" : "Nível máximo do herói",
|
||||
@ -325,8 +325,8 @@
|
||||
"vcmi.townHall.missingBase" : "A construção base %s deve ser construída primeiro",
|
||||
"vcmi.townHall.noCreaturesToRecruit" : "Não há criaturas para recrutar!",
|
||||
|
||||
"vcmi.townStructure.bank.borrow" : "Você entra no banco. Um banqueiro o vê e diz: \"Temos uma oferta especial para você. Você pode tomar um empréstimo de 2500 de ouro por 5 dias. Você terá que pagar 500 de ouro todos os dias.\"",
|
||||
"vcmi.townStructure.bank.payBack" : "Você entra no banco. Um banqueiro o vê e diz: \"Você já pegou um empréstimo. Pague-o antes de tomar um novo.\"",
|
||||
"vcmi.townStructure.bank.borrow" : "Você entra no banco. Um banqueiro o vê e diz: \"Temos uma oferta especial para você. Você pode pegar um empréstimo de 2500 de ouro por 5 dias. Você terá que pagar 500 de ouro todos os dias.\"",
|
||||
"vcmi.townStructure.bank.payBack" : "Você entra no banco. Um banqueiro o vê e diz: \"Você já pegou um empréstimo. Pague-o antes de pegar um novo.\"",
|
||||
|
||||
"vcmi.logicalExpressions.anyOf" : "Qualquer um dos seguintes:",
|
||||
"vcmi.logicalExpressions.allOf" : "Todos os seguintes:",
|
||||
@ -660,5 +660,7 @@
|
||||
"core.bonus.WATER_IMMUNITY.name" : "Imunidade à Água",
|
||||
"core.bonus.WATER_IMMUNITY.description" : "Imune a todos os feitiços da escola de magia da Água",
|
||||
"core.bonus.WIDE_BREATH.name" : "Sopro Amplo",
|
||||
"core.bonus.WIDE_BREATH.description" : "Ataque de sopro amplo (vários hexágonos)"
|
||||
"core.bonus.WIDE_BREATH.description" : "Ataque de sopro amplo (vários hexágonos)",
|
||||
"core.bonus.DISINTEGRATE.name": "Desintegrar",
|
||||
"core.bonus.DISINTEGRATE.description": "Nenhum corpo permanece após a morte"
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ void AssetGenerator::generateAll()
|
||||
createAdventureOptionsCleanBackground();
|
||||
for (int i = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i)
|
||||
createPlayerColoredBackground(PlayerColor(i));
|
||||
createCombatUnitNumberWindow();
|
||||
}
|
||||
|
||||
void AssetGenerator::createAdventureOptionsCleanBackground()
|
||||
|
@ -191,14 +191,14 @@ void Canvas::drawText(const Point & position, const EFonts & font, const ColorRG
|
||||
|
||||
void Canvas::drawColor(const Rect & target, const ColorRGBA & color)
|
||||
{
|
||||
Rect realTarget = (target + renderArea.topLeft()) * getScalingFactor();
|
||||
Rect realTarget = target * getScalingFactor() + renderArea.topLeft();
|
||||
|
||||
CSDL_Ext::fillRect(surface, realTarget, CSDL_Ext::toSDL(color));
|
||||
}
|
||||
|
||||
void Canvas::drawColorBlended(const Rect & target, const ColorRGBA & color)
|
||||
{
|
||||
Rect realTarget = (target + renderArea.topLeft()) * getScalingFactor();
|
||||
Rect realTarget = target * getScalingFactor() + renderArea.topLeft();
|
||||
|
||||
CSDL_Ext::fillRectBlended(surface, realTarget, CSDL_Ext::toSDL(color));
|
||||
}
|
||||
|
@ -415,6 +415,10 @@ void SDLImageIndexed::shiftPalette(uint32_t firstColorID, uint32_t colorsToMove,
|
||||
|
||||
void SDLImageIndexed::adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask)
|
||||
{
|
||||
// If shadow is enabled, following colors must be skipped unconditionally
|
||||
if (shadowEnabled)
|
||||
colorsToSkipMask |= (1 << 0) + (1 << 1) + (1 << 4);
|
||||
|
||||
// Note: here we skip first colors in the palette that are predefined in H3 images
|
||||
for(int i = 0; i < currentPalette->ncolors; i++)
|
||||
{
|
||||
|
@ -54,6 +54,7 @@
|
||||
#include "../../lib/entities/building/CBuilding.h"
|
||||
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
#include "../../lib/mapObjects/TownBuildingInstance.h"
|
||||
|
||||
|
||||
static bool useCompactCreatureBox()
|
||||
@ -845,7 +846,21 @@ bool CCastleBuildings::buildingTryActivateCustomUI(BuildingID buildingToTest, Bu
|
||||
|
||||
void CCastleBuildings::enterRewardable(BuildingID building)
|
||||
{
|
||||
LOCPLINT->cb->visitTownBuilding(town, building);
|
||||
if (town->visitingHero == nullptr)
|
||||
{
|
||||
MetaString message;
|
||||
message.appendTextID("core.genrltxt.273"); // only visiting heroes may visit %s
|
||||
message.replaceTextID(town->town->buildings.at(building)->getNameTextID());
|
||||
|
||||
LOCPLINT->showInfoDialog(message.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (town->rewardableBuildings.at(building)->wasVisited(town->visitingHero))
|
||||
enterBuilding(building);
|
||||
else
|
||||
LOCPLINT->cb->visitTownBuilding(town, building);
|
||||
}
|
||||
}
|
||||
|
||||
void CCastleBuildings::enterBlacksmith(BuildingID building, ArtifactID artifactID)
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "../windows/CMessage.h"
|
||||
#include "../renderSDL/SDL_PixelAccess.h"
|
||||
#include "../render/IImage.h"
|
||||
#include "../render/IScreenHandler.h"
|
||||
#include "../render/IRenderHandler.h"
|
||||
#include "../render/Canvas.h"
|
||||
|
||||
@ -115,7 +116,8 @@ void CWindowObject::updateShadow()
|
||||
void CWindowObject::setShadow(bool on)
|
||||
{
|
||||
//size of shadow
|
||||
static const int size = 8;
|
||||
int sizeOriginal = 8;
|
||||
int size = sizeOriginal * GH.screenHandler().getScalingFactor();
|
||||
|
||||
if(on == !shadowParts.empty())
|
||||
return;
|
||||
@ -180,9 +182,9 @@ void CWindowObject::setShadow(bool on)
|
||||
//FIXME: do something with this points
|
||||
Point shadowStart;
|
||||
if (options & BORDERED)
|
||||
shadowStart = Point(size - 14, size - 14);
|
||||
shadowStart = Point(sizeOriginal - 14, sizeOriginal - 14);
|
||||
else
|
||||
shadowStart = Point(size, size);
|
||||
shadowStart = Point(sizeOriginal, sizeOriginal);
|
||||
|
||||
Point shadowPos;
|
||||
if (options & BORDERED)
|
||||
@ -198,8 +200,8 @@ void CWindowObject::setShadow(bool on)
|
||||
|
||||
//create base 8x8 piece of shadow
|
||||
SDL_Surface * shadowCorner = CSDL_Ext::copySurface(shadowCornerTempl);
|
||||
SDL_Surface * shadowBottom = CSDL_Ext::scaleSurface(shadowBottomTempl, fullsize.x - size, size);
|
||||
SDL_Surface * shadowRight = CSDL_Ext::scaleSurface(shadowRightTempl, size, fullsize.y - size);
|
||||
SDL_Surface * shadowBottom = CSDL_Ext::scaleSurface(shadowBottomTempl, (fullsize.x - sizeOriginal) * GH.screenHandler().getScalingFactor(), size);
|
||||
SDL_Surface * shadowRight = CSDL_Ext::scaleSurface(shadowRightTempl, size, (fullsize.y - sizeOriginal) * GH.screenHandler().getScalingFactor());
|
||||
|
||||
blitAlphaCol(shadowBottom, 0);
|
||||
blitAlphaRow(shadowRight, 0);
|
||||
|
@ -19,7 +19,7 @@ class VCMI(ConanFile):
|
||||
"sdl_image/[~2.0.5]",
|
||||
"sdl_mixer/[~2.0.4]",
|
||||
"sdl_ttf/[~2.0.18]",
|
||||
"onetbb/[^2021.3]",
|
||||
"onetbb/[^2021.7 <2021.10]", # 2021.10+ breaks mobile builds due to added hwloc dependency
|
||||
"xz_utils/[>=5.2.5]", # Required for innoextract
|
||||
]
|
||||
|
||||
@ -39,7 +39,6 @@ class VCMI(ConanFile):
|
||||
|
||||
"boost/*:shared": True,
|
||||
"minizip/*:shared": True,
|
||||
"onetbb/*:shared": True,
|
||||
}
|
||||
|
||||
def configure(self):
|
||||
|
@ -197,6 +197,7 @@ These are just a couple of examples of what can be done in VCMI. See vcmi config
|
||||
"bonuses" : [ BONUS_FORMAT ]
|
||||
|
||||
// If set to true, this building will not automatically activate on new day or on entering town and needs to be activated manually on click
|
||||
// Note that such building can only be activated by visiting hero, and not by garrisoned hero.
|
||||
"manualHeroVisit" : false,
|
||||
|
||||
// Bonuses provided by this special building if this building or any of its upgrades are constructed in town
|
||||
|
@ -21,6 +21,80 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
// Algorithm for detection of typos in words
|
||||
// Determines how 'different' two strings are - how many changes must be done to turn one string into another one
|
||||
// https://en.wikipedia.org/wiki/Levenshtein_distance#Iterative_with_two_matrix_rows
|
||||
static int getLevenshteinDistance(const std::string & s, const std::string & t)
|
||||
{
|
||||
int n = t.size();
|
||||
int m = s.size();
|
||||
|
||||
// create two work vectors of integer distances
|
||||
std::vector<int> v0(n+1, 0);
|
||||
std::vector<int> v1(n+1, 0);
|
||||
|
||||
// initialize v0 (the previous row of distances)
|
||||
// this row is A[0][i]: edit distance from an empty s to t;
|
||||
// that distance is the number of characters to append to s to make t.
|
||||
for (int i = 0; i < n; ++i)
|
||||
v0[i] = i;
|
||||
|
||||
for (int i = 0; i < m; ++i)
|
||||
{
|
||||
// calculate v1 (current row distances) from the previous row v0
|
||||
|
||||
// first element of v1 is A[i + 1][0]
|
||||
// edit distance is delete (i + 1) chars from s to match empty t
|
||||
v1[0] = i + 1;
|
||||
|
||||
// use formula to fill in the rest of the row
|
||||
for (int j = 0; j < n; ++j)
|
||||
{
|
||||
// calculating costs for A[i + 1][j + 1]
|
||||
int deletionCost = v0[j + 1] + 1;
|
||||
int insertionCost = v1[j] + 1;
|
||||
int substitutionCost;
|
||||
|
||||
if (s[i] == t[j])
|
||||
substitutionCost = v0[j];
|
||||
else
|
||||
substitutionCost = v0[j] + 1;
|
||||
|
||||
v1[j + 1] = std::min({deletionCost, insertionCost, substitutionCost});
|
||||
}
|
||||
|
||||
// copy v1 (current row) to v0 (previous row) for next iteration
|
||||
// since data in v1 is always invalidated, a swap without copy could be more efficient
|
||||
std::swap(v0, v1);
|
||||
}
|
||||
|
||||
// after the last swap, the results of v1 are now in v0
|
||||
return v0[n];
|
||||
}
|
||||
|
||||
/// Searches for keys similar to 'target' in 'candidates' map
|
||||
/// Returns closest match or empty string if no suitable candidates are found
|
||||
static std::string findClosestMatch(JsonMap candidates, std::string target)
|
||||
{
|
||||
// Maximum distance at which we can consider strings to be similar
|
||||
// If strings have more different symbols than this number then it is not a typo, but a completely different word
|
||||
static constexpr int maxDistance = 5;
|
||||
int bestDistance = maxDistance;
|
||||
std::string bestMatch;
|
||||
|
||||
for (auto const & candidate : candidates)
|
||||
{
|
||||
int newDistance = getLevenshteinDistance(candidate.first, target);
|
||||
|
||||
if (newDistance < bestDistance)
|
||||
{
|
||||
bestDistance = newDistance;
|
||||
bestMatch = candidate.first;
|
||||
}
|
||||
}
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
static std::string emptyCheck(JsonValidator & validator, const JsonNode & baseSchema, const JsonNode & schema, const JsonNode & data)
|
||||
{
|
||||
// check is not needed - e.g. incorporated into another check
|
||||
@ -417,7 +491,13 @@ static std::string additionalPropertiesCheck(JsonValidator & validator, const Js
|
||||
|
||||
// or, additionalItems field can be bool which indicates if such items are allowed
|
||||
else if(!schema.isNull() && !schema.Bool()) // present and set to false - error
|
||||
errors += validator.makeErrorMessage("Unknown entry found: " + entry.first);
|
||||
{
|
||||
std::string bestCandidate = findClosestMatch(baseSchema["properties"].Struct(), entry.first);
|
||||
if (!bestCandidate.empty())
|
||||
errors += validator.makeErrorMessage("Unknown entry found: '" + entry.first + "'. Perhaps you meant '" + bestCandidate + "'?");
|
||||
else
|
||||
errors += validator.makeErrorMessage("Unknown entry found: " + entry.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
|
@ -246,6 +246,9 @@ void CRewardableObject::blockingDialogAnswered(const CGHeroInstance * hero, int3
|
||||
}
|
||||
else
|
||||
{
|
||||
if (answer == 0)
|
||||
return; //Player refused
|
||||
|
||||
if(answer > 0 && answer - 1 < configuration.info.size())
|
||||
{
|
||||
auto list = getAvailableRewards(hero, Rewardable::EEventType::EVENT_FIRST_VISIT);
|
||||
|
@ -165,6 +165,11 @@ void TownRewardableBuildingInstance::grantReward(ui32 rewardID, const CGHeroInst
|
||||
}
|
||||
}
|
||||
|
||||
bool TownRewardableBuildingInstance::wasVisited(const CGHeroInstance * contextHero) const
|
||||
{
|
||||
return wasVisitedBefore(contextHero);
|
||||
}
|
||||
|
||||
bool TownRewardableBuildingInstance::wasVisitedBefore(const CGHeroInstance * contextHero) const
|
||||
{
|
||||
switch (configuration.visitMode)
|
||||
|
@ -70,6 +70,7 @@ class DLL_LINKAGE TownRewardableBuildingInstance : public TownBuildingInstance,
|
||||
public:
|
||||
void setProperty(ObjProperty what, ObjPropertyID identifier) override;
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
bool wasVisited(const CGHeroInstance * contextHero) const override;
|
||||
|
||||
void newTurn(vstd::RNG & rand) const override;
|
||||
|
||||
|
@ -196,6 +196,7 @@ endif()
|
||||
target_sources(vcmieditor PRIVATE
|
||||
${editor_SRCS}
|
||||
${editor_HEADERS}
|
||||
${editor_FORMS}
|
||||
${editor_RESOURCES}
|
||||
)
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "towneventdialog.h"
|
||||
#include "ui_towneventdialog.h"
|
||||
#include "mapeditorroles.h"
|
||||
#include "../mapsettings/eventsettings.h"
|
||||
#include "../../lib/entities/building/CBuilding.h"
|
||||
#include "../../lib/entities/faction/CTownHandler.h"
|
||||
#include "../../lib/constants/NumericConstants.h"
|
||||
@ -63,9 +64,10 @@ TownEventDialog::~TownEventDialog()
|
||||
|
||||
void TownEventDialog::initPlayers()
|
||||
{
|
||||
auto playerList = params.value("players").toList();
|
||||
for (int i = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i)
|
||||
{
|
||||
bool isAffected = (1 << i) & params.value("players").toInt();
|
||||
bool isAffected = playerList.contains(toQString(PlayerColor(i)));
|
||||
auto * item = new QListWidgetItem(QString::fromStdString(GameConstants::PLAYER_COLOR_NAMES[i]));
|
||||
item->setData(MapEditorRoles::PlayerIDRole, QVariant::fromValue(i));
|
||||
item->setCheckState(isAffected ? Qt::Checked : Qt::Unchecked);
|
||||
@ -155,7 +157,12 @@ void TownEventDialog::initCreatures()
|
||||
{
|
||||
auto creatures = params.value("creatures").toList();
|
||||
auto * ctown = town.town;
|
||||
for (int i = 0; i < GameConstants::CREATURES_PER_TOWN; ++i)
|
||||
if (!ctown)
|
||||
ui->creaturesTable->setRowCount(GameConstants::CREATURES_PER_TOWN);
|
||||
else
|
||||
ui->creaturesTable->setRowCount(ctown->creatures.size());
|
||||
|
||||
for (int i = 0; i < ui->creaturesTable->rowCount(); ++i)
|
||||
{
|
||||
QString creatureNames;
|
||||
if (!ctown)
|
||||
@ -208,12 +215,12 @@ void TownEventDialog::on_TownEventDialog_finished(int result)
|
||||
|
||||
QVariant TownEventDialog::playersToVariant()
|
||||
{
|
||||
int players = 0;
|
||||
QVariantList players;
|
||||
for (int i = 0; i < ui->playersAffected->count(); ++i)
|
||||
{
|
||||
auto * item = ui->playersAffected->item(i);
|
||||
if (item->checkState() == Qt::Checked)
|
||||
players |= 1 << i;
|
||||
players.push_back(toQString(PlayerColor(i)));
|
||||
}
|
||||
return QVariant::fromValue(players);
|
||||
}
|
||||
@ -239,7 +246,7 @@ QVariantList TownEventDialog::buildingsToVariant()
|
||||
QVariantList TownEventDialog::creaturesToVariant()
|
||||
{
|
||||
QVariantList creaturesList;
|
||||
for (int i = 0; i < GameConstants::CREATURES_PER_TOWN; ++i)
|
||||
for (int i = 0; i < ui->creaturesTable->rowCount(); ++i)
|
||||
{
|
||||
auto * item = static_cast<QSpinBox *>(ui->creaturesTable->cellWidget(i, 1));
|
||||
creaturesList.push_back(item->value());
|
||||
|
@ -17,7 +17,7 @@ static QVariantMap JsonToMap(const JsonMap & json)
|
||||
QVariantMap map;
|
||||
for(auto & entry : json)
|
||||
{
|
||||
map.insert(QString::fromUtf8(entry.first.c_str()), JsonUtils::toVariant(entry.second));
|
||||
map.insert(QString::fromStdString(entry.first), JsonUtils::toVariant(entry.second));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
@ -61,23 +61,18 @@ QVariant toVariant(const JsonNode & node)
|
||||
{
|
||||
switch(node.getType())
|
||||
{
|
||||
break;
|
||||
case JsonNode::JsonType::DATA_NULL:
|
||||
return QVariant();
|
||||
break;
|
||||
case JsonNode::JsonType::DATA_BOOL:
|
||||
return QVariant(node.Bool());
|
||||
break;
|
||||
case JsonNode::JsonType::DATA_FLOAT:
|
||||
case JsonNode::JsonType::DATA_INTEGER:
|
||||
return QVariant(node.Float());
|
||||
break;
|
||||
case JsonNode::JsonType::DATA_INTEGER:
|
||||
return QVariant{static_cast<qlonglong>(node.Integer())};
|
||||
case JsonNode::JsonType::DATA_STRING:
|
||||
return QVariant(QString::fromUtf8(node.String().c_str()));
|
||||
break;
|
||||
return QVariant(QString::fromStdString(node.String()));
|
||||
case JsonNode::JsonType::DATA_VECTOR:
|
||||
return JsonToList(node.Vector());
|
||||
break;
|
||||
case JsonNode::JsonType::DATA_STRUCT:
|
||||
return JsonToMap(node.Struct());
|
||||
}
|
||||
@ -87,33 +82,31 @@ QVariant toVariant(const JsonNode & node)
|
||||
QVariant JsonFromFile(QString filename)
|
||||
{
|
||||
QFile file(filename);
|
||||
file.open(QFile::ReadOnly);
|
||||
auto data = file.readAll();
|
||||
if(!file.open(QFile::ReadOnly))
|
||||
{
|
||||
logGlobal->error("Failed to open file %s. Reason: %s", qUtf8Printable(filename), qUtf8Printable(file.errorString()));
|
||||
return {};
|
||||
}
|
||||
|
||||
if(data.size() == 0)
|
||||
{
|
||||
logGlobal->error("Failed to open file %s", filename.toUtf8().data());
|
||||
return QVariant();
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonNode node(reinterpret_cast<const std::byte*>(data.data()), data.size(), filename.toStdString());
|
||||
return toVariant(node);
|
||||
}
|
||||
const auto data = file.readAll();
|
||||
JsonNode node(reinterpret_cast<const std::byte*>(data.data()), data.size(), filename.toStdString());
|
||||
return toVariant(node);
|
||||
}
|
||||
|
||||
JsonNode toJson(QVariant object)
|
||||
{
|
||||
JsonNode ret;
|
||||
|
||||
if(object.canConvert<QVariantMap>())
|
||||
ret.Struct() = VariantToMap(object.toMap());
|
||||
else if(object.canConvert<QVariantList>())
|
||||
ret.Vector() = VariantToList(object.toList());
|
||||
else if(object.userType() == QMetaType::QString)
|
||||
if(object.userType() == QMetaType::QString)
|
||||
ret.String() = object.toString().toUtf8().data();
|
||||
else if(object.userType() == QMetaType::Bool)
|
||||
ret.Bool() = object.toBool();
|
||||
else if(object.canConvert<QVariantMap>())
|
||||
ret.Struct() = VariantToMap(object.toMap());
|
||||
else if(object.canConvert<QVariantList>())
|
||||
ret.Vector() = VariantToList(object.toList());
|
||||
else if(object.canConvert<int>())
|
||||
ret.Integer() = object.toInt();
|
||||
else if(object.canConvert<double>())
|
||||
ret.Float() = object.toFloat();
|
||||
|
||||
|
@ -16,11 +16,16 @@
|
||||
#include "../../lib/constants/NumericConstants.h"
|
||||
#include "../../lib/constants/StringConstants.h"
|
||||
|
||||
QString toQString(const PlayerColor & player)
|
||||
{
|
||||
return QString::fromStdString(player.toString());
|
||||
}
|
||||
|
||||
QVariant toVariant(const std::set<PlayerColor> & players)
|
||||
{
|
||||
QVariantList result;
|
||||
for(auto const id : players)
|
||||
result.push_back(QString::fromStdString(id.toString()));
|
||||
result.push_back(toQString(id));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ namespace Ui {
|
||||
class EventSettings;
|
||||
}
|
||||
|
||||
QString toQString(const PlayerColor & player);
|
||||
QVariant toVariant(const TResources & resources);
|
||||
QVariant toVariant(const std::set<PlayerColor> & players);
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "StdInc.h"
|
||||
#include "timedevent.h"
|
||||
#include "ui_timedevent.h"
|
||||
#include "eventsettings.h"
|
||||
#include "../../lib/constants/EntityIdentifiers.h"
|
||||
#include "../../lib/constants/StringConstants.h"
|
||||
|
||||
@ -30,9 +31,10 @@ TimedEvent::TimedEvent(QListWidgetItem * t, QWidget *parent) :
|
||||
ui->eventFirstOccurrence->setValue(params.value("firstOccurrence").toInt());
|
||||
ui->eventRepeatAfter->setValue(params.value("nextOccurrence").toInt());
|
||||
|
||||
auto playerList = params.value("players").toList();
|
||||
for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i)
|
||||
{
|
||||
bool isAffected = (1 << i) & params.value("players").toInt();
|
||||
bool isAffected = playerList.contains(toQString(PlayerColor(i)));
|
||||
auto * item = new QListWidgetItem(QString::fromStdString(GameConstants::PLAYER_COLOR_NAMES[i]));
|
||||
item->setData(Qt::UserRole, QVariant::fromValue(i));
|
||||
item->setCheckState(isAffected ? Qt::Checked : Qt::Unchecked);
|
||||
@ -69,12 +71,12 @@ void TimedEvent::on_TimedEvent_finished(int result)
|
||||
descriptor["firstOccurrence"] = QVariant::fromValue(ui->eventFirstOccurrence->value());
|
||||
descriptor["nextOccurrence"] = QVariant::fromValue(ui->eventRepeatAfter->value());
|
||||
|
||||
int players = 0;
|
||||
QVariantList players;
|
||||
for(int i = 0; i < ui->playersAffected->count(); ++i)
|
||||
{
|
||||
auto * item = ui->playersAffected->item(i);
|
||||
if(item->checkState() == Qt::Checked)
|
||||
players |= 1 << i;
|
||||
players.push_back(toQString(PlayerColor(i)));
|
||||
}
|
||||
descriptor["players"] = QVariant::fromValue(players);
|
||||
|
||||
|
@ -67,22 +67,22 @@
|
||||
<message>
|
||||
<location filename="../mapsettings/generalsettings.ui" line="52"/>
|
||||
<source>Author</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Autor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mapsettings/generalsettings.ui" line="62"/>
|
||||
<source>Author contact (e.g. email)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Contato do autor (ex.: e-mail)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mapsettings/generalsettings.ui" line="72"/>
|
||||
<source>Map Creation Time</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Data de Criação do Mapa</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mapsettings/generalsettings.ui" line="86"/>
|
||||
<source>Map Version</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Versão do Mapa</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mapsettings/generalsettings.ui" line="120"/>
|
||||
@ -947,17 +947,17 @@
|
||||
<message>
|
||||
<location filename="../mapcontroller.cpp" line="405"/>
|
||||
<source>Can't place object</source>
|
||||
<translation type="unfinished">Não é possível colocar objeto</translation>
|
||||
<translation>Não é possível colocar objeto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mapcontroller.cpp" line="577"/>
|
||||
<source>There can only be one grail object on the map.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Pode haver apenas um objeto graal no mapa.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mapcontroller.cpp" line="583"/>
|
||||
<source>Hero %1 cannot be created as NEUTRAL.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>O herói %1 não pode ser criado como NEUTRO.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -1762,17 +1762,17 @@
|
||||
<message>
|
||||
<location filename="../validator.cpp" line="148"/>
|
||||
<source>Spell scroll %1 doesn't have instance assigned and must be removed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>O pergaminho de feitiço %1 não tem uma instância atribuída e deve ser removido</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../validator.cpp" line="154"/>
|
||||
<source>Artifact %1 is prohibited by map settings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>O artefato %1 é proibido pelas configurações do mapa</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../validator.cpp" line="168"/>
|
||||
<source>Player %1 has no towns and heroes assigned</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>O jogador %1 não tem cidades e heróis atribuídos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../validator.cpp" line="116"/>
|
||||
|
@ -150,6 +150,10 @@ bool WindowNewMap::loadUserSettings()
|
||||
ui->monsterOpt4->setChecked(true); break;
|
||||
}
|
||||
|
||||
ui->roadDirt->setChecked(mapGenOptions.isRoadEnabled(Road::DIRT_ROAD));
|
||||
ui->roadGravel->setChecked(mapGenOptions.isRoadEnabled(Road::GRAVEL_ROAD));
|
||||
ui->roadCobblestone->setChecked(mapGenOptions.isRoadEnabled(Road::COBBLESTONE_ROAD));
|
||||
|
||||
ret = true;
|
||||
}
|
||||
|
||||
@ -236,6 +240,10 @@ void WindowNewMap::on_okButton_clicked()
|
||||
|
||||
mapGenOptions.setWaterContent(water);
|
||||
mapGenOptions.setMonsterStrength(monster);
|
||||
|
||||
mapGenOptions.setRoadEnabled(Road::DIRT_ROAD, ui->roadDirt->isChecked());
|
||||
mapGenOptions.setRoadEnabled(Road::GRAVEL_ROAD, ui->roadGravel->isChecked());
|
||||
mapGenOptions.setRoadEnabled(Road::COBBLESTONE_ROAD, ui->roadCobblestone->isChecked());
|
||||
|
||||
saveUserSettings();
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>444</width>
|
||||
<height>445</height>
|
||||
<height>506</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -52,7 +52,7 @@
|
||||
<x>0</x>
|
||||
<y>20</y>
|
||||
<width>281</width>
|
||||
<height>68</height>
|
||||
<height>73</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="3,0,1">
|
||||
@ -72,7 +72,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="inputMethodHints">
|
||||
<set>Qt::ImhDigitsOnly</set>
|
||||
<set>Qt::InputMethodHint::ImhDigitsOnly</set>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">36</string>
|
||||
@ -98,7 +98,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="inputMethodHints">
|
||||
<set>Qt::ImhDigitsOnly</set>
|
||||
<set>Qt::InputMethodHint::ImhDigitsOnly</set>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">36</string>
|
||||
@ -132,10 +132,10 @@
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
@ -207,7 +207,7 @@
|
||||
<x>10</x>
|
||||
<y>140</y>
|
||||
<width>431</width>
|
||||
<height>301</height>
|
||||
<height>361</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -237,7 +237,7 @@
|
||||
<x>10</x>
|
||||
<y>20</y>
|
||||
<width>391</width>
|
||||
<height>68</height>
|
||||
<height>72</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0,0">
|
||||
@ -546,7 +546,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
@ -675,7 +675,104 @@
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>230</y>
|
||||
<width>411</width>
|
||||
<height>51</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>480</width>
|
||||
<height>96</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Roads</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="layoutWidget4_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>20</y>
|
||||
<width>411</width>
|
||||
<height>26</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5" stretch="0,0,0,0,0,1">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="roadDirt">
|
||||
<property name="text">
|
||||
<string>Dirt</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="roadGravel">
|
||||
<property name="text">
|
||||
<string>Gravel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="roadCobblestone">
|
||||
<property name="text">
|
||||
<string>Cobblestone</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
@ -692,9 +789,9 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>230</y>
|
||||
<y>280</y>
|
||||
<width>411</width>
|
||||
<height>32</height>
|
||||
<height>34</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
@ -732,37 +829,37 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QLineEdit" name="lineSeed">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>280</x>
|
||||
<y>270</y>
|
||||
<width>131</width>
|
||||
<height>21</height>
|
||||
<x>80</x>
|
||||
<y>320</y>
|
||||
<width>283</width>
|
||||
<height>33</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="inputMethodHints">
|
||||
<set>Qt::ImhDigitsOnly</set>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QCheckBox" name="checkSeed">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>110</x>
|
||||
<y>270</y>
|
||||
<width>161</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Custom seed</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkSeed">
|
||||
<property name="text">
|
||||
<string>Custom seed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineSeed">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="inputMethodHints">
|
||||
<set>Qt::InputMethodHint::ImhDigitsOnly</set>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QCheckBox" name="randomMapCheck">
|
||||
|
@ -1171,7 +1171,6 @@ void CGameHandler::heroVisitCastle(const CGTownInstance * obj, const CGHeroInsta
|
||||
sendAndApply(&vc);
|
||||
}
|
||||
visitCastleObjects(obj, hero);
|
||||
giveSpells (obj, hero);
|
||||
|
||||
if (obj->visitingHero && obj->garrisonHero)
|
||||
useScholarSkill(obj->visitingHero->id, obj->garrisonHero->id);
|
||||
@ -1180,10 +1179,27 @@ void CGameHandler::heroVisitCastle(const CGTownInstance * obj, const CGHeroInsta
|
||||
|
||||
void CGameHandler::visitCastleObjects(const CGTownInstance * t, const CGHeroInstance * h)
|
||||
{
|
||||
std::vector<const CGHeroInstance * > visitors;
|
||||
visitors.push_back(h);
|
||||
visitCastleObjects(t, visitors);
|
||||
}
|
||||
|
||||
void CGameHandler::visitCastleObjects(const CGTownInstance * t, std::vector<const CGHeroInstance * > visitors)
|
||||
{
|
||||
std::vector<BuildingID> buildingsToVisit;
|
||||
for (auto const & hero : visitors)
|
||||
giveSpells (t, hero);
|
||||
|
||||
for (auto & building : t->rewardableBuildings)
|
||||
{
|
||||
if (!t->town->buildings.at(building.first)->manualHeroVisit)
|
||||
building.second->onHeroVisit(h);
|
||||
buildingsToVisit.push_back(building.first);
|
||||
}
|
||||
|
||||
if (!buildingsToVisit.empty())
|
||||
{
|
||||
auto visitQuery = std::make_shared<TownBuildingVisitQuery>(this, t, visitors, buildingsToVisit);
|
||||
queries->addQuery(visitQuery);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2144,10 +2160,15 @@ bool CGameHandler::buildStructure(ObjectInstanceID tid, BuildingID requestedID,
|
||||
|
||||
if (!force)
|
||||
{
|
||||
if(t->garrisonHero) //garrison hero first - consistent with original H3 Mana Vortex and Battle Scholar Academy levelup windows order
|
||||
objectVisited(t, t->garrisonHero);
|
||||
if(t->visitingHero)
|
||||
objectVisited(t, t->visitingHero);
|
||||
//garrison hero first - consistent with original H3 Mana Vortex and Battle Scholar Academy levelup windows order
|
||||
std::vector<const CGHeroInstance *> visitors;
|
||||
if (t->garrisonHero)
|
||||
visitors.push_back(t->garrisonHero);
|
||||
if (t->visitingHero)
|
||||
visitors.push_back(t->visitingHero);
|
||||
|
||||
if (!visitors.empty())
|
||||
visitCastleObjects(t, visitors);
|
||||
}
|
||||
|
||||
checkVictoryLossConditionsForPlayer(t->tempOwner);
|
||||
@ -2173,19 +2194,15 @@ bool CGameHandler::visitTownBuilding(ObjectInstanceID tid, BuildingID bid)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t->rewardableBuildings.count(bid))
|
||||
if (t->rewardableBuildings.count(bid) && t->visitingHero && t->town->buildings.at(bid)->manualHeroVisit)
|
||||
{
|
||||
auto & hero = t->garrisonHero ? t->garrisonHero : t->visitingHero;
|
||||
auto * building = t->rewardableBuildings.at(bid);
|
||||
|
||||
if (hero && t->town->buildings.at(bid)->manualHeroVisit)
|
||||
{
|
||||
auto visitQuery = std::make_shared<TownBuildingVisitQuery>(this, t, hero, bid);
|
||||
queries->addQuery(visitQuery);
|
||||
building->onHeroVisit(hero);
|
||||
queries->popIfTop(visitQuery);
|
||||
return true;
|
||||
}
|
||||
std::vector<BuildingID> buildingsToVisit;
|
||||
std::vector<const CGHeroInstance*> visitors;
|
||||
buildingsToVisit.push_back(bid);
|
||||
visitors.push_back(t->visitingHero);
|
||||
auto visitQuery = std::make_shared<TownBuildingVisitQuery>(this, t, visitors, buildingsToVisit);
|
||||
queries->addQuery(visitQuery);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -182,6 +182,7 @@ public:
|
||||
void visitObjectOnTile(const TerrainTile &t, const CGHeroInstance * h);
|
||||
bool teleportHero(ObjectInstanceID hid, ObjectInstanceID dstid, ui8 source, PlayerColor asker = PlayerColor::NEUTRAL);
|
||||
void visitCastleObjects(const CGTownInstance * obj, const CGHeroInstance * hero) override;
|
||||
void visitCastleObjects(const CGTownInstance * obj, std::vector<const CGHeroInstance * > visitors);
|
||||
void levelUpHero(const CGHeroInstance * hero, SecondarySkill skill);//handle client respond and send one more request if needed
|
||||
void levelUpHero(const CGHeroInstance * hero);//initial call - check if hero have remaining levelups & handle them
|
||||
void levelUpCommander (const CCommanderInstance * c, int skill); //secondary skill 1 to 6, special skill : skill - 100
|
||||
|
@ -110,7 +110,7 @@ void NewTurnProcessor::handleTownEvents(const CGTownInstance * town)
|
||||
|
||||
for (si32 i=0;i<event.creatures.size();i++) //creature growths
|
||||
{
|
||||
if (!town->creatures.at(i).second.empty() && event.creatures.at(i) > 0)//there is dwelling
|
||||
if (i < town->creatures.size() && !town->creatures.at(i).second.empty() && event.creatures.at(i) > 0)//there is dwelling
|
||||
{
|
||||
sac.creatures[i].first += event.creatures.at(i);
|
||||
iw.components.emplace_back(ComponentType::CREATURE, town->creatures.at(i).second.back(), event.creatures.at(i));
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "VisitQueries.h"
|
||||
|
||||
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
#include "../../lib/mapObjects/TownBuildingInstance.h"
|
||||
#include "../CGameHandler.h"
|
||||
#include "QueriesProcessor.h"
|
||||
|
||||
@ -29,7 +31,7 @@ bool VisitQuery::blocksPack(const CPack * pack) const
|
||||
return true;
|
||||
}
|
||||
|
||||
void VisitQuery::onExposure(QueryPtr topQuery)
|
||||
void MapObjectVisitQuery::onExposure(QueryPtr topQuery)
|
||||
{
|
||||
//Object may have been removed and deleted.
|
||||
if(gh->isValidObject(visitedObject))
|
||||
@ -54,13 +56,31 @@ void MapObjectVisitQuery::onRemoval(PlayerColor color)
|
||||
gh->removeObject(visitedObject, color);
|
||||
}
|
||||
|
||||
TownBuildingVisitQuery::TownBuildingVisitQuery(CGameHandler * owner, const CGObjectInstance * Obj, const CGHeroInstance * Hero, BuildingID buildingToVisit)
|
||||
: VisitQuery(owner, Obj, Hero)
|
||||
, visitedBuilding(buildingToVisit)
|
||||
TownBuildingVisitQuery::TownBuildingVisitQuery(CGameHandler * owner, const CGTownInstance * Obj, std::vector<const CGHeroInstance *> heroes, std::vector<BuildingID> buildingToVisit)
|
||||
: VisitQuery(owner, Obj, heroes.front())
|
||||
, visitedTown(Obj)
|
||||
{
|
||||
// generate in reverse order - first building-hero pair to handle must be in the end of vector
|
||||
for (auto const * hero : boost::adaptors::reverse(heroes))
|
||||
for (auto const & building : boost::adaptors::reverse(buildingToVisit))
|
||||
visitedBuilding.push_back({ hero, building});
|
||||
}
|
||||
|
||||
void TownBuildingVisitQuery::onRemoval(PlayerColor color)
|
||||
void TownBuildingVisitQuery::onExposure(QueryPtr topQuery)
|
||||
{
|
||||
|
||||
onAdded(players.front());
|
||||
}
|
||||
|
||||
void TownBuildingVisitQuery::onAdded(PlayerColor color)
|
||||
{
|
||||
while (!visitedBuilding.empty() && owner->topQuery(color).get() == this)
|
||||
{
|
||||
visitingHero = visitedBuilding.back().hero;
|
||||
auto * building = visitedTown->rewardableBuildings.at(visitedBuilding.back().building);
|
||||
building->onHeroVisit(visitingHero);
|
||||
visitedBuilding.pop_back();
|
||||
}
|
||||
|
||||
if (visitedBuilding.empty() && owner->topQuery(color).get() == this)
|
||||
owner->popIfTop(*this);
|
||||
}
|
||||
|
@ -11,19 +11,22 @@
|
||||
|
||||
#include "CQuery.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class CGTownInstance;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
//Created when hero visits object.
|
||||
//Removed when query above is resolved (or immediately after visit if no queries were created)
|
||||
class VisitQuery : public CQuery
|
||||
{
|
||||
protected:
|
||||
VisitQuery(CGameHandler * owner, const CGObjectInstance *Obj, const CGHeroInstance *Hero);
|
||||
VisitQuery(CGameHandler * owner, const CGObjectInstance * Obj, const CGHeroInstance * Hero);
|
||||
|
||||
public:
|
||||
const CGObjectInstance *visitedObject;
|
||||
const CGHeroInstance *visitingHero;
|
||||
const CGObjectInstance * visitedObject;
|
||||
const CGHeroInstance * visitingHero;
|
||||
|
||||
bool blocksPack(const CPack *pack) const final;
|
||||
void onExposure(QueryPtr topQuery) final;
|
||||
bool blocksPack(const CPack * pack) const final;
|
||||
};
|
||||
|
||||
class MapObjectVisitQuery final : public VisitQuery
|
||||
@ -31,17 +34,26 @@ class MapObjectVisitQuery final : public VisitQuery
|
||||
public:
|
||||
bool removeObjectAfterVisit;
|
||||
|
||||
MapObjectVisitQuery(CGameHandler * owner, const CGObjectInstance *Obj, const CGHeroInstance *Hero);
|
||||
MapObjectVisitQuery(CGameHandler * owner, const CGObjectInstance * Obj, const CGHeroInstance * Hero);
|
||||
|
||||
void onRemoval(PlayerColor color) final;
|
||||
void onExposure(QueryPtr topQuery) final;
|
||||
};
|
||||
|
||||
class TownBuildingVisitQuery final : public VisitQuery
|
||||
{
|
||||
struct BuildingVisit
|
||||
{
|
||||
const CGHeroInstance * hero;
|
||||
BuildingID building;
|
||||
};
|
||||
|
||||
const CGTownInstance * visitedTown;
|
||||
std::vector<BuildingVisit> visitedBuilding;
|
||||
|
||||
public:
|
||||
BuildingID visitedBuilding;
|
||||
TownBuildingVisitQuery(CGameHandler * owner, const CGTownInstance * Obj, std::vector<const CGHeroInstance *> heroes, std::vector<BuildingID> buildingToVisit);
|
||||
|
||||
TownBuildingVisitQuery(CGameHandler * owner, const CGObjectInstance *Obj, const CGHeroInstance *Hero, BuildingID buildingToVisit);
|
||||
|
||||
void onRemoval(PlayerColor color) final;
|
||||
void onAdded(PlayerColor color) final;
|
||||
void onExposure(QueryPtr topQuery) final;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user