diff --git a/client/adventureMap/AdventureMapInterface.cpp b/client/adventureMap/AdventureMapInterface.cpp index 7ee136edd..740b84a48 100644 --- a/client/adventureMap/AdventureMapInterface.cpp +++ b/client/adventureMap/AdventureMapInterface.cpp @@ -394,8 +394,9 @@ void AdventureMapInterface::onPlayerTurnStarted(PlayerColor playerID) LOCPLINT->localState->setSelection(LOCPLINT->localState->getWanderingHero(0)); } - //show new day animation and sound on infobar - widget->getInfoBar()->showDate(); + //show new day animation and sound on infobar, except for 1st day of the game + if (LOCPLINT->cb->getDate(Date::DAY) != 1) + widget->getInfoBar()->showDate(); onHeroChanged(nullptr); Canvas canvas = Canvas::createFromSurface(screen); diff --git a/client/adventureMap/CList.cpp b/client/adventureMap/CList.cpp index 23c325ea9..e53968d9f 100644 --- a/client/adventureMap/CList.cpp +++ b/client/adventureMap/CList.cpp @@ -287,8 +287,28 @@ void CHeroList::updateElement(const CGHeroInstance * hero) void CHeroList::updateWidget() { - listBox->resize(LOCPLINT->localState->getWanderingHeroes().size()); - listBox->reset(); + auto & heroes = LOCPLINT->localState->getWanderingHeroes(); + + listBox->resize(heroes.size()); + + for (size_t i = 0; i < heroes.size(); ++i) + { + auto item = std::dynamic_pointer_cast(listBox->getItem(i)); + + if (!item) + continue; + + if (item->hero == heroes[i]) + { + item->update(); + } + else + { + listBox->reset(); + break; + } + } + if (LOCPLINT->localState->getCurrentHero()) select(LOCPLINT->localState->getCurrentHero()); @@ -364,8 +384,28 @@ void CTownList::updateElement(const CGTownInstance * town) void CTownList::updateWidget() { - listBox->resize(LOCPLINT->localState->getOwnedTowns().size()); - listBox->reset(); + auto & towns = LOCPLINT->localState->getOwnedTowns(); + + listBox->resize(towns.size()); + + for (size_t i = 0; i < towns.size(); ++i) + { + auto item = std::dynamic_pointer_cast(listBox->getItem(i)); + + if (!item) + continue; + + if (item->town == towns[i]) + { + item->update(); + } + else + { + listBox->reset(); + break; + } + } + if (LOCPLINT->localState->getCurrentTown()) select(LOCPLINT->localState->getCurrentTown()); diff --git a/client/gui/EventDispatcher.cpp b/client/gui/EventDispatcher.cpp index 290cf1ee6..c09d95826 100644 --- a/client/gui/EventDispatcher.cpp +++ b/client/gui/EventDispatcher.cpp @@ -172,6 +172,15 @@ void EventDispatcher::dispatchClosePopup(const Point & position) void EventDispatcher::handleLeftButtonClick(const Point & position, bool isPressed) { + // WARNING: this approach is NOT SAFE + // 1) We allow (un)registering elements when list itself is being processed/iterated + // 2) To avoid iterator invalidation we create a copy of this list for processing + // HOWEVER it is completely possible (as in, actually happen, no just theory) to: + // 1) element gets unregistered and deleted from lclickable + // 2) element is completely deleted, as in - destructor called, memory freed + // 3) new element is created *with exactly same address(!) + // 4) new element is registered and code will incorrectly assume that this element is still registered + // POSSIBLE SOLUTION: make EventReceivers inherit from create_shared_from this and store weak_ptr's in lists auto hlp = lclickable; for(auto & i : hlp) { diff --git a/launcher/aboutProject/aboutproject_moc.cpp b/launcher/aboutProject/aboutproject_moc.cpp index 769e95bac..b24f9e85d 100644 --- a/launcher/aboutProject/aboutproject_moc.cpp +++ b/launcher/aboutProject/aboutproject_moc.cpp @@ -29,6 +29,14 @@ AboutProjectView::AboutProjectView(QWidget * parent) ui->lineEditOperatingSystem->setText(QSysInfo::prettyProductName()); } +void AboutProjectView::changeEvent(QEvent *event) +{ + if(event->type() == QEvent::LanguageChange) + ui->retranslateUi(this); + + QWidget::changeEvent(event); +} + void AboutProjectView::on_updatesButton_clicked() { UpdateDialog::showUpdateDialog(true); diff --git a/launcher/aboutProject/aboutproject_moc.h b/launcher/aboutProject/aboutproject_moc.h index 915f32fac..386565a60 100644 --- a/launcher/aboutProject/aboutproject_moc.h +++ b/launcher/aboutProject/aboutproject_moc.h @@ -21,6 +21,7 @@ class AboutProjectView : public QWidget { Q_OBJECT + void changeEvent(QEvent *event) override; public: explicit AboutProjectView(QWidget * parent = 0); diff --git a/launcher/settingsView/csettingsview_moc.cpp b/launcher/settingsView/csettingsview_moc.cpp index bc1a4ce4e..3690bf68f 100644 --- a/launcher/settingsView/csettingsview_moc.cpp +++ b/launcher/settingsView/csettingsview_moc.cpp @@ -127,7 +127,7 @@ QSize CSettingsView::getPreferredRenderingResolution() return QSize(resX, resY); } #endif - return QApplication::primaryScreen()->geometry().size(); + return QApplication::primaryScreen()->geometry().size() * QApplication::primaryScreen()->devicePixelRatio(); } void CSettingsView::fillValidScalingRange() diff --git a/lib/mapping/MapFeaturesH3M.cpp b/lib/mapping/MapFeaturesH3M.cpp index a5b240576..b5d3a4b7b 100644 --- a/lib/mapping/MapFeaturesH3M.cpp +++ b/lib/mapping/MapFeaturesH3M.cpp @@ -136,7 +136,7 @@ MapFormatFeaturesH3M MapFormatFeaturesH3M::getFeaturesHOTA(uint32_t hotaVersion) { result.artifactsCount = 163; // + HotA artifacts result.heroesCount = 178; // + Cove - result.heroesPortraitsCount = 185; // + Cove + result.heroesPortraitsCount = 186; // + Cove } if(hotaVersion == 3) { diff --git a/lib/mapping/MapFormatH3M.cpp b/lib/mapping/MapFormatH3M.cpp index 4b4f69af7..119f5895e 100644 --- a/lib/mapping/MapFormatH3M.cpp +++ b/lib/mapping/MapFormatH3M.cpp @@ -1735,7 +1735,7 @@ CGObjectInstance * CMapLoaderH3M::readHero(const int3 & mapPosition, const Objec if(!object->spells.empty()) { object->clear(); - logGlobal->warn("Hero %s subID=%d has spells set twice (in map properties and on adventure map instance). Using the latter set...", object->getNameTextID(), object->subID); + logGlobal->debug("Hero %s subID=%d has spells set twice (in map properties and on adventure map instance). Using the latter set...", object->getNameTextID(), object->subID); } object->spells.insert(SpellID::PRESET); //placeholder "preset spells" diff --git a/lib/mapping/MapIdentifiersH3M.cpp b/lib/mapping/MapIdentifiersH3M.cpp index e2eeefb0c..2168848fa 100644 --- a/lib/mapping/MapIdentifiersH3M.cpp +++ b/lib/mapping/MapIdentifiersH3M.cpp @@ -29,7 +29,7 @@ void MapIdentifiersH3M::loadMapping(std::map & resul for (auto entry : mapping.Struct()) { IdentifierID sourceID (entry.second.Integer()); - IdentifierID targetID (*VLC->modh->identifiers.getIdentifier(VLC->modh->scopeGame(), identifierName, entry.first)); + IdentifierID targetID (*VLC->modh->identifiers.getIdentifier(entry.second.meta, identifierName, entry.first)); result[sourceID] = targetID; } @@ -39,13 +39,13 @@ void MapIdentifiersH3M::loadMapping(const JsonNode & mapping) { for (auto entryFaction : mapping["buildings"].Struct()) { - FactionID factionID (*VLC->modh->identifiers.getIdentifier(VLC->modh->scopeGame(), "faction", entryFaction.first)); + FactionID factionID (*VLC->modh->identifiers.getIdentifier(entryFaction.second.meta, "faction", entryFaction.first)); auto buildingMap = entryFaction.second; for (auto entryBuilding : buildingMap.Struct()) { BuildingID sourceID (entryBuilding.second.Integer()); - BuildingID targetID (*VLC->modh->identifiers.getIdentifier(VLC->modh->scopeGame(), "building." + VLC->factions()->getById(factionID)->getJsonKey(), entryBuilding.first)); + BuildingID targetID (*VLC->modh->identifiers.getIdentifier(entryBuilding.second.meta, "building." + VLC->factions()->getById(factionID)->getJsonKey(), entryBuilding.first)); mappingFactionBuilding[factionID][sourceID] = targetID; } @@ -68,7 +68,7 @@ void MapIdentifiersH3M::loadMapping(const JsonNode & mapping) { for (auto entryInner : entryOuter.second.Struct()) { - auto handler = VLC->objtypeh->getHandlerFor( VLC->modh->scopeGame(), entryOuter.first, entryInner.first); + auto handler = VLC->objtypeh->getHandlerFor( entryInner.second.meta, entryOuter.first, entryInner.first); auto entryValues = entryInner.second.Vector(); ObjectTypeIdentifier h3mID{Obj(entryValues[0].Integer()), int32_t(entryValues[1].Integer())}; @@ -78,7 +78,7 @@ void MapIdentifiersH3M::loadMapping(const JsonNode & mapping) } else { - auto handler = VLC->objtypeh->getHandlerFor( VLC->modh->scopeGame(), entryOuter.first, entryOuter.first); + auto handler = VLC->objtypeh->getHandlerFor( entryOuter.second.meta, entryOuter.first, entryOuter.first); auto entryValues = entryOuter.second.Vector(); ObjectTypeIdentifier h3mID{Obj(entryValues[0].Integer()), int32_t(entryValues[1].Integer())}; @@ -90,7 +90,7 @@ void MapIdentifiersH3M::loadMapping(const JsonNode & mapping) for (auto entry : mapping["portraits"].Struct()) { int32_t sourceID = entry.second.Integer(); - int32_t targetID = *VLC->modh->identifiers.getIdentifier(VLC->modh->scopeGame(), "hero", entry.first); + int32_t targetID = *VLC->modh->identifiers.getIdentifier(entry.second.meta, "hero", entry.first); int32_t iconID = VLC->heroTypes()->getByIndex(targetID)->getIconIndex(); mappingHeroPortrait[sourceID] = iconID; diff --git a/server/PlayerMessageProcessor.cpp b/server/PlayerMessageProcessor.cpp index 7ff537d88..28713c413 100644 --- a/server/PlayerMessageProcessor.cpp +++ b/server/PlayerMessageProcessor.cpp @@ -299,7 +299,7 @@ void PlayerMessageProcessor::cheatResources(PlayerColor player, std::vector