From d5b02f8dc2665cedfbfdb12934818ff234b024b5 Mon Sep 17 00:00:00 2001 From: Dydzio Date: Mon, 23 Jan 2023 18:56:00 +0100 Subject: [PATCH 01/79] Add sane aliases for cheat names + "vcmiazure" "vcmifaerie" cheats --- server/CGameHandler.cpp | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index c2de15c0a..eb8163c03 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -7032,7 +7032,7 @@ void CGameHandler::spawnWanderingMonsters(CreatureID creatureID) void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, const CGHeroInstance * hero, const CGTownInstance * town, bool & cheated) { - if (cheat == "vcmiistari") + if (cheat == "vcmiistari" || cheat == "vcmispells") { cheated = true; if (!hero) return; @@ -7058,7 +7058,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons sm.absolute = true; sendAndApply(&sm); } - else if (cheat == "vcmiarmenelos") + else if (cheat == "vcmiarmenelos" || cheat == "vcmibuild") { cheated = true; if (!town) return; @@ -7073,7 +7073,8 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons } } } - else if (cheat == "vcmiainur" || cheat == "vcmiangband" || cheat == "vcmiglaurung") + else if (cheat == "vcmiainur" || cheat == "vcmiangband" || cheat == "vcmiglaurung" || cheat == "vcmiarchangel" + || cheat == "vcmiblackknight" || cheat == "vcmicrystal" || cheat == "vcmiazure" || cheat == "vcmifaerie") { cheated = true; if (!hero) return; @@ -7082,13 +7083,18 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons creatures.insert(std::make_pair("vcmiainur", std::make_pair(13, 5))); //5 archangels creatures.insert(std::make_pair("vcmiangband", std::make_pair(66, 10))); //10 black knights creatures.insert(std::make_pair("vcmiglaurung", std::make_pair(133, 5000))); //5000 crystal dragons + creatures.insert(std::make_pair("vcmiarchangel", std::make_pair(13, 5))); //5 archangels + creatures.insert(std::make_pair("vcmiblackknight", std::make_pair(66, 10))); //10 black knights + creatures.insert(std::make_pair("vcmicrystal", std::make_pair(133, 5000))); //5000 crystal dragons + creatures.insert(std::make_pair("vcmiazure", std::make_pair(132, 5000))); //5000 azure dragons + creatures.insert(std::make_pair("vcmifaerie", std::make_pair(134, 5000))); //5000 faerie dragons const CCreature * creature = VLC->creh->objects.at(creatures[cheat].first); for (int i = 0; i < GameConstants::ARMY_SIZE; i++) if (!hero->hasStackAtSlot(SlotID(i))) insertNewStack(StackLocation(hero, SlotID(i)), creature, creatures[cheat].second); } - else if (cheat == "vcminoldor") + else if (cheat == "vcminoldor" || cheat == "vcmimachines") { cheated = true; if (!hero) return; @@ -7100,7 +7106,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons if (!hero->getArt(ArtifactPosition::MACH3)) giveHeroNewArtifact(hero, VLC->arth->objects[ArtifactID::FIRST_AID_TENT], ArtifactPosition::MACH3); } - else if (cheat == "vcmiforgeofnoldorking") + else if (cheat == "vcmiforgeofnoldorking" || cheat == "vcmiartifacts") { cheated = true; if (!hero) return; @@ -7108,14 +7114,14 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons for (int g = 7; g < VLC->arth->objects.size(); ++g) //including artifacts from mods giveHeroNewArtifact(hero, VLC->arth->objects[g], ArtifactPosition::PRE_FIRST); } - else if (cheat == "vcmiglorfindel") + else if (cheat == "vcmiglorfindel" || cheat == "vcmilevel") { cheated = true; if (!hero) return; ///selected hero gains a new level changePrimSkill(hero, PrimarySkill::EXPERIENCE, VLC->heroh->reqExp(hero->level + 1) - VLC->heroh->reqExp(hero->level)); } - else if (cheat == "vcminahar") + else if (cheat == "vcminahar" || cheat == "vcmimove") { cheated = true; if (!hero) return; @@ -7132,7 +7138,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons gb.id = hero->id.getNum(); giveHeroBonus(&gb); } - else if (cheat == "vcmiformenos") + else if (cheat == "vcmiformenos" || cheat == "vcmiresources") { cheated = true; ///Give resources to player @@ -7143,7 +7149,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons giveResources(player, resources); } - else if (cheat == "vcmisilmaril") + else if (cheat == "vcmisilmaril" || cheat == "vcmiwin") { cheated = true; ///Player wins @@ -7152,7 +7158,7 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons pc.winningCheatCode = true; sendAndApply(&pc); } - else if (cheat == "vcmimelkor") + else if (cheat == "vcmimelkor" || cheat == "vcmilose") { cheated = true; ///Player looses @@ -7161,12 +7167,12 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons pc.losingCheatCode = true; sendAndApply(&pc); } - else if (cheat == "vcmieagles" || cheat == "vcmiungoliant") + else if (cheat == "vcmieagles" || cheat == "vcmiungoliant" || cheat == "vcmimap" || cheat == "vcmihidemap") { cheated = true; ///Reveal or conceal FoW FoWChange fc; - fc.mode = (cheat == "vcmieagles" ? 1 : 0); + fc.mode = ((cheat == "vcmieagles" || cheat == "vcmimap") ? 1 : 0); fc.player = player; const auto & fowMap = gs->getPlayerTeam(player)->fogOfWarMap; auto hlp_tab = new int3[gs->map->width * gs->map->height * (gs->map->levels())]; From 75e0bfa80c7fec6bacbf3d8986c83630be5a0eb9 Mon Sep 17 00:00:00 2001 From: Dydzio Date: Mon, 23 Jan 2023 21:18:43 +0100 Subject: [PATCH 02/79] Add vcmiarmy cheat --- server/CGameHandler.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index eb8163c03..53330c201 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -5130,7 +5130,14 @@ void CGameHandler::playerMessage(PlayerColor player, const std::string &message, town = hero->visitedTown; if (words.size() == 1 || obj) + { handleCheatCode(words[0], player, hero, town, cheated); + } + else if(words[0] == "vcmiarmy" && words.size() > 1) + { + std::string cheatCodeWithCreatureIdentifier = std::string(words[0]) + " " + words[1]; + handleCheatCode(cheatCodeWithCreatureIdentifier, player, hero, town, cheated); + } else { for (const auto & i : gs->players) @@ -7094,6 +7101,34 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons if (!hero->hasStackAtSlot(SlotID(i))) insertNewStack(StackLocation(hero, SlotID(i)), creature, creatures[cheat].second); } + else if (boost::starts_with(cheat, "vcmiarmy")) + { + cheated = true; + if (!hero) return; + + std::vector words; + boost::split(words, cheat, boost::is_any_of(" ")); + + if(words.size() < 2) + return; + + std::string creatureIdentifier = words[1]; + + auto creature = vstd::tryFindIf(VLC->creh->objects, + [creatureIdentifier](auto x) + { + std::string identifier = x->getJsonKey(); + boost::to_lower(identifier); + return identifier == creatureIdentifier; + }); + + if(creature.is_initialized()) + { + for (int i = 0; i < GameConstants::ARMY_SIZE; i++) + if (!hero->hasStackAtSlot(SlotID(i))) + insertNewStack(StackLocation(hero, SlotID(i)), creature->get(), 5 * std::pow(10, i)); + } + } else if (cheat == "vcminoldor" || cheat == "vcmimachines") { cheated = true; From 583f1ce911c5223347492990ba9ffbe262e24907 Mon Sep 17 00:00:00 2001 From: Dydzio Date: Mon, 23 Jan 2023 23:12:41 +0100 Subject: [PATCH 03/79] Implemented vcmiexp cheat --- server/CGameHandler.cpp | 42 ++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 53330c201..481b1cf37 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -5117,7 +5117,7 @@ void CGameHandler::playerMessage(PlayerColor player, const std::string &message, } int obj = 0; - if (words.size() == 2) + if (words.size() == 2 && words[0] != "vcmiexp") { obj = std::atoi(words[1].c_str()); if (obj) @@ -5129,15 +5129,15 @@ void CGameHandler::playerMessage(PlayerColor player, const std::string &message, if (!town && hero) town = hero->visitedTown; - if (words.size() == 1 || obj) + if((words[0] == "vcmiarmy" || words[0] == "vcmiexp") && words.size() > 1) + { + std::string cheatCodeWithOneParameter = std::string(words[0]) + " " + words[1]; + handleCheatCode(cheatCodeWithOneParameter, player, hero, town, cheated); + } + else if (words.size() == 1 || obj) { handleCheatCode(words[0], player, hero, town, cheated); } - else if(words[0] == "vcmiarmy" && words.size() > 1) - { - std::string cheatCodeWithCreatureIdentifier = std::string(words[0]) + " " + words[1]; - handleCheatCode(cheatCodeWithCreatureIdentifier, player, hero, town, cheated); - } else { for (const auto & i : gs->players) @@ -7156,6 +7156,34 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons ///selected hero gains a new level changePrimSkill(hero, PrimarySkill::EXPERIENCE, VLC->heroh->reqExp(hero->level + 1) - VLC->heroh->reqExp(hero->level)); } + else if (boost::starts_with(cheat, "vcmiexp")) + { + cheated = true; + if (!hero) return; + + std::vector words; + boost::split(words, cheat, boost::is_any_of(" ")); + + if(words.size() < 2) + return; + + std::string expAmount = words[1]; + long expAmountProcessed = 0; + + try + { + expAmountProcessed = std::stol(expAmount); + } + catch(std::exception&) + { + logGlobal->error("Could not parse experience amount for vcmiexp cheat"); + } + + if(expAmountProcessed > 1) + { + changePrimSkill(hero, PrimarySkill::EXPERIENCE, expAmountProcessed); + } + } else if (cheat == "vcminahar" || cheat == "vcmimove") { cheated = true; From 3d9f04c6e0831b2c0e4068b14375aefa901be3d7 Mon Sep 17 00:00:00 2001 From: Dydzio Date: Wed, 25 Jan 2023 12:10:48 +0100 Subject: [PATCH 04/79] Minor cheats code changes --- lib/CModHandler.h | 2 +- server/CGameHandler.cpp | 38 ++++++++++++++++++++------------------ 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/lib/CModHandler.h b/lib/CModHandler.h index 64e4c420a..a4552f355 100644 --- a/lib/CModHandler.h +++ b/lib/CModHandler.h @@ -30,7 +30,7 @@ class IHandlerBase; /// class that stores all object identifiers strings and maps them to numeric ID's /// if possible, objects ID's should be in format ., camelCase e.g. "creature.grandElf" -class CIdentifierStorage +class DLL_LINKAGE CIdentifierStorage { enum ELoadingState { diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 481b1cf37..b412ef7a7 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -5152,11 +5152,12 @@ void CGameHandler::playerMessage(PlayerColor player, const std::string &message, else if (words[1] != "all" && words[1] != i.first.getStr()) continue; - if (words[0] == "vcmiformenos" || words[0] == "vcmieagles" || words[0] == "vcmiungoliant") + if (words[0] == "vcmiformenos" || words[0] == "vcmieagles" || words[0] == "vcmiungoliant" + || words[0] == "vcmiresources" || words[0] == "vcmimap" || words[0] == "vcmihidemap") { handleCheatCode(words[0], i.first, nullptr, nullptr, cheated); } - else if (words[0] == "vcmiarmenelos") + else if (words[0] == "vcmiarmenelos" || words[0] == "vcmibuild") { for (const auto & t : i.second.towns) { @@ -7086,17 +7087,18 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons cheated = true; if (!hero) return; ///Gives N creatures into each slot - std::map> creatures; - creatures.insert(std::make_pair("vcmiainur", std::make_pair(13, 5))); //5 archangels - creatures.insert(std::make_pair("vcmiangband", std::make_pair(66, 10))); //10 black knights - creatures.insert(std::make_pair("vcmiglaurung", std::make_pair(133, 5000))); //5000 crystal dragons - creatures.insert(std::make_pair("vcmiarchangel", std::make_pair(13, 5))); //5 archangels - creatures.insert(std::make_pair("vcmiblackknight", std::make_pair(66, 10))); //10 black knights - creatures.insert(std::make_pair("vcmicrystal", std::make_pair(133, 5000))); //5000 crystal dragons - creatures.insert(std::make_pair("vcmiazure", std::make_pair(132, 5000))); //5000 azure dragons - creatures.insert(std::make_pair("vcmifaerie", std::make_pair(134, 5000))); //5000 faerie dragons + std::map> creatures; + creatures.insert(std::make_pair("vcmiainur", std::make_pair("archangel", 5))); //5 archangels + creatures.insert(std::make_pair("vcmiangband", std::make_pair("blackKnight", 10))); //10 black knights + creatures.insert(std::make_pair("vcmiglaurung", std::make_pair("crystalDragon", 5000))); //5000 crystal dragons + creatures.insert(std::make_pair("vcmiarchangel", std::make_pair("archangel", 5))); //5 archangels + creatures.insert(std::make_pair("vcmiblackknight", std::make_pair("blackKnight", 10))); //10 black knights + creatures.insert(std::make_pair("vcmicrystal", std::make_pair("crystalDragon", 5000))); //5000 crystal dragons + creatures.insert(std::make_pair("vcmiazure", std::make_pair("azureDragon", 5000))); //5000 azure dragons + creatures.insert(std::make_pair("vcmifaerie", std::make_pair("fairieDragon", 5000))); //5000 faerie dragons - const CCreature * creature = VLC->creh->objects.at(creatures[cheat].first); + const int32_t creatureIdentifier = VLC->modh->identifiers.getIdentifier(CModHandler::scopeGame(), "creature", creatures[cheat].first, false).get(); + const CCreature * creature = VLC->creh->objects.at(creatureIdentifier); for (int i = 0; i < GameConstants::ARMY_SIZE; i++) if (!hero->hasStackAtSlot(SlotID(i))) insertNewStack(StackLocation(hero, SlotID(i)), creature, creatures[cheat].second); @@ -7115,12 +7117,12 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons std::string creatureIdentifier = words[1]; auto creature = vstd::tryFindIf(VLC->creh->objects, - [creatureIdentifier](auto x) - { - std::string identifier = x->getJsonKey(); - boost::to_lower(identifier); - return identifier == creatureIdentifier; - }); + [creatureIdentifier](auto x) + { + std::string identifier = x->getJsonKey(); + boost::to_lower(identifier); + return identifier == creatureIdentifier; + }); if(creature.is_initialized()) { From 5b8e8e60fb32754a6e9f52277535eeb49cf3892e Mon Sep 17 00:00:00 2001 From: Dydzio Date: Wed, 25 Jan 2023 12:50:18 +0100 Subject: [PATCH 05/79] Change vcmiarmy handling a bit --- server/CGameHandler.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index b412ef7a7..57e3ee87c 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -7116,19 +7116,15 @@ void CGameHandler::handleCheatCode(std::string & cheat, PlayerColor player, cons std::string creatureIdentifier = words[1]; - auto creature = vstd::tryFindIf(VLC->creh->objects, - [creatureIdentifier](auto x) - { - std::string identifier = x->getJsonKey(); - boost::to_lower(identifier); - return identifier == creatureIdentifier; - }); + boost::optional creatureId = VLC->modh->identifiers.getIdentifier(CModHandler::scopeGame(), "creature", creatureIdentifier, false); - if(creature.is_initialized()) + if(creatureId.is_initialized()) { + const CCreature * creature = VLC->creh->objects.at(creatureId.get()); + for (int i = 0; i < GameConstants::ARMY_SIZE; i++) if (!hero->hasStackAtSlot(SlotID(i))) - insertNewStack(StackLocation(hero, SlotID(i)), creature->get(), 5 * std::pow(10, i)); + insertNewStack(StackLocation(hero, SlotID(i)), creature, 5 * std::pow(10, i)); } } else if (cheat == "vcminoldor" || cheat == "vcmimachines") From 0bbf70f30a603c329976d417abdb3efec2e980a9 Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Wed, 25 Jan 2023 18:13:06 +0300 Subject: [PATCH 06/79] show resurrect message in the battle log --- lib/spells/effects/Heal.cpp | 19 +++++++++++++++++-- lib/spells/effects/Heal.h | 3 ++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/spells/effects/Heal.cpp b/lib/spells/effects/Heal.cpp index 4723d908b..b1b0007e9 100644 --- a/lib/spells/effects/Heal.cpp +++ b/lib/spells/effects/Heal.cpp @@ -49,10 +49,13 @@ void Heal::apply(ServerCallback * server, const Mechanics * m, const EffectTarge void Heal::apply(int64_t value, ServerCallback * server, const Mechanics * m, const EffectTarget & target) const { + BattleLogMessage logMessage; BattleUnitsChanged pack; - prepareHealEffect(value, pack, *server->getRNG(), m, target); + prepareHealEffect(value, pack, logMessage, *server->getRNG(), m, target); if(!pack.changedStacks.empty()) server->apply(&pack); + if(!logMessage.lines.empty()) + server->apply(&logMessage); } bool Heal::isValidTarget(const Mechanics * m, const battle::Unit * unit) const @@ -112,7 +115,7 @@ void Heal::serializeJsonUnitEffect(JsonSerializeFormat & handler) handler.serializeInt("minFullUnits", minFullUnits); } -void Heal::prepareHealEffect(int64_t value, BattleUnitsChanged & pack, RNG & rng, const Mechanics * m, const EffectTarget & target) const +void Heal::prepareHealEffect(int64_t value, BattleUnitsChanged & pack, BattleLogMessage & logMessage, RNG & rng, const Mechanics * m, const EffectTarget & target) const { for(auto & oneTarget : target) { @@ -123,8 +126,20 @@ void Heal::prepareHealEffect(int64_t value, BattleUnitsChanged & pack, RNG & rng auto unitHPgained = m->applySpellBonus(value, unit); auto state = unit->acquire(); + const auto countBeforeHeal = state->getCount(); state->heal(unitHPgained, healLevel, healPower); + if(const auto resurrectedCount = std::max(0, state->getCount() - countBeforeHeal)) + { + // %d %s rise from the dead! + // in the table first comes plural string, then the singular one + MetaString resurrectText; + state->addText(resurrectText, MetaString::GENERAL_TXT, 116, resurrectedCount == 1); + state->addNameReplacement(resurrectText); + resurrectText.addReplacement(resurrectedCount); + logMessage.lines.push_back(std::move(resurrectText)); + } + if(unitHPgained > 0) { UnitChanges info(state->unitId(), UnitChanges::EOperation::RESET_STATE); diff --git a/lib/spells/effects/Heal.h b/lib/spells/effects/Heal.h index 138935626..886c45781 100644 --- a/lib/spells/effects/Heal.h +++ b/lib/spells/effects/Heal.h @@ -15,6 +15,7 @@ VCMI_LIB_NAMESPACE_BEGIN +struct BattleLogMessage; struct BattleUnitsChanged; namespace spells @@ -42,7 +43,7 @@ private: int32_t minFullUnits; - void prepareHealEffect(int64_t value, BattleUnitsChanged & pack, RNG & rng, const Mechanics * m, const EffectTarget & target) const; + void prepareHealEffect(int64_t value, BattleUnitsChanged & pack, BattleLogMessage & logMessage, RNG & rng, const Mechanics * m, const EffectTarget & target) const; }; } From a2ac189e036f32ab45803d11aff6e8d9bc3c7391 Mon Sep 17 00:00:00 2001 From: Andrey Filipenkov Date: Wed, 25 Jan 2023 18:13:11 +0300 Subject: [PATCH 07/79] fix typo --- client/battle/BattleConstants.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/battle/BattleConstants.h b/client/battle/BattleConstants.h index 0a6b0deba..b815132a1 100644 --- a/client/battle/BattleConstants.h +++ b/client/battle/BattleConstants.h @@ -79,7 +79,7 @@ enum class ECreatureAnimType DEAD = 22, // new group, used to show dead stacks. If empty - last frame from "DEATH" will be copied here DEAD_RANGED = 23, // new group, used to show dead stacks (if DEATH_RANGED was used). If empty - last frame from "DEATH_RANGED" will be copied here - RESURRECTION = 24, // new group, used for animating resurrection, if empty - reversed "DEATH" animation will be copiend here + RESURRECTION = 24, // new group, used for animating resurrection, if empty - reversed "DEATH" animation will be copied here FROZEN = 25, // new group, used when stack animation is paused (e.g. petrified). If empty - consist of first frame from HOLDING animation CAST_UP = 30, From d82822d37a3d8919c6f21409621fbe5c5cc5ed3f Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 27 Jan 2023 00:59:10 +0200 Subject: [PATCH 08/79] Fix reset of rewardable objects with reset period of 1 day --- lib/mapObjects/CRewardableObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mapObjects/CRewardableObject.cpp b/lib/mapObjects/CRewardableObject.cpp index 2de00f67a..25dc4fe86 100644 --- a/lib/mapObjects/CRewardableObject.cpp +++ b/lib/mapObjects/CRewardableObject.cpp @@ -538,7 +538,7 @@ void CRewardableObject::triggerReset() const void CRewardableObject::newTurn(CRandomGenerator & rand) const { - if (resetParameters.period != 0 && cb->getDate(Date::DAY) > 1 && (cb->getDate(Date::DAY) % resetParameters.period) == 1) + if (resetParameters.period != 0 && cb->getDate(Date::DAY) > 1 && ((cb->getDate(Date::DAY)-1) % resetParameters.period) == 0) triggerReset(); } From a2cd17197e5845a8d9345d297a3f9a3e72bdd8a4 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sat, 28 Jan 2023 00:01:10 +0200 Subject: [PATCH 09/79] Fix Campfire Gold reward amount. Now always one of 400/500/600 --- config/objects/rewardablePickable.json | 3 +-- lib/mapObjects/JsonRandom.cpp | 11 +++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/config/objects/rewardablePickable.json b/config/objects/rewardablePickable.json index bdda59802..868c9239c 100644 --- a/config/objects/rewardablePickable.json +++ b/config/objects/rewardablePickable.json @@ -35,8 +35,7 @@ }, { "type" : "gold", - "min" : 400, - "max" : 600 + "amount" : [ 400, 500, 600 ] } ] } diff --git a/lib/mapObjects/JsonRandom.cpp b/lib/mapObjects/JsonRandom.cpp index 2299b9c37..712d78ffc 100644 --- a/lib/mapObjects/JsonRandom.cpp +++ b/lib/mapObjects/JsonRandom.cpp @@ -31,10 +31,17 @@ namespace JsonRandom return defaultValue; if (value.isNumber()) return static_cast(value.Float()); + if (value.isVector()) + { + const auto & vector = value.Vector(); + + size_t index= rng.getIntRange(0, vector.size()-1)(); + return loadValue(vector[index], rng, 0); + } if (!value["amount"].isNull()) return static_cast(loadValue(value["amount"], rng, defaultValue)); - si32 min = static_cast(value["min"].Float()); - si32 max = static_cast(value["max"].Float()); + si32 min = static_cast(loadValue(value["min"], rng, 0)); + si32 max = static_cast(loadValue(value["max"], rng, 0)); return rng.getIntRange(min, max)(); } From a9fefffc65bc0bdb946b8b9752da6f67313c8425 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 27 Jan 2023 01:52:40 +0200 Subject: [PATCH 10/79] Video playback is now time-based, using video file timings --- client/CVideoHandler.cpp | 50 ++++++++++++++++++++++------------------ client/CVideoHandler.h | 43 ++++++---------------------------- 2 files changed, 35 insertions(+), 58 deletions(-) diff --git a/client/CVideoHandler.cpp b/client/CVideoHandler.cpp index b3dbe9563..aae6d0811 100644 --- a/client/CVideoHandler.cpp +++ b/client/CVideoHandler.cpp @@ -18,6 +18,14 @@ extern CGuiHandler GH; //global gui handler #ifndef DISABLE_VIDEO + +extern "C" { +#include +#include +#include +#include +} + //reads events and returns true on key down static bool keyDown() { @@ -56,22 +64,20 @@ static si64 lodSeek(void * opaque, si64 pos, int whence) } CVideoPlayer::CVideoPlayer() -{ - stream = -1; - format = nullptr; - codecContext = nullptr; - codec = nullptr; - frame = nullptr; - sws = nullptr; - context = nullptr; - texture = nullptr; - dest = nullptr; - destRect = CSDL_Ext::genRect(0,0,0,0); - pos = CSDL_Ext::genRect(0,0,0,0); - refreshWait = 0; - refreshCount = 0; - doLoop = false; -} + : stream(-1) + , format (nullptr) + , codecContext(nullptr) + , codec(nullptr) + , frame(nullptr) + , sws(nullptr) + , context(nullptr) + , texture(nullptr) + , dest(nullptr) + , destRect(0,0,0,0) + , pos(0,0,0,0) + , frameTime(0) + , doLoop(false) +{} bool CVideoPlayer::open(std::string fname, bool scale) { @@ -85,9 +91,8 @@ bool CVideoPlayer::open(std::string fname, bool loop, bool useOverlay, bool scal close(); this->fname = fname; - refreshWait = 3; - refreshCount = -1; doLoop = loop; + frameTime = 0; ResourceID resource(std::string("Video/") + fname, EResType::VIDEO); @@ -254,6 +259,7 @@ bool CVideoPlayer::nextFrame() if (doLoop && !gotError) { // Rewind + frameTime = 0; if (av_seek_frame(format, stream, 0, AVSEEK_FLAG_BYTE) < 0) break; gotError = true; @@ -354,9 +360,11 @@ void CVideoPlayer::update( int x, int y, SDL_Surface *dst, bool forceRedraw, boo if (sws == nullptr) return; - if (refreshCount <= 0) + double frameEndTime = (frame->pts + frame->pkt_duration) * av_q2d(format->streams[stream]->time_base); + frameTime += GH.mainFPSmng->getElapsedMilliseconds() / 1000.0; + + if (frameTime >= frameEndTime ) { - refreshCount = refreshWait; if (nextFrame()) show(x,y,dst,update); else @@ -374,8 +382,6 @@ void CVideoPlayer::update( int x, int y, SDL_Surface *dst, bool forceRedraw, boo { redraw(x, y, dst, update); } - - refreshCount --; } void CVideoPlayer::close() diff --git a/client/CVideoHandler.h b/client/CVideoHandler.h index 863961013..684270685 100644 --- a/client/CVideoHandler.h +++ b/client/CVideoHandler.h @@ -56,39 +56,11 @@ public: #include "../lib/filesystem/CInputStream.h" -extern "C" { -#include -#include -#include -#include -} - -//compatibility for libav 9.18 in ubuntu 14.04, 52.66.100 is ffmpeg 2.2.3 -#if (LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 66, 100)) -inline AVFrame * av_frame_alloc() -{ - return avcodec_alloc_frame(); -} - -inline void av_frame_free(AVFrame ** frame) -{ - av_free(*frame); - *frame = nullptr; -} -#endif // VCMI_USE_OLD_AVUTIL - -//fix for travis-ci -#if (LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 0, 0)) - #define AVPixelFormat PixelFormat - #define AV_PIX_FMT_NONE PIX_FMT_NONE - #define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P - #define AV_PIX_FMT_BGR565 PIX_FMT_BGR565 - #define AV_PIX_FMT_BGR24 PIX_FMT_BGR24 - #define AV_PIX_FMT_BGR32 PIX_FMT_BGR32 - #define AV_PIX_FMT_RGB565 PIX_FMT_RGB565 - #define AV_PIX_FMT_RGB24 PIX_FMT_RGB24 - #define AV_PIX_FMT_RGB32 PIX_FMT_RGB32 -#endif +struct AVFormatContext; +struct AVCodecContext; +struct AVCodec; +struct AVFrame; +struct AVIOContext; class CVideoPlayer : public IMainVideoPlayer { @@ -108,8 +80,8 @@ class CVideoPlayer : public IMainVideoPlayer Rect destRect; // valid when dest is used Rect pos; // destination on screen - int refreshWait; // Wait several refresh before updating the image - int refreshCount; + /// video playback currnet progress, in seconds + double frameTime; bool doLoop; // loop through video bool playVideo(int x, int y, bool stopOnKey); @@ -141,4 +113,3 @@ public: }; #endif - From 3acee297be46d0b936c20d056dc9fdd55888fd22 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 27 Jan 2023 12:22:48 +0200 Subject: [PATCH 11/79] CShowableAnim is now time-based with timing matching H3 --- client/widgets/AdventureMapClasses.cpp | 8 ++++---- client/widgets/Images.cpp | 20 +++++++++++--------- client/widgets/Images.h | 8 ++++---- client/windows/CCastleInterface.cpp | 2 +- client/windows/CCastleInterface.h | 4 +++- 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/client/widgets/AdventureMapClasses.cpp b/client/widgets/AdventureMapClasses.cpp index e507e99ff..53f121e60 100644 --- a/client/widgets/AdventureMapClasses.cpp +++ b/client/widgets/AdventureMapClasses.cpp @@ -690,7 +690,7 @@ CInfoBar::VisibleDateInfo::VisibleDateInfo() { OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - animation = std::make_shared(1, 0, getNewDayName(), CShowableAnim::PLAY_ONCE); + animation = std::make_shared(1, 0, getNewDayName(), CShowableAnim::PLAY_ONCE, 180);// H3 uses around 175-180 ms per frame std::string labelText; if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) == 1 && LOCPLINT->cb->getDate(Date::DAY) != 1) // monday of any week but first - show new week info @@ -731,8 +731,8 @@ CInfoBar::VisibleEnemyTurnInfo::VisibleEnemyTurnInfo(PlayerColor player) OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); background = std::make_shared("ADSTATNX"); banner = std::make_shared("CREST58", player.getNum(), 0, 20, 51); - sand = std::make_shared(99, 51, "HOURSAND"); - glass = std::make_shared(99, 51, "HOURGLAS", CShowableAnim::PLAY_ONCE, 40); + sand = std::make_shared(99, 51, "HOURSAND", 0, 100); // H3 uses around 100 ms per frame + glass = std::make_shared(99, 51, "HOURGLAS", CShowableAnim::PLAY_ONCE, 1000); // H3 scales this nicely for AI turn duration, don't have anything like that in vcmi } CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo() @@ -890,7 +890,7 @@ void CInfoBar::showDate() playNewDaySound(); state = DATE; visibleInfo = std::make_shared(); - setTimer(3000); + setTimer(3000); // confirmed to match H3 redraw(); } diff --git a/client/widgets/Images.cpp b/client/widgets/Images.cpp index 88bced4b5..37e8e41d7 100644 --- a/client/widgets/Images.cpp +++ b/client/widgets/Images.cpp @@ -333,13 +333,13 @@ void CAnimImage::playerColored(PlayerColor currPlayer) anim->getImage(0, group)->playerColored(player); } -CShowableAnim::CShowableAnim(int x, int y, std::string name, ui8 Flags, ui32 Delay, size_t Group, uint8_t alpha): +CShowableAnim::CShowableAnim(int x, int y, std::string name, ui8 Flags, ui32 frameTime, size_t Group, uint8_t alpha): anim(std::make_shared(name)), group(Group), frame(0), first(0), - frameDelay(Delay), - value(0), + frameTimeTotal(frameTime), + frameTimePassed(0), flags(Flags), xOffset(0), yOffset(0), @@ -380,7 +380,7 @@ bool CShowableAnim::set(size_t Group, size_t from, size_t to) group = Group; frame = first = from; last = max; - value = 0; + frameTimePassed = 0; return true; } @@ -397,13 +397,13 @@ bool CShowableAnim::set(size_t Group) group = Group; last = anim->size(Group); } - frame = value = 0; + frame = 0; + frameTimePassed = 0; return true; } void CShowableAnim::reset() { - value = 0; frame = first; if (callback) @@ -427,9 +427,11 @@ void CShowableAnim::show(SDL_Surface * to) if ((flags & PLAY_ONCE) && frame + 1 == last) return; - if ( ++value == frameDelay ) + frameTimePassed += GH.mainFPSmng->getElapsedMilliseconds(); + + if(frameTimePassed >= frameTimeTotal) { - value = 0; + frameTimePassed -= frameTimeTotal; if ( ++frame >= last) reset(); } @@ -466,7 +468,7 @@ void CShowableAnim::rotate(bool on, bool vertical) } CCreatureAnim::CCreatureAnim(int x, int y, std::string name, ui8 flags, ECreatureAnimType type): - CShowableAnim(x,y,name,flags,4,size_t(type)) + CShowableAnim(x, y, name, flags, 100, size_t(type)) // H3 uses 100 ms per frame, irregardless of battle speed settings { xOffset = 0; yOffset = 0; diff --git a/client/widgets/Images.h b/client/widgets/Images.h index 2b4b1bd24..166ba45d9 100644 --- a/client/widgets/Images.h +++ b/client/widgets/Images.h @@ -125,9 +125,9 @@ protected: size_t first, last; //animation range - //TODO: replace with time delay(needed for battles) - ui32 frameDelay;//delay in frames of each image - ui32 value;//how many times current frame was showed + /// how long (in milliseconds) should + ui32 frameTimeTotal; + ui32 frameTimePassed; ui8 flags;//Flags from EFlags enum @@ -146,7 +146,7 @@ public: //Set per-surface alpha, 0 = transparent, 255 = opaque void setAlpha(ui32 alphaValue); - CShowableAnim(int x, int y, std::string name, ui8 flags=0, ui32 Delay=4, size_t Group=0, uint8_t alpha = UINT8_MAX); + CShowableAnim(int x, int y, std::string name, ui8 flags, ui32 frameTime, size_t Group=0, uint8_t alpha = UINT8_MAX); ~CShowableAnim(); //set animation to group or part of group diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index 1dafce97f..dc8403735 100644 --- a/client/windows/CCastleInterface.cpp +++ b/client/windows/CCastleInterface.cpp @@ -43,7 +43,7 @@ #include "../../lib/mapObjects/CGTownInstance.h" CBuildingRect::CBuildingRect(CCastleBuildings * Par, const CGTownInstance * Town, const CStructure * Str) - : CShowableAnim(0, 0, Str->defName, CShowableAnim::BASE), + : CShowableAnim(0, 0, Str->defName, CShowableAnim::BASE, BUILDING_FRAME_TIME), parent(Par), town(Town), str(Str), diff --git a/client/windows/CCastleInterface.h b/client/windows/CCastleInterface.h index 6b9f7f7e8..6f87599d6 100644 --- a/client/windows/CCastleInterface.h +++ b/client/windows/CCastleInterface.h @@ -47,7 +47,9 @@ public: BUILDING_APPEAR_TIMEPOINT = 500, //500 msec building appears: 0->100% transparency BUILDING_WHITE_BORDER_TIMEPOINT = 1000, //500 msec border glows from white to yellow BUILDING_YELLOW_BORDER_TIMEPOINT = 1500, //500 msec border glows from yellow to normal - BUILD_ANIMATION_FINISHED_TIMEPOINT = 2500 //1000 msec delay, nothing happens + BUILD_ANIMATION_FINISHED_TIMEPOINT = 2500, //1000 msec delay, nothing happens + + BUILDING_FRAME_TIME = 150 // confirmed H3 timing: 150 ms for each building animation frame }; /// returns building associated with this structure From f1647cc3bb07afb6bb9d5095bf858e7857304e05 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 27 Jan 2023 13:07:45 +0200 Subject: [PATCH 12/79] Animated spellcasting cursor now has same speed as in H3 --- client/gui/CursorHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/gui/CursorHandler.cpp b/client/gui/CursorHandler.cpp index 39c19b860..7e76b1d0c 100644 --- a/client/gui/CursorHandler.cpp +++ b/client/gui/CursorHandler.cpp @@ -260,7 +260,7 @@ void CursorHandler::centerCursor() void CursorHandler::updateSpellcastCursor() { - static const float frameDisplayDuration = 0.1f; + static const float frameDisplayDuration = 5.0 / 60.0; // H3 uses ~83 ms per image = 5 / 60 second frameTime += GH.mainFPSmng->getElapsedMilliseconds() / 1000.f; size_t newFrame = frame; From 09413c61b899b34b3441e343037f8d1b5e148ae0 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 27 Jan 2023 13:08:09 +0200 Subject: [PATCH 13/79] Changed timing of building fade-in to match H3 --- client/windows/CCastleInterface.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/windows/CCastleInterface.h b/client/windows/CCastleInterface.h index 6f87599d6..7acfa4282 100644 --- a/client/windows/CCastleInterface.h +++ b/client/windows/CCastleInterface.h @@ -45,9 +45,9 @@ public: enum EBuildingCreationAnimationPhases : uint32_t { BUILDING_APPEAR_TIMEPOINT = 500, //500 msec building appears: 0->100% transparency - BUILDING_WHITE_BORDER_TIMEPOINT = 1000, //500 msec border glows from white to yellow - BUILDING_YELLOW_BORDER_TIMEPOINT = 1500, //500 msec border glows from yellow to normal - BUILD_ANIMATION_FINISHED_TIMEPOINT = 2500, //1000 msec delay, nothing happens + BUILDING_WHITE_BORDER_TIMEPOINT = 900, //400 msec border glows from white to yellow + BUILDING_YELLOW_BORDER_TIMEPOINT = 1100, //200 msec border glows from yellow to normal (dark orange) + BUILD_ANIMATION_FINISHED_TIMEPOINT = 1200, //once border is back to yellow nothing happens BUILDING_FRAME_TIME = 150 // confirmed H3 timing: 150 ms for each building animation frame }; From bdde9f831a32e2f986f297455c7e167abc6c2453 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 27 Jan 2023 15:01:43 +0200 Subject: [PATCH 14/79] Fixed timings of building construction to match H3 --- client/gui/CursorHandler.cpp | 2 +- client/windows/CCastleInterface.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/gui/CursorHandler.cpp b/client/gui/CursorHandler.cpp index 7e76b1d0c..bb57fa80a 100644 --- a/client/gui/CursorHandler.cpp +++ b/client/gui/CursorHandler.cpp @@ -260,7 +260,7 @@ void CursorHandler::centerCursor() void CursorHandler::updateSpellcastCursor() { - static const float frameDisplayDuration = 5.0 / 60.0; // H3 uses ~83 ms per image = 5 / 60 second + static const float frameDisplayDuration = 5.f / 60.f; // H3 uses ~83 ms per image = 5 / 60 second frameTime += GH.mainFPSmng->getElapsedMilliseconds() / 1000.f; size_t newFrame = frame; diff --git a/client/windows/CCastleInterface.h b/client/windows/CCastleInterface.h index 7acfa4282..197fcd984 100644 --- a/client/windows/CCastleInterface.h +++ b/client/windows/CCastleInterface.h @@ -47,7 +47,7 @@ public: BUILDING_APPEAR_TIMEPOINT = 500, //500 msec building appears: 0->100% transparency BUILDING_WHITE_BORDER_TIMEPOINT = 900, //400 msec border glows from white to yellow BUILDING_YELLOW_BORDER_TIMEPOINT = 1100, //200 msec border glows from yellow to normal (dark orange) - BUILD_ANIMATION_FINISHED_TIMEPOINT = 1200, //once border is back to yellow nothing happens + BUILD_ANIMATION_FINISHED_TIMEPOINT = 2100, // 1000msec once border is back to yellow nothing happens (this stage is basically removed by HD Mod) BUILDING_FRAME_TIME = 150 // confirmed H3 timing: 150 ms for each building animation frame }; From d34efaeb8145d8360fd145ab622594b54ae57995 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Fri, 27 Jan 2023 23:16:02 +0200 Subject: [PATCH 15/79] All battle effects now use time-based timings --- client/battle/BattleAnimationClasses.cpp | 9 ++-- client/battle/BattleAnimationClasses.h | 7 ++- client/battle/BattleInterface.cpp | 2 +- client/battle/BattleInterfaceClasses.cpp | 6 +-- client/battle/BattleProjectileController.cpp | 18 ++++--- client/battle/BattleProjectileController.h | 2 +- client/battle/CreatureAnimation.cpp | 54 +++++++++++++------- client/battle/CreatureAnimation.h | 13 +++-- config/battleEffects.json | 8 +-- lib/CCreatureHandler.cpp | 2 +- lib/CCreatureHandler.h | 4 +- 11 files changed, 75 insertions(+), 50 deletions(-) diff --git a/client/battle/BattleAnimationClasses.cpp b/client/battle/BattleAnimationClasses.cpp index 111a4e3a6..fac752acc 100644 --- a/client/battle/BattleAnimationClasses.cpp +++ b/client/battle/BattleAnimationClasses.cpp @@ -364,7 +364,7 @@ bool MovementAnimation::init() Point begPosition = owner.stacksController->getStackPositionAtHex(prevHex, stack); Point endPosition = owner.stacksController->getStackPositionAtHex(nextHex, stack); - timeToMove = AnimationControls::getMovementDuration(stack->getCreature()); + progressPerSecond = AnimationControls::getMovementDistance(stack->getCreature()); begX = begPosition.x; begY = begPosition.y; @@ -375,8 +375,7 @@ bool MovementAnimation::init() if (stack->hasBonus(Selector::type()(Bonus::FLYING))) { float distance = static_cast(sqrt(distanceX * distanceX + distanceY * distanceY)); - - timeToMove *= AnimationControls::getFlightDistance(stack->getCreature()) / distance; + progressPerSecond = AnimationControls::getFlightDistance(stack->getCreature()) / distance; } return true; @@ -384,7 +383,7 @@ bool MovementAnimation::init() void MovementAnimation::nextFrame() { - progress += float(GH.mainFPSmng->getElapsedMilliseconds()) / 1000 * timeToMove; + progress += float(GH.mainFPSmng->getElapsedMilliseconds()) / 1000 * progressPerSecond; //moving instructions myAnim->pos.x = static_cast(begX + distanceX * progress ); @@ -432,7 +431,7 @@ MovementAnimation::MovementAnimation(BattleInterface & owner, const CStack *stac curentMoveIndex(0), begX(0), begY(0), distanceX(0), distanceY(0), - timeToMove(0.0), + progressPerSecond(0.0), progress(0.0) { logAnim->debug("Created MovementAnimation for %s", stack->getName()); diff --git a/client/battle/BattleAnimationClasses.h b/client/battle/BattleAnimationClasses.h index f89d4435c..89309ffe9 100644 --- a/client/battle/BattleAnimationClasses.h +++ b/client/battle/BattleAnimationClasses.h @@ -147,8 +147,11 @@ private: double begX, begY; // starting position double distanceX, distanceY; // full movement distance, may be negative if creture moves topleft - double timeToMove; // full length of movement animation - double progress; // range 0 -> 1, indicates move progrees. 0 = movement starts, 1 = move ends + /// progress gain per second + double progressPerSecond; + + /// range 0 -> 1, indicates move progrees. 0 = movement starts, 1 = move ends + double progress; public: bool init() override; diff --git a/client/battle/BattleInterface.cpp b/client/battle/BattleInterface.cpp index 14ade3839..e87745884 100644 --- a/client/battle/BattleInterface.cpp +++ b/client/battle/BattleInterface.cpp @@ -521,7 +521,7 @@ void BattleInterface::displaySpellHit(const CSpell * spell, BattleHex destinatio void BattleInterface::setAnimSpeed(int set) { Settings speed = settings.write["battle"]["animationSpeed"]; - speed->Float() = float(set) / 100; + speed->Float() = float(set); } int BattleInterface::getAnimSpeed() const diff --git a/client/battle/BattleInterfaceClasses.cpp b/client/battle/BattleInterfaceClasses.cpp index 5c5031ef7..280385372 100644 --- a/client/battle/BattleInterfaceClasses.cpp +++ b/client/battle/BattleInterfaceClasses.cpp @@ -438,13 +438,13 @@ BattleOptionsWindow::BattleOptionsWindow(BattleInterface & owner): std::shared_ptr toggle; toggle = std::make_shared(Point( 28, 225), "sysopb9.def", CGI->generaltexth->zelp[422]); - animSpeeds->addToggle(40, toggle); + animSpeeds->addToggle(1, toggle); toggle = std::make_shared(Point( 92, 225), "sysob10.def", CGI->generaltexth->zelp[423]); - animSpeeds->addToggle(63, toggle); + animSpeeds->addToggle(2, toggle); toggle = std::make_shared(Point(156, 225), "sysob11.def", CGI->generaltexth->zelp[424]); - animSpeeds->addToggle(100, toggle); + animSpeeds->addToggle(3, toggle); animSpeeds->setSelected(owner.getAnimSpeed()); diff --git a/client/battle/BattleProjectileController.cpp b/client/battle/BattleProjectileController.cpp index 429d11fc1..b9260d37e 100644 --- a/client/battle/BattleProjectileController.cpp +++ b/client/battle/BattleProjectileController.cpp @@ -77,7 +77,11 @@ void ProjectileAnimatedMissile::show(Canvas & canvas) void ProjectileCatapult::show(Canvas & canvas) { - auto image = animation->getImage(frameNum, 0, true); + frameProgress += AnimationControls::getSpellEffectSpeed() * GH.mainFPSmng->getElapsedMilliseconds() / 1000; + int frameCounter = std::floor(frameProgress); + int frameIndex = (frameCounter + 1) % animation->size(0); + + auto image = animation->getImage(frameIndex, 0, true); if(image) { @@ -86,8 +90,6 @@ void ProjectileCatapult::show(Canvas & canvas) Point pos(posX, posY); canvas.draw(image, pos); - - frameNum = (frameNum + 1) % animation->size(0); } float timePassed = GH.mainFPSmng->getElapsedMilliseconds() / 1000.f; @@ -294,13 +296,13 @@ void BattleProjectileController::createCatapultProjectile(const CStack * shooter auto catapultProjectile = new ProjectileCatapult(); catapultProjectile->animation = getProjectileImage(shooter); - catapultProjectile->frameNum = 0; catapultProjectile->progress = 0; catapultProjectile->speed = computeProjectileFlightTime(from, dest, AnimationControls::getCatapultSpeed()); catapultProjectile->from = from; catapultProjectile->dest = dest; catapultProjectile->shooterID = shooter->ID; catapultProjectile->playing = false; + catapultProjectile->frameProgress = 0.f; projectiles.push_back(std::shared_ptr(catapultProjectile)); } @@ -321,6 +323,7 @@ void BattleProjectileController::createProjectile(const CStack * shooter, Point projectile.reset(rayProjectile); rayProjectile->rayConfig = shooterInfo.animation.projectileRay; + rayProjectile->speed = computeProjectileFlightTime(from, dest, AnimationControls::getRayProjectileSpeed()); } else if (stackUsesMissileProjectile(shooter)) { @@ -328,11 +331,12 @@ void BattleProjectileController::createProjectile(const CStack * shooter, Point projectile.reset(missileProjectile); missileProjectile->animation = getProjectileImage(shooter); - missileProjectile->reverse = !owner.stacksController->facingRight(shooter); - missileProjectile->frameNum = computeProjectileFrameID(from, dest, shooter); + missileProjectile->reverse = !owner.stacksController->facingRight(shooter); + missileProjectile->frameNum = computeProjectileFrameID(from, dest, shooter); + missileProjectile->speed = computeProjectileFlightTime(from, dest, AnimationControls::getProjectileSpeed()); } - projectile->speed = computeProjectileFlightTime(from, dest, AnimationControls::getProjectileSpeed()); + projectile->from = from; projectile->dest = dest; projectile->shooterID = shooter->ID; diff --git a/client/battle/BattleProjectileController.h b/client/battle/BattleProjectileController.h index 102a99f09..477072eec 100644 --- a/client/battle/BattleProjectileController.h +++ b/client/battle/BattleProjectileController.h @@ -61,7 +61,7 @@ struct ProjectileCatapult : ProjectileBase void show(Canvas & canvas) override; std::shared_ptr animation; - int frameNum; // frame to display from projectile animation + float frameProgress; }; /// Projectile for mages/evil eye - render ray expanding from origin position to destination diff --git a/client/battle/CreatureAnimation.cpp b/client/battle/CreatureAnimation.cpp index 0dda6089a..436cc162d 100644 --- a/client/battle/CreatureAnimation.cpp +++ b/client/battle/CreatureAnimation.cpp @@ -56,20 +56,24 @@ float AnimationControls::getCreatureAnimationSpeed(const CCreature * creature, c // possible new fields for creature format: //split "Attack time" into "Shoot Time" and "Cast Time" - // a lot of arbitrary multipliers, mostly to make animation speed closer to H3 - const float baseSpeed = 0.1f; + // base speed for all H3 animations is 10/20/30 frames per second (100/50/33 ms per frame) + const float baseSpeed = 10.f; const float speedMult = static_cast(settings["battle"]["animationSpeed"].Float()); - const float speed = baseSpeed / speedMult; + const float speed = baseSpeed * speedMult; switch (type) { case ECreatureAnimType::MOVING: - return static_cast(speed * 2 * creature->animation.walkAnimationTime / anim->framesInGroup(type)); + return speed / creature->animation.walkAnimationTime; case ECreatureAnimType::MOUSEON: return baseSpeed; + case ECreatureAnimType::HOLDING: - return static_cast(baseSpeed * creature->animation.idleAnimationTime / anim->framesInGroup(type)); + if ( creature->animation.idleAnimationTime > 0.01) + return speed / creature->animation.idleAnimationTime; + else + return 0.f; case ECreatureAnimType::SHOOT_UP: case ECreatureAnimType::SHOOT_FRONT: @@ -80,7 +84,7 @@ float AnimationControls::getCreatureAnimationSpeed(const CCreature * creature, c case ECreatureAnimType::CAST_DOWN: case ECreatureAnimType::CAST_FRONT: case ECreatureAnimType::CAST_UP: - return static_cast(speed * 4 * creature->animation.attackAnimationTime / anim->framesInGroup(type)); + return speed / creature->animation.attackAnimationTime; // as strange as it looks like "attackAnimationTime" does not affects melee attacks // necessary because length of these animations must be same for all creatures for synchronization @@ -95,15 +99,15 @@ float AnimationControls::getCreatureAnimationSpeed(const CCreature * creature, c case ECreatureAnimType::GROUP_ATTACK_DOWN: case ECreatureAnimType::GROUP_ATTACK_FRONT: case ECreatureAnimType::GROUP_ATTACK_UP: - return speed * 3 / anim->framesInGroup(type); + return speed; case ECreatureAnimType::TURN_L: case ECreatureAnimType::TURN_R: - return speed / 3; + return speed; case ECreatureAnimType::MOVE_START: case ECreatureAnimType::MOVE_END: - return speed / 3; + return speed; case ECreatureAnimType::DEAD: case ECreatureAnimType::DEAD_RANGED: @@ -116,37 +120,51 @@ float AnimationControls::getCreatureAnimationSpeed(const CCreature * creature, c float AnimationControls::getProjectileSpeed() { + // H3 speed: 1250/2500/3750 pixels per second + return static_cast(settings["battle"]["animationSpeed"].Float() * 1250); +} + +float AnimationControls::getRayProjectileSpeed() +{ + // H3 speed: 4000/8000/12000 pixels per second return static_cast(settings["battle"]["animationSpeed"].Float() * 4000); } float AnimationControls::getCatapultSpeed() { - return static_cast(settings["battle"]["animationSpeed"].Float() * 1000); + // H3 speed: 200/400/600 pixels per second + return static_cast(settings["battle"]["animationSpeed"].Float() * 200); } float AnimationControls::getSpellEffectSpeed() { - return static_cast(settings["battle"]["animationSpeed"].Float() * 30); + // H3 speed: 10/20/30 frames per second + return static_cast(settings["battle"]["animationSpeed"].Float() * 10); } -float AnimationControls::getMovementDuration(const CCreature * creature) +float AnimationControls::getMovementDistance(const CCreature * creature) { - return static_cast(settings["battle"]["animationSpeed"].Float() * 4 / creature->animation.walkAnimationTime); + // H3 speed: 2/4/6 tiles per second + return static_cast( 2.0 * settings["battle"]["animationSpeed"].Float() / creature->animation.walkAnimationTime); } float AnimationControls::getFlightDistance(const CCreature * creature) { - return static_cast(creature->animation.flightAnimationDistance * 200); + // Note: for whatever reason, H3 uses "Walk Animation Time" here, even though "Flight Animation Distance" also exists + // H3 speed: 250/500/750 pixels per second + return static_cast( 250.0 * settings["battle"]["animationSpeed"].Float() / creature->animation.walkAnimationTime); } float AnimationControls::getFadeInDuration() { - return 1.0f / settings["battle"]["animationSpeed"].Float(); + // H3 speed: 500/250/166 ms + return 0.5f / settings["battle"]["animationSpeed"].Float(); } float AnimationControls::getObstaclesSpeed() { - return 10.0;// does not seems to be affected by animaiton speed settings + // H3 speed: 20 frames per second, irregardless of speed setting. + return 20.f; } ECreatureAnimType CreatureAnimation::getType() const @@ -407,7 +425,5 @@ void CreatureAnimation::pause() void CreatureAnimation::play() { //logAnim->trace("Play %s group %d at %d:%d", name, static_cast(getType()), pos.x, pos.y); - speed = 0; - if(speedController(this, type) != 0) - speed = 1 / speedController(this, type); + speed = speedController(this, type); } diff --git a/client/battle/CreatureAnimation.h b/client/battle/CreatureAnimation.h index cdead9c79..04f68afac 100644 --- a/client/battle/CreatureAnimation.h +++ b/client/battle/CreatureAnimation.h @@ -31,19 +31,22 @@ namespace AnimationControls /// returns animation speed of specific group, taking in mind game setting (in frames per second) float getCreatureAnimationSpeed(const CCreature * creature, const CreatureAnimation * anim, ECreatureAnimType groupID); - /// returns how far projectile should move per second + /// returns how far projectile should move per second, in pixels per second float getProjectileSpeed(); - /// returns speed of catapult projectile, in pixels per second (horizontal axis only) + /// returns how far projectile should move per second, in pixels per second + float getRayProjectileSpeed(); + + /// returns speed of catapult projectile, in pixels per second, on a straight line, without parabola correction float getCatapultSpeed(); /// returns speed of any spell effects, including any special effects like morale (in frames per second) float getSpellEffectSpeed(); - /// returns duration of full movement animation, in seconds. Needed to move animation on screen - float getMovementDuration(const CCreature * creature); + /// returns speed of movement animation across the screen, in tiles per second + float getMovementDistance(const CCreature * creature); - /// Returns distance on which flying creatures should during one animation loop + /// returns speed of movement animation across the screen, in pixels per seconds float getFlightDistance(const CCreature * creature); /// Returns total time for full fade-in effect on newly summoned creatures, in seconds diff --git a/config/battleEffects.json b/config/battleEffects.json index 089d8dbef..7f08e608e 100644 --- a/config/battleEffects.json +++ b/config/battleEffects.json @@ -85,28 +85,28 @@ "time" : 0.0 }, { - "time" : 0.2, + "time" : 0.25, "red" : [ 0.5, 0.0, 0.5, 0.4 ], "green" : [ 0.0, 1.0, 0.0, 0.0 ], "blue" : [ 0.0, 0.0, 1.0, 0.0 ], "alpha" : 1.0 }, { - "time" : 0.4, + "time" : 0.5, "red" : [ 0.6, 0.6, 0.6, 0.0 ], "green" : [ 0.0, 0.5, 0.0, 0.0 ], "blue" : [ 0.0, 0.0, 0.5, 0.0 ], "alpha" : 1.0 }, { - "time" : 0.6, + "time" : 0.75, "red" : [ 0.5, 0.0, 0.5, 0.4 ], "green" : [ 0.0, 1.0, 0.0, 0.0 ], "blue" : [ 0.0, 0.0, 1.0, 0.0 ], "alpha" : 1.0 }, { - "time" : 0.8, + "time" : 1.0, }, ], } diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index f5e256301..8c72c5b10 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -851,7 +851,7 @@ void CCreatureHandler::loadJsonAnimation(CCreature * cre, const JsonNode & graph cre->animation.walkAnimationTime = animationTime["walk"].Float(); cre->animation.idleAnimationTime = animationTime["idle"].Float(); cre->animation.attackAnimationTime = animationTime["attack"].Float(); - cre->animation.flightAnimationDistance = animationTime["flight"].Float(); //? + cre->animation.missileVelocityFactor = animationTime["missile"].Float(); const JsonNode & missile = graphics["missile"]; const JsonNode & offsets = missile["offset"]; diff --git a/lib/CCreatureHandler.h b/lib/CCreatureHandler.h index 0958c6eea..acf27a08b 100644 --- a/lib/CCreatureHandler.h +++ b/lib/CCreatureHandler.h @@ -73,7 +73,7 @@ public: }; double timeBetweenFidgets, idleAnimationTime, - walkAnimationTime, attackAnimationTime, flightAnimationDistance; + walkAnimationTime, attackAnimationTime, missileVelocityFactor; int upperRightMissleOffsetX, rightMissleOffsetX, lowerRightMissleOffsetX, upperRightMissleOffsetY, rightMissleOffsetY, lowerRightMissleOffsetY; @@ -90,7 +90,7 @@ public: h & idleAnimationTime; h & walkAnimationTime; h & attackAnimationTime; - h & flightAnimationDistance; + h & missileVelocityFactor; h & upperRightMissleOffsetX; h & rightMissleOffsetX; h & lowerRightMissleOffsetX; From a85304550903fe7e60216938430a0b80c36612ce Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sat, 28 Jan 2023 13:56:51 +0200 Subject: [PATCH 16/79] Removed unused value from creature config --- config/schemas/creature.json | 6 +----- lib/CCreatureHandler.cpp | 3 +-- lib/CCreatureHandler.h | 3 +-- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/config/schemas/creature.json b/config/schemas/creature.json index a57766839..f23bc333c 100644 --- a/config/schemas/creature.json +++ b/config/schemas/creature.json @@ -172,7 +172,7 @@ "animationTime": { "type":"object", "additionalProperties" : false, - "required" : [ "attack", "flight", "walk", "idle" ], + "required" : [ "attack", "walk", "idle" ], "description": "Length of several animations", "properties":{ "attack": { @@ -183,10 +183,6 @@ "type":"number", "description": "idle" }, - "flight": { - "type":"number", - "description": "flight" - }, "walk": { "type":"number", "description": "walk" diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index 8c72c5b10..cc80f2a28 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -812,7 +812,7 @@ void CCreatureHandler::loadUnitAnimInfo(JsonNode & graphics, CLegacyConfigParser JsonNode & animationTime = graphics["animationTime"]; animationTime["walk"].Float() = parser.readNumber(); animationTime["attack"].Float() = parser.readNumber(); - animationTime["flight"].Float() = parser.readNumber(); + parser.readNumber(); // unused value "Flight animation time" - H3 actually uses "Walk animation time" even for flying creatures animationTime["idle"].Float() = 10.0; JsonNode & missile = graphics["missile"]; @@ -851,7 +851,6 @@ void CCreatureHandler::loadJsonAnimation(CCreature * cre, const JsonNode & graph cre->animation.walkAnimationTime = animationTime["walk"].Float(); cre->animation.idleAnimationTime = animationTime["idle"].Float(); cre->animation.attackAnimationTime = animationTime["attack"].Float(); - cre->animation.missileVelocityFactor = animationTime["missile"].Float(); const JsonNode & missile = graphics["missile"]; const JsonNode & offsets = missile["offset"]; diff --git a/lib/CCreatureHandler.h b/lib/CCreatureHandler.h index acf27a08b..8b2089481 100644 --- a/lib/CCreatureHandler.h +++ b/lib/CCreatureHandler.h @@ -73,7 +73,7 @@ public: }; double timeBetweenFidgets, idleAnimationTime, - walkAnimationTime, attackAnimationTime, missileVelocityFactor; + walkAnimationTime, attackAnimationTime; int upperRightMissleOffsetX, rightMissleOffsetX, lowerRightMissleOffsetX, upperRightMissleOffsetY, rightMissleOffsetY, lowerRightMissleOffsetY; @@ -90,7 +90,6 @@ public: h & idleAnimationTime; h & walkAnimationTime; h & attackAnimationTime; - h & missileVelocityFactor; h & upperRightMissleOffsetX; h & rightMissleOffsetX; h & lowerRightMissleOffsetX; From 9d1a0758068b8846d3354d65919732b294b0fbbf Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sat, 28 Jan 2023 14:00:49 +0200 Subject: [PATCH 17/79] Fix battle speed selector in settings --- client/battle/BattleInterface.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/battle/BattleInterface.cpp b/client/battle/BattleInterface.cpp index e87745884..3e54a619c 100644 --- a/client/battle/BattleInterface.cpp +++ b/client/battle/BattleInterface.cpp @@ -527,9 +527,9 @@ void BattleInterface::setAnimSpeed(int set) int BattleInterface::getAnimSpeed() const { if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-battle-speed"].isNull()) - return static_cast(vstd::round(settings["session"]["spectate-battle-speed"].Float() *100)); + return static_cast(vstd::round(settings["session"]["spectate-battle-speed"].Float())); - return static_cast(vstd::round(settings["battle"]["animationSpeed"].Float() *100)); + return static_cast(vstd::round(settings["battle"]["animationSpeed"].Float())); } CPlayerInterface *BattleInterface::getCurrentPlayerInterface() const From 3749074a4d1478522ddc9b27ebce52da3107b39e Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sat, 28 Jan 2023 16:49:35 +0200 Subject: [PATCH 18/79] Renamed speed setting name to force-reset it to new scale --- client/battle/BattleInterface.cpp | 4 ++-- client/battle/CreatureAnimation.cpp | 30 ++++++++++++++++++----------- client/battle/CreatureAnimation.h | 4 ++++ config/schemas/settings.json | 6 +++--- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/client/battle/BattleInterface.cpp b/client/battle/BattleInterface.cpp index 3e54a619c..6a6e435a4 100644 --- a/client/battle/BattleInterface.cpp +++ b/client/battle/BattleInterface.cpp @@ -520,7 +520,7 @@ void BattleInterface::displaySpellHit(const CSpell * spell, BattleHex destinatio void BattleInterface::setAnimSpeed(int set) { - Settings speed = settings.write["battle"]["animationSpeed"]; + Settings speed = settings.write["battle"]["speedFactor"]; speed->Float() = float(set); } @@ -529,7 +529,7 @@ int BattleInterface::getAnimSpeed() const if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-battle-speed"].isNull()) return static_cast(vstd::round(settings["session"]["spectate-battle-speed"].Float())); - return static_cast(vstd::round(settings["battle"]["animationSpeed"].Float())); + return static_cast(vstd::round(settings["battle"]["speedFactor"].Float())); } CPlayerInterface *BattleInterface::getCurrentPlayerInterface() const diff --git a/client/battle/CreatureAnimation.cpp b/client/battle/CreatureAnimation.cpp index 436cc162d..84bfc513b 100644 --- a/client/battle/CreatureAnimation.cpp +++ b/client/battle/CreatureAnimation.cpp @@ -47,6 +47,15 @@ std::shared_ptr AnimationControls::getAnimation(const CCreatu return std::make_shared(creature->animDefName, func); } +float AnimationControls::getAnimationSpeedFactor() +{ + // according to testing, H3 ratios between slow/medium/fast might actually be 36/60/100 (x1.666) + // exact value is hard to tell due to large rounding errors + // however we will assume them to be 33/66/100 since these values are better for standard 60 fps displays: + // with these numbers, base frame display duration will be 100/66/33 ms - exactly 6/4/2 frames + return settings["battle"]["speedFactor"].Float(); +} + float AnimationControls::getCreatureAnimationSpeed(const CCreature * creature, const CreatureAnimation * anim, ECreatureAnimType type) { assert(creature->animation.walkAnimationTime != 0); @@ -56,10 +65,9 @@ float AnimationControls::getCreatureAnimationSpeed(const CCreature * creature, c // possible new fields for creature format: //split "Attack time" into "Shoot Time" and "Cast Time" - // base speed for all H3 animations is 10/20/30 frames per second (100/50/33 ms per frame) + // base speed for all H3 animations on slow speed is 10 frames per second (or 100ms per frame) const float baseSpeed = 10.f; - const float speedMult = static_cast(settings["battle"]["animationSpeed"].Float()); - const float speed = baseSpeed * speedMult; + const float speed = baseSpeed * getAnimationSpeedFactor(); switch (type) { @@ -73,7 +81,7 @@ float AnimationControls::getCreatureAnimationSpeed(const CCreature * creature, c if ( creature->animation.idleAnimationTime > 0.01) return speed / creature->animation.idleAnimationTime; else - return 0.f; + return 0.f; // this animation is disabled for current creature case ECreatureAnimType::SHOOT_UP: case ECreatureAnimType::SHOOT_FRONT: @@ -121,44 +129,44 @@ float AnimationControls::getCreatureAnimationSpeed(const CCreature * creature, c float AnimationControls::getProjectileSpeed() { // H3 speed: 1250/2500/3750 pixels per second - return static_cast(settings["battle"]["animationSpeed"].Float() * 1250); + return static_cast(getAnimationSpeedFactor() * 1250); } float AnimationControls::getRayProjectileSpeed() { // H3 speed: 4000/8000/12000 pixels per second - return static_cast(settings["battle"]["animationSpeed"].Float() * 4000); + return static_cast(getAnimationSpeedFactor() * 4000); } float AnimationControls::getCatapultSpeed() { // H3 speed: 200/400/600 pixels per second - return static_cast(settings["battle"]["animationSpeed"].Float() * 200); + return static_cast(getAnimationSpeedFactor() * 200); } float AnimationControls::getSpellEffectSpeed() { // H3 speed: 10/20/30 frames per second - return static_cast(settings["battle"]["animationSpeed"].Float() * 10); + return static_cast(getAnimationSpeedFactor() * 10); } float AnimationControls::getMovementDistance(const CCreature * creature) { // H3 speed: 2/4/6 tiles per second - return static_cast( 2.0 * settings["battle"]["animationSpeed"].Float() / creature->animation.walkAnimationTime); + return static_cast( 2.0 * getAnimationSpeedFactor() / creature->animation.walkAnimationTime); } float AnimationControls::getFlightDistance(const CCreature * creature) { // Note: for whatever reason, H3 uses "Walk Animation Time" here, even though "Flight Animation Distance" also exists // H3 speed: 250/500/750 pixels per second - return static_cast( 250.0 * settings["battle"]["animationSpeed"].Float() / creature->animation.walkAnimationTime); + return static_cast( 250.0 * getAnimationSpeedFactor() / creature->animation.walkAnimationTime); } float AnimationControls::getFadeInDuration() { // H3 speed: 500/250/166 ms - return 0.5f / settings["battle"]["animationSpeed"].Float(); + return 0.5f / getAnimationSpeedFactor(); } float AnimationControls::getObstaclesSpeed() diff --git a/client/battle/CreatureAnimation.h b/client/battle/CreatureAnimation.h index 04f68afac..5d14dbb70 100644 --- a/client/battle/CreatureAnimation.h +++ b/client/battle/CreatureAnimation.h @@ -25,6 +25,10 @@ namespace AnimationControls SDL_Color getGoldBorder(); SDL_Color getNoBorder(); + /// returns animation speed factor according to game settings, + /// slow speed is considered to be "base speed" and will return 1.0 + float getAnimationSpeedFactor(); + /// creates animation object with preset speed control std::shared_ptr getAnimation(const CCreature * creature); diff --git a/config/schemas/settings.json b/config/schemas/settings.json index d3472c3ab..c05448291 100644 --- a/config/schemas/settings.json +++ b/config/schemas/settings.json @@ -230,11 +230,11 @@ "type" : "object", "additionalProperties" : false, "default": {}, - "required" : [ "animationSpeed", "mouseShadow", "cellBorders", "stackRange", "showQueue", "queueSize" ], + "required" : [ "speedFactor", "mouseShadow", "cellBorders", "stackRange", "showQueue", "queueSize" ], "properties" : { - "animationSpeed" : { + "speedFactor" : { "type" : "number", - "default" : 0.63 + "default" : 2 }, "mouseShadow" : { "type":"boolean", From 080d4b13ddedbbc7d4b859e3735499e2f4bda1cb Mon Sep 17 00:00:00 2001 From: Konstantin Date: Sun, 29 Jan 2023 21:30:37 +0300 Subject: [PATCH 19/79] vcmi: suppress warning on IOS Let CI passes on develop. --- client/gui/CGuiHandler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/gui/CGuiHandler.cpp b/client/gui/CGuiHandler.cpp index db88716c6..ced56145f 100644 --- a/client/gui/CGuiHandler.cpp +++ b/client/gui/CGuiHandler.cpp @@ -474,7 +474,9 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current ) } else if(current.type == SDL_FINGERUP) { +#ifndef VCMI_IOS auto fingerCount = SDL_GetNumTouchFingers(current.tfinger.touchId); +#endif //VCMI_IOS if(isPointerRelativeMode) { From 848e8583123710cda764f7f8829d9198119071c0 Mon Sep 17 00:00:00 2001 From: Konstantin Date: Sun, 29 Jan 2023 19:54:40 +0300 Subject: [PATCH 20/79] launcher: russian translation This is mostly finished russian translation --- launcher/translation/russian.ts | 447 ++++++++++++++++++++++---------- 1 file changed, 306 insertions(+), 141 deletions(-) diff --git a/launcher/translation/russian.ts b/launcher/translation/russian.ts index 9860912e4..dd445542f 100644 --- a/launcher/translation/russian.ts +++ b/launcher/translation/russian.ts @@ -6,599 +6,764 @@ Name - + Название Type - + Тип Version - + Версия Size - + Размер Author - + Автор CModListView + Filter - + Фильтр + All mods - + Все моды + Downloadable - + Доступные + Installed - + Установленные + Updatable - + Обновления + Active - + Активны + Inactive - + Неактивны + Download && refresh repositories - + Обновить репозиторий + Description - + Описание + Changelog - + Изменения + Screenshots - + Скриншоты + Show details - + Подробности + Uninstall - + Удалить + Enable - + Включить + Disable - + Отключить + Update - + Обновить + Install - + Установить + %p% (%v KB out of %m KB) - + %p% (%v КБ з %m КБ) + Abort - + Отмена Mod name - + Название мода Installed version - + Установленная версия Latest version - + Последняя версия Download size - + Размер загрузки Authors - + Авторы License - + Лицензия Home - + Домашняя страница Compatibility - + Совместимость Required VCMI version - + Требуемая версия VCMI Supported VCMI version - + Поддерживаемая версия VCMI Supported VCMI versions - + Поддерживаемые версии VCMI Required mods - + Зависимости Conflicting mods - + Конфликтующие моды This mod can not be installed or enabled because following dependencies are not present - + Этот мод не может быть установлен или активирован, так как отсутствуют следующие зависимости This mod can not be enabled because following mods are incompatible with this mod - + Этот мод не может быть установлен или активирован, так как следующие моды несовместимы с этим This mod can not be disabled because it is required to run following mods - + Этот мод не может быть выключен, так как он является зависимостью для следующих This mod can not be uninstalled or updated because it is required to run following mods - + Этот мод не может быть удален или обновлен, так как является зависимостью для следующих модов This is submod and it can not be installed or uninstalled separately from parent mod - + Это вложенный мод, он не может быть установлен или удален отдельно от родительского Notes - + Замечания - + Screenshot %1 - + Скриншот %1 Mod is compatible - + Мод совместим Mod is incompatible - + Мод несовместим CSettingsView + Change - + Изменить + + + Open - + Открыть + User data directory - + Данные пользователя + + + + Off - + Отключено + + + + On - + Включено + Fullscreen - + Полноэкранный режим + Repositories - + Репозитории + Check for updates - + Проверить обновления - + + Neutral AI - + Нейтральный ИИ + Real - + Полный + General - + Общее + Player AI - + ИИ игроков + VCMI Language - + Язык VCMI - Central European (Windows 1250) - + + Automatic detection + Автоматическое определение - Cyrillic script (Windows 1251) - + + Central European (Windows 1250) + Центральноевропейская (Windows-1250) - Western European (Windows 1252) - + + Cyrillic script (Windows 1251) + Кириллица (Windows 1251) - Simplified Chinese (GBK) - + + Western European (Windows 1252) + Западноевропейская (Windows 1252) - Simplified Chinese (GB2312) - + + Simplified Chinese (GBK) + Упрощенная китайская (GBK) - Korean (Windows 949) - + + Simplified Chinese (GB2312) + Упрощенная китайская (GB2312) - + + + Korean (Windows 949) + Корейская (Windows 949) + + + + English English (Английский) - + + Deutsch (German) - Deutsch (Немецкий) + Deutsch (Немецкий) - + + Polska (Polish) Polska (Польский) - + + Русский (Russian) Русский - + + Українська (Ukrainian) Українська (Украинский) - + + Friendly AI - + Дружественный ИИ + + + + + Cursor + Курсор + + + + + Default + По умолчанию + + + + + Hardware + Аппаратный + + + + + Software + Программный + Resolution - + Разрешение экрана + AI on the map - + ИИ на карте приключений + Autosave - + Автосохранение + Display index - + Дисплей + Check repositories on startup - + Проверка репозиториев при запуске + Network port - + Сетевой порт + Data Directories - + Директории данных + Video - + Графика + Heroes III character set - + Кодировка Героев III + Extra data directory - + Дополнительные данные + Log files directory - + Журналы + Show intro - + Вступление + Launcher Settings - + Настройки загрузчика + Build version - + Версия сборки - + + Enemy AI - + Вражеский ИИ + AI in the battlefield - + ИИ на поле боя ImageViewer + Image Viewer - + Просмотр изображений Lobby - + + + Connect - + Подключиться - + + Username - + Имя пользователя - + + Server - + Сервер - + + + People in lobby + Люди в лобби + + + + + Lobby chat + Чат лобби + + + + Session - + Сессия - + + Players - + Игроки - + + + Resolve + Скорректировать + + + + + New game + Новая игра + + + + + Load game + Загрузить игру + + + + New room - + Создать комнату - + + Join room - + Присоединиться к комнате - + + Ready - + Готово - + + Mods mismatch - + Моды не совпадают - + + Leave - + Выйти - + + Kick player - + Выгнать игрока - + + Players in the room - + Игроки в комнате + + + + Disconnect + Отключиться + + + + No issues detected + Проблем не обнаружено LobbyRoomRequest + Room settings - + Настройки комнаты + Room name - + Название + Maximum players - + Максимум игроков + Password (optional) - + Пароль (не обязательно) MainWindow + VCMI Launcher - + Запуск VCMI - + + Settings - + Параметры - + + Map Editor - + Редактор карт - + + Start game - + Играть - + + Lobby - + Лобби - + + Mods - + Моды UpdateDialog + You have latest version - + У вас уже последняя версия + Close - + Закрыть + Check updates on startup - + Проверять обновления при запуске From f577b7240b0d18eedff8b7177c549df4459f1c13 Mon Sep 17 00:00:00 2001 From: Konstantin Date: Sun, 29 Jan 2023 20:41:55 +0300 Subject: [PATCH 21/79] launcher & editor: use qt_add_translations for Qt6 This will make possible to run update_translations target on Qt6 build of VCMI --- launcher/CMakeLists.txt | 16 +++++++++++----- mapeditor/CMakeLists.txt | 16 +++++++++++----- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 1ba52a9b3..5eaef18a6 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -90,11 +90,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) if(TARGET Qt6::Core) qt_wrap_ui(launcher_UI_HEADERS ${launcher_FORMS}) - if(ENABLE_TRANSLATIONS) - set_source_files_properties(${launcher_TS} PROPERTIES OUTPUT_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/translation) - # TODO: consider using qt_add_translations: https://doc.qt.io/qt-6/qtlinguist-cmake-qt-add-translations.html - qt_add_translation( launcher_QM ${launcher_TS} ) - endif() else() qt5_wrap_ui(launcher_UI_HEADERS ${launcher_FORMS}) if(ENABLE_TRANSLATIONS) @@ -114,6 +109,17 @@ else() add_executable(vcmilauncher WIN32 ${launcher_QM} ${launcher_SRCS} ${launcher_HEADERS} ${launcher_UI_HEADERS} ${launcher_ICON}) endif() +if(TARGET Qt6::Core) + if(ENABLE_TRANSLATIONS) + set_source_files_properties(${launcher_TS} PROPERTIES OUTPUT_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/translation) + qt_add_translations(vcmilauncher + TS_FILES ${launcher_TS} + QM_FILES_OUTPUT_VARIABLE launcher_QM + INCLUDE_DIRECTORIES + ${CMAKE_CURRENT_BINARY_DIR}) + endif() +endif() + if(WIN32) set_target_properties(vcmilauncher PROPERTIES diff --git a/mapeditor/CMakeLists.txt b/mapeditor/CMakeLists.txt index 11b3f7659..5308539ae 100644 --- a/mapeditor/CMakeLists.txt +++ b/mapeditor/CMakeLists.txt @@ -92,11 +92,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) if(TARGET Qt6::Core) qt_wrap_ui(editor_UI_HEADERS ${editor_FORMS}) - if(ENABLE_TRANSLATIONS) - set_source_files_properties(${editor_TS} PROPERTIES OUTPUT_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/translation) - # TODO: consider using qt_add_translations: https://doc.qt.io/qt-6/qtlinguist-cmake-qt-add-translations.html - qt_add_translation( editor_QM ${editor_TS} ) - endif() else() qt5_wrap_ui(editor_UI_HEADERS ${editor_FORMS}) if(ENABLE_TRANSLATIONS) @@ -111,6 +106,17 @@ endif() add_executable(vcmieditor WIN32 ${editor_QM} ${editor_SRCS} ${editor_HEADERS} ${editor_UI_HEADERS} ${editor_ICON}) +if(TARGET Qt6::Core) + if(ENABLE_TRANSLATIONS) + set_source_files_properties(${editor_TS} PROPERTIES OUTPUT_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/translation) + qt_add_translations(vcmieditor + TS_FILES ${editor_TS} + QM_FILES_OUTPUT_VARIABLE editor_QM + INCLUDE_DIRECTORIES + ${CMAKE_CURRENT_BINARY_DIR}) + endif() +endif() + if(WIN32) set_target_properties(vcmieditor PROPERTIES From 47457e61cc25f9f24ef6a75a301ed16b35078d0f Mon Sep 17 00:00:00 2001 From: Konstantin Date: Sun, 29 Jan 2023 21:06:03 +0300 Subject: [PATCH 22/79] mapeditor: russian translation This is a complete russian translation of map editor. --- mapeditor/translation/russian.ts | 236 +++++++++++++++---------------- 1 file changed, 118 insertions(+), 118 deletions(-) diff --git a/mapeditor/translation/russian.ts b/mapeditor/translation/russian.ts index 4a0bc3525..7a98ca844 100644 --- a/mapeditor/translation/russian.ts +++ b/mapeditor/translation/russian.ts @@ -6,17 +6,17 @@ Army settings - + Настройки армии Wide formation - + Расширенная формация Tight formation - + Суженная формация @@ -24,7 +24,7 @@ Generating map - + Создание карты @@ -32,266 +32,266 @@ VCMI Map Editor - + Редактор карт VCMI File - + Файл Map - + Карта Edit - + Правка View - + Вид Player - + Игрок Browser - + Навигатор Inspector - + Инспектор Property - + Свойство Value - + Значение Brush - + Кисть Terrains - + Земли Roads - + Дороги Rivers - + Реки Open - + Открыть Save - + Сохранить New - + Создать Save as - + Сохранить как Ctrl+Shift+S - + Ctrl+Shift+S U/G - + П/Н View underground - + Вид на подземелье Pass - + Проходимость Cut - + Вырезать Copy - + Копировать Paste - + Вставить Fill - + Заливка Fills the selection with obstacles - + Заливает выбранное препятствиями Grid - + Сетка General - + Общее Map title and description - + Название и описание карты Players settings - + Настройки игроков Undo - + Отменить Redo - + Повторить Erase - + Удалить Neutral - + Нейтральный Validate - + Проверить Update appearance - + Обновить вид Recreate obstacles - + Обновить препятствия Player 1 - + Игрок 1 Player 2 - + Игрок 2 Player 3 - + Игрок 3 Player 4 - + Игрок 4 Player 5 - + Игрок 5 Player 6 - + Игрок 6 Player 7 - + Игрок 7 Player 8 - + Игрок 8 Open map - + Открыть карту All supported maps (*.vmap *.h3m);;VCMI maps(*.vmap);;HoMM3 maps(*.h3m) - + Все поддерживаемые карты (*.vmap *.h3m);;Карты VCMI (*.vmap);;Карты Героев III (*.h3m) Save map - + Сохранить карту VCMI maps (*.vmap) - + Карты VCMI (*.vmap) Type - + Тип View surface - + Вид на поверхность @@ -299,47 +299,47 @@ Map settings - + Настройки карты General - + Общее Map name - + Название карты Map description - + Описание карты Abilities - + Способности Spells - + Заклинания Artifacts - + Артефакты Heroes - + Герои Ok - + ОК @@ -347,7 +347,7 @@ Message - + Сообщение @@ -355,47 +355,47 @@ No team - + Без команды Human/CPU - + Человек/ИИ CPU only - + Только ИИ Team - + Команда Main town - + Главный город Random faction - + Случайная фракция Generate hero at main - + Создать героя (default) - + (по умолчанию) Player ID: %1 - + Игрок: %1 @@ -403,17 +403,17 @@ Player settings - + Настройки игрока Players - + Игрок Ok - + ОК @@ -421,7 +421,7 @@ Mission goal - + Цель миссии @@ -429,22 +429,22 @@ Rewards - + Награды Remove selected - + Удалить выбранное Delete all - + Удалить все Add or change - + Добавить/Изменить @@ -452,7 +452,7 @@ Buildings - + Постройки @@ -460,12 +460,12 @@ Map validation results - + Результаты проверки карты Town %1 has undefined owner %2 - + У города %1 неопределенный владелец %2 @@ -473,67 +473,67 @@ Create new map - + Создание новой карты Map size - + Размер Two level map - + Двухуровневая Height - + Высота Width - + Ширина S (36x36) - + Мал. (36x36) M (72x72) - + Ср. (72x72) L (108x108) - + Бол. (108x108) XL (144x144) - + Гиг. (144x144) Random map - + Случайная карта Players - + Игроки 0 - + 0 Human/Computer - + Человек/ИИ @@ -541,73 +541,73 @@ Random - + Случайно Computer only - + Только ИИ Monster strength - + Сила монстров Weak - + Слабо Normal - + Нормально Strong - + Сильно Water content - + Вода None - + Нет Islands - + Острова Template - + Шаблон Custom seed - + Пользовательское зерно Generate random map - + Сгенерировать случайную карту Ok - + ОК Cancel - + Отмена @@ -615,27 +615,27 @@ Filepath of the map to open. - + Путь к файлу карты для открытия. Extract original H3 archives into a separate folder. - + Распаковать архивы оригинальных Героев III в отдельную папку. From an extracted archive, it Splits TwCrPort, CPRSMALL, FlagPort, ITPA, ITPt, Un32 and Un44 into individual PNG's. - + Разделение в распакованном архиве TwCrPort, CPRSMALL, FlagPort, ITPA, ITPt, Un32 и Un44 на отдельные PNG. From an extracted archive, Converts single Images (found in Images folder) from .pcx to png. - + Преобразование в расспакованном архиве изображений .pcx в .png. Delete original files, for the ones splitted / converted. - + Удалить оригиналы для преобразованных файлов. From 8cdc9985d288264a376009c4c78dae6661ad868d Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Thu, 26 Jan 2023 00:30:51 +0200 Subject: [PATCH 23/79] Small redesign of Settings tab in Launcher --- launcher/settingsView/csettingsview_moc.cpp | 23 +- launcher/settingsView/csettingsview_moc.h | 2 + launcher/settingsView/csettingsview_moc.ui | 1251 +++++++++---------- 3 files changed, 646 insertions(+), 630 deletions(-) diff --git a/launcher/settingsView/csettingsview_moc.cpp b/launcher/settingsView/csettingsview_moc.cpp index 902992081..4e7b3098e 100644 --- a/launcher/settingsView/csettingsview_moc.cpp +++ b/launcher/settingsView/csettingsview_moc.cpp @@ -202,7 +202,7 @@ CSettingsView::CSettingsView(QWidget * parent) { ui->setupUi(this); - ui->labelBuildVersion->setText(QString::fromStdString(GameConstants::VCMI_VERSION)); + ui->lineEditBuildVersion->setText(QString::fromStdString(GameConstants::VCMI_VERSION)); loadSettings(); } @@ -359,3 +359,24 @@ void CSettingsView::on_comboBoxCursorType_currentIndexChanged(int index) node->String() = cursorTypesList[index]; } + +void CSettingsView::on_listWidgetSettings_currentRowChanged(int currentRow) +{ + QVector targetWidgets = { + ui->labelGeneral, + ui->labelVideo, + ui->labelArtificialIntelligence, + ui->labelDataDirs, + ui->labelRepositories + }; + + QWidget * currentTarget = targetWidgets[currentRow]; + + // We want to scroll in a way that will put target widget in topmost visible position + // To show not just header, but all settings in this group as well + // In order to do that, let's scroll to the very bottom and the scroll back up until target widget is visible + int maxPosition = ui->settingsScrollArea->verticalScrollBar()->maximum(); + ui->settingsScrollArea->verticalScrollBar()->setValue(maxPosition); + ui->settingsScrollArea->ensureWidgetVisible(currentTarget, 5, 5); + +} diff --git a/launcher/settingsView/csettingsview_moc.h b/launcher/settingsView/csettingsview_moc.h index 987143924..84a044eb7 100644 --- a/launcher/settingsView/csettingsview_moc.h +++ b/launcher/settingsView/csettingsview_moc.h @@ -73,6 +73,8 @@ private slots: void on_comboBoxCursorType_currentIndexChanged(int index); + void on_listWidgetSettings_currentRowChanged(int currentRow); + private: Ui::CSettingsView * ui; diff --git a/launcher/settingsView/csettingsview_moc.ui b/launcher/settingsView/csettingsview_moc.ui index 73c7226f8..8182a6d22 100644 --- a/launcher/settingsView/csettingsview_moc.ui +++ b/launcher/settingsView/csettingsview_moc.ui @@ -6,14 +6,14 @@ 0 0 - 779 - 619 + 842 + 363 - + 0 @@ -26,642 +26,635 @@ 0 - - - - false + + + + + 1 + 0 + - 150 + 200 0 - - /home/user/.vcmi + + + 75 + true + - + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + false + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SelectRows + + + 4 + + + + General + + + + + Video + + + + + Artificial Intelligence + + + + + Data Directories + + + + + Mod Repositories + + + + + + + + + 100 + 0 + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOff + + true - - - - - - - 75 - true - - - - Launcher Settings - - - - - - - - 150 - 0 - - - - /usr/share/vcmi - - - - - - - false - - - Change - - - - - - - 1 - - - - Off + + + + 0 + 0 + 620 + 762 + - - - - On - - - - - - - - Open - - - - - - - Heroes III character set - - - - - - - Fullscreen - - - - - - - 1 - - - - Off - - - - - On - - - - - - - - Log files directory - - - - - - - false - - - - 150 - 0 - - - - /home/user/.vcmi - - - true - - - - - - - Autosave - - - - - - - - 75 - true - - - - Repositories - - - - - - - Check for updates - - - - - - - - - - Check repositories on startup - - - - - - - Open - - - - - - - Player AI - - - - - - - Display index - - - - - - - - 75 - true - true - false - - - - AI in the battlefield - - - - - - - QPlainTextEdit::NoWrap - - - http://downloads.vcmi.eu/Mods/repository.json - - - - - - - - 75 - true - - - - General - - - - - - - Show intro - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 8 - - - - - - - - Build version - - - - - - - Extra data directory - - - - - - - Resolution - - - - - - - 0 - - - - Off - - - - - On - - - - - Real - - - - - - - - 1 - - - - Off - - - - - On - - - - - - - - - 75 - true - - - - AI on the map - - - - - - - VCAI - - - - VCAI - - - - - Nullkiller - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 8 - 20 - - - - - - - - - - - Open - - - - - - - - 75 - true - - - - Video - - - - - - - - 75 - true - - - - Data Directories - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 56 - 8 - - - - - - - - User data directory - - - - - - - Network port - - - - - - - 1024 - - - 65535 - - - 3030 - - - - - - - VCMI Language - - - - - - - - - - - - - - - Automatic detection - - - - - Central European (Windows 1250) - - - - - Cyrillic script (Windows 1251) - - - - - Western European (Windows 1252) - - - - - Simplified Chinese (GBK) - - - - - Simplified Chinese (GB2312) - - - - - Korean (Windows 949) - - - - - - - - - English - - - - - Deutsch (German) - - - - - Polska (Polish) - - - - - Русский (Russian) - - - - - Українська (Ukrainian) - - - - - - - - Neutral AI - - - - - - - BattleAI - - - - BattleAI - - - - - StupidAI - - - - - - - - - 0 - 22 - - - - Friendly AI - - - - - - - false - - - BattleAI - - - - BattleAI - - - - - StupidAI - - - - - - - - false - - - BattleAI - - - - BattleAI - - - - - StupidAI - - - - - - - - - 0 - 22 - - - - Enemy AI - - - - - - - Cursor - - - - - - - - Default - - - - - Hardware - - - - - Software - - + + + + + + 75 + true + + + + General + + + + + + + VCMI Language + + + + + + + Heroes III character set + + + + + + + + Automatic detection + + + + + Central European (Windows 1250) + + + + + Cyrillic script (Windows 1251) + + + + + Western European (Windows 1252) + + + + + Simplified Chinese (GBK) + + + + + Simplified Chinese (GB2312) + + + + + Korean (Windows 949) + + + + + + + + Network port + + + + + + + Autosave + + + + + + + Build version + + + + + + + + 75 + true + + + + Video + + + + + + + Resolution + + + + + + + Fullscreen + + + + + + + Show intro + + + + + + + Display index + + + + + + + Cursor + + + + + + + + 75 + true + + + + Artificial Intelligence + + + + + + + Adventure Map AI + + + + + + + Neutral AI + + + + + + + Friendly AI + + + + + + + Enemy AI + + + + + + + + 75 + true + + + + Data Directories + + + + + + + Extra data directory + + + + + + + /usr/share/vcmi + + + + + + + false + + + Change + + + + + + + Open + + + + + + + User data directory + + + + + + + Open + + + + + + + Log files directory + + + + + + + Open + + + + + + + + 75 + true + + + + Mod Repositories + + + + + + + Check on startup + + + + + + + 1 + + + + Off + + + + + On + + + + + + + + Update now + + + + + + + QPlainTextEdit::NoWrap + + + http://downloads.vcmi.eu/Mods/repository.json + + + + + + + + Default + + + + + Hardware + + + + + Software + + + + + + + + + English + + + + + Deutsch (German) + + + + + Polska (Polish) + + + + + Русский (Russian) + + + + + Українська (Ukrainian) + + + + + + + + 1024 + + + 65535 + + + 3030 + + + + + + + 1 + + + + Off + + + + + On + + + + + + + + + + + false + + + /home/user/.vcmi + + + true + + + + + + + false + + + /home/user/.vcmi + + + true + + + + + + + false + + + BattleAI + + + + BattleAI + + + + + StupidAI + + + + + + + + false + + + BattleAI + + + + BattleAI + + + + + StupidAI + + + + + + + + BattleAI + + + + BattleAI + + + + + StupidAI + + + + + + + + VCAI + + + + VCAI + + + + + Nullkiller + + + + + + + + + + + 1 + + + + Off + + + + + On + + + + + + + + 0 + + + + Off + + + + + On + + + + + Real + + + + + + + + + + + true + + + + + From e87a157b329660acdeb22c1aa28bb0a2c184de62 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Thu, 26 Jan 2023 01:01:41 +0200 Subject: [PATCH 24/79] Adjustments to Mods screen layout in Launcher --- launcher/modManager/cmodlistmodel_moc.cpp | 10 - launcher/modManager/cmodlistmodel_moc.h | 2 - launcher/modManager/cmodlistview_moc.cpp | 64 +-- launcher/modManager/cmodlistview_moc.h | 8 - launcher/modManager/cmodlistview_moc.ui | 658 ++++++++++------------ 5 files changed, 288 insertions(+), 454 deletions(-) diff --git a/launcher/modManager/cmodlistmodel_moc.cpp b/launcher/modManager/cmodlistmodel_moc.cpp index 7e9622f26..1c58dfef4 100644 --- a/launcher/modManager/cmodlistmodel_moc.cpp +++ b/launcher/modManager/cmodlistmodel_moc.cpp @@ -21,8 +21,6 @@ static const QString names[ModFields::COUNT] = "", "modType", "version", - "size", - "author" }; } @@ -72,8 +70,6 @@ QVariant CModListModel::getText(const CModEntry & mod, int field) const case ModFields::STATUS_ENABLED: case ModFields::STATUS_UPDATE: return ""; - case ModFields::SIZE: - return CModEntry::sizeToString(getValue(mod, field).toDouble()); default: return getValue(mod, field); } @@ -96,10 +92,6 @@ QVariant CModListModel::getIcon(const CModEntry & mod, int field) const QVariant CModListModel::getTextAlign(int field) const { - if(field == ModFields::SIZE) - return QVariant(Qt::AlignRight | Qt::AlignVCenter); - //if (field == ModFields::NAME) - // return QVariant(Qt::AlignHCenter | Qt::AlignVCenter); return QVariant(Qt::AlignLeft | Qt::AlignVCenter); } @@ -152,8 +144,6 @@ QVariant CModListModel::headerData(int section, Qt::Orientation orientation, int QT_TR_NOOP(""), // status icon QT_TR_NOOP("Type"), QT_TR_NOOP("Version"), - QT_TR_NOOP("Size"), - QT_TR_NOOP("Author") }; if(role == Qt::DisplayRole && orientation == Qt::Horizontal) diff --git a/launcher/modManager/cmodlistmodel_moc.h b/launcher/modManager/cmodlistmodel_moc.h index 208efc625..5fe3c0f3b 100644 --- a/launcher/modManager/cmodlistmodel_moc.h +++ b/launcher/modManager/cmodlistmodel_moc.h @@ -23,8 +23,6 @@ enum EModFields STATUS_UPDATE, TYPE, VERSION, - SIZE, - AUTHOR, COUNT }; } diff --git a/launcher/modManager/cmodlistview_moc.cpp b/launcher/modManager/cmodlistview_moc.cpp index df1e17885..a7bcf0101 100644 --- a/launcher/modManager/cmodlistview_moc.cpp +++ b/launcher/modManager/cmodlistview_moc.cpp @@ -74,7 +74,6 @@ void CModListView::setupModsView() ui->allModsView->setColumnWidth(ModFields::STATUS_ENABLED, 30); ui->allModsView->setColumnWidth(ModFields::STATUS_UPDATE, 30); ui->allModsView->setColumnWidth(ModFields::TYPE, 75); - ui->allModsView->setColumnWidth(ModFields::SIZE, 80); ui->allModsView->setColumnWidth(ModFields::VERSION, 60); } @@ -161,23 +160,6 @@ void CModListView::showEvent(QShowEvent * event) } } -void CModListView::showModInfo() -{ - enableModInfo(); - ui->modInfoWidget->show(); - ui->hideModInfoButton->setArrowType(Qt::RightArrow); - ui->showInfoButton->setVisible(false); - loadScreenshots(); -} - -void CModListView::hideModInfo() -{ - ui->modInfoWidget->hide(); - ui->hideModInfoButton->setArrowType(Qt::LeftArrow); - ui->hideModInfoButton->setEnabled(true); - ui->showInfoButton->setVisible(true); -} - static QString replaceIfNotEmpty(QVariant value, QString pattern) { if(value.canConvert()) @@ -255,7 +237,7 @@ QString CModListView::genModInfoText(CModEntry & mod) result += urlTemplate.arg(tr("License")).arg(mod.getValue("licenseURL").toString()).arg(mod.getValue("licenseName").toString()); if(mod.getValue("contact").isValid()) - result += urlTemplate.arg(tr("Home")).arg(mod.getValue("contact").toString()).arg(mod.getValue("contact").toString()); + result += urlTemplate.arg(tr("Contact")).arg(mod.getValue("contact").toString()).arg(mod.getValue("contact").toString()); //compatibility info if(mod.isCompatible()) @@ -313,18 +295,8 @@ QString CModListView::genModInfoText(CModEntry & mod) return result; } -void CModListView::enableModInfo() -{ - ui->hideModInfoButton->setEnabled(true); - ui->showInfoButton->setVisible(true); -} - void CModListView::disableModInfo() { - hideModInfo(); - ui->hideModInfoButton->setEnabled(false); - ui->showInfoButton->setVisible(false); - ui->disableButton->setVisible(false); ui->enableButton->setVisible(false); ui->installButton->setVisible(false); @@ -354,8 +326,6 @@ void CModListView::selectMod(const QModelIndex & index) bool hasBlockingMods = !findBlockingMods(index.data(ModRoles::ModNameRole).toString()).empty(); bool hasDependentMods = !findDependentMods(index.data(ModRoles::ModNameRole).toString(), true).empty(); - ui->hideModInfoButton->setEnabled(true); - ui->showInfoButton->setVisible(!ui->modInfoWidget->isVisible()); ui->disableButton->setVisible(mod.isEnabled()); ui->enableButton->setVisible(mod.isDisabled()); ui->installButton->setVisible(mod.isAvailable() && !mod.getName().contains('.')); @@ -380,35 +350,15 @@ bool CModListView::isExtraResolutionsModEnabled() const return manager->isExtraResolutionsModEnabled(); } -void CModListView::keyPressEvent(QKeyEvent * event) -{ - if(event->key() == Qt::Key_Escape && ui->modInfoWidget->isVisible()) - { - hideModInfo(); - } - else - { - return QWidget::keyPressEvent(event); - } -} - void CModListView::modSelected(const QModelIndex & current, const QModelIndex &) { selectMod(current); } -void CModListView::on_hideModInfoButton_clicked() -{ - if(ui->modInfoWidget->isVisible()) - hideModInfo(); - else - showModInfo(); -} - void CModListView::on_allModsView_activated(const QModelIndex & index) { - showModInfo(); selectMod(index); + loadScreenshots(); } void CModListView::on_lineEdit_textChanged(const QString & arg1) @@ -798,8 +748,7 @@ void CModListView::on_pushButton_clicked() void CModListView::modelReset() { - if(ui->modInfoWidget->isVisible()) - selectMod(filterModel->rowCount() > 0 ? filterModel->index(0, 0) : QModelIndex()); + selectMod(filterModel->rowCount() > 0 ? filterModel->index(0, 0) : QModelIndex()); } void CModListView::checkManagerErrors() @@ -820,7 +769,7 @@ void CModListView::on_tabWidget_currentChanged(int index) void CModListView::loadScreenshots() { - if(ui->tabWidget->currentIndex() == 2 && ui->modInfoWidget->isVisible()) + if(ui->tabWidget->currentIndex() == 2) { ui->screenshotsList->clear(); QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString(); @@ -860,11 +809,6 @@ void CModListView::on_screenshotsList_clicked(const QModelIndex & index) } } -void CModListView::on_showInfoButton_clicked() -{ - showModInfo(); -} - const CModList & CModListView::getModList() const { assert(modModel); diff --git a/launcher/modManager/cmodlistview_moc.h b/launcher/modManager/cmodlistview_moc.h index 8aa98c499..db13c29eb 100644 --- a/launcher/modManager/cmodlistview_moc.h +++ b/launcher/modManager/cmodlistview_moc.h @@ -40,8 +40,6 @@ class CModListView : public QWidget void showEvent(QShowEvent * event) override; - void keyPressEvent(QKeyEvent * event) override; - void setupModModel(); void setupFilterModel(); void setupModsView(); @@ -74,8 +72,6 @@ public: explicit CModListView(QWidget * parent = 0); ~CModListView(); - void showModInfo(); - void hideModInfo(); void loadScreenshots(); void enableModInfo(); @@ -98,8 +94,6 @@ private slots: void modelReset(); void hideProgressBar(); - void on_hideModInfoButton_clicked(); - void on_lineEdit_textChanged(const QString & arg1); void on_comboBox_currentIndexChanged(int index); @@ -124,8 +118,6 @@ private slots: void on_screenshotsList_clicked(const QModelIndex & index); - void on_showInfoButton_clicked(); - private: Ui::CModListView * ui; }; diff --git a/launcher/modManager/cmodlistview_moc.ui b/launcher/modManager/cmodlistview_moc.ui index 5e546e279..9c7c6dc08 100644 --- a/launcher/modManager/cmodlistview_moc.ui +++ b/launcher/modManager/cmodlistview_moc.ui @@ -6,8 +6,8 @@ 0 0 - 680 - 342 + 639 + 351 @@ -30,159 +30,263 @@ 3 - + 6 - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - - - - Filter - - + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + + + Filter + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + 0 + + + + All mods + + + + + Downloadable + + + + + Installed + + + + + Updatable + + + + + Active + + + + + Inactive + + + + + + + + + 0 + 0 + + + + Download && refresh repositories + + + + - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - 0 - + + - - All mods - + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + + 32 + 32 + + + + QAbstractItemView::ScrollPerItem + + + QAbstractItemView::ScrollPerPixel + + + true + + + false + + - - Downloadable - + + + 0 + + + + Description + + + + 4 + + + 4 + + + 4 + + + 4 + + + + + + 0 + 0 + + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu'; font-size:11pt;"><br /></p></body></html> + + + true + + + true + + + + + + + + Changelog + + + + 4 + + + 4 + + + 4 + + + 4 + + + + + + + + + Screenshots + + + + 4 + + + 4 + + + 4 + + + 4 + + + + + Qt::ScrollBarAlwaysOff + + + QAbstractItemView::NoSelection + + + QAbstractItemView::SelectRows + + + + 240 + 180 + + + + QListView::IconMode + + + true + + + + + + - - - Installed - - - - - Updatable - - - - - Active - - - - - Inactive - - - - - - - - - 0 - 0 - - - - Download && refresh repositories - - - - - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - - 32 - 32 - - - - QAbstractItemView::ScrollPerItem - - - QAbstractItemView::ScrollPerPixel - - - true - - - false - - + - - - - - 0 - 0 - - - - - 16 - 100 - - - - - - + + + true - - Qt::RightArrow - - - - - - + 0 0 @@ -193,182 +297,62 @@ 0 - - - 16777215 - 16777215 - - - - Qt::LeftToRight - - - false - - + - 0 + 9 - 0 - - - 0 + 6 - 0 + 6 - - - + + + + + 0 + 0 + + + 0 - - - Description - - - - 4 - - - 4 - - - 4 - - - 4 - - - - - - 0 - 0 - - - - true - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu'; font-size:11pt;"><br /></p></body></html> - - - true - - - true - - - - - - - - Changelog - - - - 4 - - - 4 - - - 4 - - - 4 - - - - - - - - - Screenshots - - - - 4 - - - 4 - - - 4 - - - 4 - - - - - Qt::ScrollBarAlwaysOff - - - QAbstractItemView::NoSelection - - - QAbstractItemView::SelectRows - - - - 240 - 180 - - - - QListView::IconMode - - - true - - - - - + + 0 + + + true + + + false + + + %p% (%v KB out of %m KB) + + + + + + + + 0 + 0 + + + + Abort + - + 6 - - - - - 0 - 0 - - - - - 51 - 0 - - - - - 220 - 16777215 - - - - Show details - - - @@ -512,82 +496,8 @@ p, li { white-space: pre-wrap; } - - - - true - - - - 0 - 0 - - - - - 0 - 0 - - - - - 9 - - - 6 - - - 6 - - - - - - 0 - 0 - - - - 0 - - - 0 - - - true - - - false - - - %p% (%v KB out of %m KB) - - - - - - - - 0 - 0 - - - - Abort - - - - - - - - lineEdit - comboBox - allModsView - hideModInfoButton - From 4fc96a09cb2d37fdcd55640eeabc52787704e1cf Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Thu, 26 Jan 2023 13:21:38 +0200 Subject: [PATCH 25/79] Simplified internal layout of Mod List, no visible changes --- launcher/modManager/cmodlistview_moc.ui | 468 ++++++++++++------------ 1 file changed, 232 insertions(+), 236 deletions(-) diff --git a/launcher/modManager/cmodlistview_moc.ui b/launcher/modManager/cmodlistview_moc.ui index 9c7c6dc08..d9a893edf 100644 --- a/launcher/modManager/cmodlistview_moc.ui +++ b/launcher/modManager/cmodlistview_moc.ui @@ -13,7 +13,10 @@ - + + + 6 + 0 @@ -26,261 +29,251 @@ 0 - - 3 - - - - - 6 - + + - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - - - - Filter - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - 0 - - - - All mods - - - - - Downloadable - - - - - Installed - - - - - Updatable - - - - - Active - - - - - Inactive - - - - - - - - - 0 - 0 - - - - Download && refresh repositories - - - - + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + + + Filter + + - + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + 0 + - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - - 32 - 32 - - - - QAbstractItemView::ScrollPerItem - - - QAbstractItemView::ScrollPerPixel - - - true - - - false - - + + All mods + - - - 0 + + Downloadable + + + + + Installed + + + + + Updatable + + + + + Active + + + + + Inactive + + + + + + + + + 0 + 0 + + + + Download && refresh repositories + + + + + + + + + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + + 32 + 32 + + + + QAbstractItemView::ScrollPerItem + + + QAbstractItemView::ScrollPerPixel + + + true + + + false + + + + + + + 0 + + + + Description + + + + 4 - - - Description - - - - 4 + + 4 + + + 4 + + + 4 + + + + + + 0 + 0 + - - 4 + + true - - 4 - - - 4 - - - - - - 0 - 0 - - - - true - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu'; font-size:11pt;"><br /></p></body></html> - - - true - - - true - - - - - - - - Changelog - - - - 4 - - 4 + + true - - 4 + + true - - 4 + + + + + + + Changelog + + + + 4 + + + 4 + + + 4 + + + 4 + + + + + + + + + Screenshots + + + + 4 + + + 4 + + + 4 + + + 4 + + + + + Qt::ScrollBarAlwaysOff - - - - - - - - Screenshots - - - - 4 + + QAbstractItemView::NoSelection - - 4 + + QAbstractItemView::SelectRows - - 4 + + + 240 + 180 + - - 4 + + QListView::IconMode - - - - Qt::ScrollBarAlwaysOff - - - QAbstractItemView::NoSelection - - - QAbstractItemView::SelectRows - - - - 240 - 180 - - - - QListView::IconMode - - - true - - - - - - - - + + true + + + + + + - + true @@ -299,13 +292,16 @@ p, li { white-space: pre-wrap; } - 9 + 0 - 6 + 0 + + + 0 - 6 + 0 @@ -348,7 +344,7 @@ p, li { white-space: pre-wrap; } - + 6 From 3da50e83bea4f30971f1262cf9de0c509f391119 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sat, 28 Jan 2023 00:38:44 +0200 Subject: [PATCH 26/79] Re-imported icons with higher size to avoid upscaling artifacts --- launcher/icons/mod-delete.png | Bin 1449 -> 9013 bytes launcher/icons/mod-disabled.png | Bin 1604 -> 10692 bytes launcher/icons/mod-download.png | Bin 895 -> 6457 bytes launcher/icons/mod-enabled.png | Bin 1104 -> 5840 bytes launcher/icons/mod-update.png | Bin 1341 -> 7096 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/launcher/icons/mod-delete.png b/launcher/icons/mod-delete.png index fa0c04d95bd286e97de68da3b40bc1cfd0dbcfb9..8055222aaced938323821358810daf6a44ed08c6 100644 GIT binary patch literal 9013 zcmW+ccRbYp|L;48JA1EW%gD+~$lkJ7*+OKCB#t|~Br`KJQIt_iGH$p+i6fsf<1Rbv z?87-f-{0f$dOe?iy`GQf99iKq}5TlqI z={v@P){AK(B;2_4wx$kvPz=H1?Vq!q+I@Ys-=RXM+e4?JbZ*^e)(`%Ci`Jah3hz=T zzR|q0G;}TDg!#sSKUn%In85Y*F7POQ^8Pu|5!JLs72F+U>#gU>gJx8i>Tqd_%ht@} zmgPm_^P{7nl{M;)Nm#S`wQE7|+qkfcz_w?(C9vqXRTH2C4;w}}l71+TZi+2wemONYop zvGF;NiC_dd_2>uDVOyS*+D=z_ z-Ai{u_WG5=*eUCeF@et_+CLE1q^!Ny8l42O!e6ra73ZKM4Y^(pDFG+P694VcvN7w! z1p?_X?3DZ}MN@C30d_&%%?sEq9^{6~twi2Iw9lLlrMBG}4Ojasnq>;%LOuaUs9&A8 zEG?bryeDZ&a!|qetJo#7Ce?qA+D<<`*~T9qvmZr&r>ct^7V%z)Pu$Bm=f)P`K-)v? zfz;Y}>|XV!M@A%ZIzB}YNYq~^hxz=GX~7$f2k}}C%fOF zsP{lf#jr~vS^_bv-F-yzp*(2@7j3mp-_jZ6HWAMROsd%dQ`?)5tf#u@>Hi#8+L-H4 zzxNl!^3oyY$1D35WA<47nKW-Eb0BIs@Nz`3n_ktBT+q;AXjhDFeB6QVW z2F!_Bc18}38Bi;L-7H|djpCLqh()-%cJE|_s#7jq_i(!d?^aJ1UCGfy09CZ~gY2rR zX0c+inFqH$-ls}oGh&eY4xT!{;538i{S~`9_?yDTU?{JF4YUyeb0?*MBmVnEjId(X zX~-fZ-2UTOgy0-R%S#6uB_hyry7EJaZ5YhAhCO)`3O*M}q=HsZl{USx(ZrM#MuVAZ zP@MDDD26i=4agUgWsw-;Y8K>C&r2f)q*?NT9VB6b1ASUqekPKNTgV736xc2b~1Z^^NX)Qk3b`;ToPkD z45+!Li58hUN9Jd34|s@A};i2Y4lw-LR6>$ z5emSR`AmrIzpQk;8=5&b7p~$0NJpQY`3+T^Z{4)VZ^&v(;6j zREk~o4^0d<9x^9RN&@=1s#w^((|htbw_-E?^j3}j_T-ywyUPL92`8{*AUK(?Smn7O zS-HX&{6MZLtOa8FeX6;N$dp43_*Wulh7FW4Kp_cIQX^d+J3YN#e+f1))JooGPE%Zq zC2BoRm*^^`yPK{%^rtydpo;D(ESII~4E@D^=N1OS@e-P=%WMSE!1ooYoRM>AVb=NJ zbE5QMK}Lv1BWbRTMFPWQOw{0*G1KaRESQ+L5=l;_vo~mdsN$B@U*U3~xicqfWj}OI zSMSW2cph!cwePA1Nn`IYDjjz(m(F@IEAc+8)CWU#B1u9SHji+JP#t!74%I!4$V6MC zOfC8}@pQ(~w`NGP!?T#^k=8QE>batyfw=rs87CB*p({yNRb{?a28hBrEZDNa&&80q z!~cLN5X>E*--;x^gnF@4^pN7Iy1{0o<_D7#&u9I{&v3dWmepF#ox4*_*Ulaoo*VFZ z(*wKQUQZYctYc`U({ZpC!PeV=SajhC1?*!zz)z2j{ zD~z5az;NcD#c(*TPkMrZgYwmji)adoAZOwZ1x^Z!TH^M*VjiYB1d)woR_3*BKxU;?cv_^}fv0r#zF#HG z+-Mij0q_Y{VnI?8=)%f|$7Rsd&vt8oDCP1TrGB>feKRCQLBAfz;9}4_om5ggcdMoE zghmMBbbN>duE0yJHM%Ok&LWWcM~j&}(;7im&|8vbOWS(7b}ixfL&fG=+by9FP)X^o z!vbkaO?ZOkmJ~eaKJ4ZfJCExBR*X_^&?_KuHtZN;yedbaW-jo3l?;Rwvl>0TvOW~^Dk+dDygCFX=mWmLQA1P%|fu{ztEd9%u5x zp$G+Hl=l$ZzoaK4_;Q*0kB~(ig2=emQ(Ecn%eyu534IY&eBYR__D|NJa+(O_!naQglCJca1kUtvF)~D3%o92t4{Gg?AfQ6&gEH+mbu4J-~Vp(MI~8m z16B1J z>brib!jfehL}@m&O+61Mc90+{K-Y5Q_=G(U4JldJAqBs+dnSf~e9a;h*h`kMDC{fD zMA^iXSgsEo?JjR<&t1j;N=m=$pC($IC&G<-#Zo2e)^IvmH95eVSUqk>xnE$+7toe* zebxMqP2&4s1N_azbK75LnR7@LX4m`t#dr1jWxZs`8`M3MzFU77h^APrJ&_bRUYlNx zUmW?qH+Rr1mjcH~J5-O(7YblZ5PRYm1O=JATAG+@paC7JO~9|pW5>2v*N6IY*B?P1 z;cR%3gT3~&-a}o{Fq8iV8XG?+-R7zgFCUANCx9HXBnSgM+#dgWE;D^z4qV74Iv77^ z{e=`b-Oj;{+vXcUpmQpC&d;+?Tvom=^TDQi$4`jCg#!EECTtS_>W&qN8O%Q*2KiU2 zq_0ono!=hMEW5T4-W+Pd?U7Z=lrEq<9a6HA4vgA~7$%D9yHPG(*23r z{%dSNK7J_Fr@9pGzbIn^lYkN&p7DFt5H;b-%Hm-0c>0!`cd27;A-8}jN7lc6>Aq(IZxT4iz2bmm57x6{ z92;*m^dRq(Gq^Ks1iSyA)vxF7hrR_6a?l4KkH9N0Z}1}Jts`N7YxVP?IKA!9H-GJr zAE4$5W7P$hU7A&U@i*bW-u#QY^0ckdrxY>0TNSPrxAKMgDtSCkOxehUHWOuRrPWzh z{rau#dGjk-@M+BF^h)3$)vm zbePZR!7ZYokAl7w0ijC>m;cpqzWwqMjAmK?9SIAR@U?CpHIxcRT|3^tIADvg;YxT? zb_W@jb(>pallFiP8xF;gyimY;D5IpAFf)h0NIoXxF1JI$+krH~w7#&Akmm&y;+PlR zx*a-A!S_as8O`_DzLFay(Lw6KFa6G~E=79|SRoS^7ywEL2xYznrHz2?n5L-mrw1}I z|Kh-~MKQn(NE^s_6BCmckKtRLVoVL~-rHXRUu0vxr-GW{|A^G#q%=QtDgff6E)DlB zxJC5AyrK$*1`;3=tmbvu?T6|te|!R@WP6o%sT`lYnUNOUt^U|K;od`y^Xz_o2yDAv zBn8BS0AY(d_J>Yx23W{<48}*&!oq=!)R!g zZIreGkQVqEOco!GWEYIPkuE2i9(aQ=&M2Qqyz9J<%!4F^guM07Pi2Fv`w4_rJDMwQ z6fjghqno2G@g^%813L2JTo}m#9?@r_l7@TAitVb)!?r&_lCYQ(E*S`-G~uW(-ma0N z;E~btzXmM>OqzsnViauvXBtD$R1V#$a;_>YHi5utFhAUy%$uU4qf?o`?_a&*wzMr* ztKro6vUu*)l_2~GBlV3GKOhn>+RT6{+SUf$YRJ{AmDgXtpM2({dqGF0m)9?-T&OuFCTg{d@sZXo=rlHSB_@U~ zG~hA(@}ar5oA%7+?DvcKu@5-ucyZH7fqr`D`}#;YyG8Ns5;8m_E_oGo;tH-PFJG4q zM)87*J{IRlJ(dHhFn{3%o++1ya%MbmUgU`YZh!TP4Klp-9}k1xj`2z|Tdlj0 zfZ_Yw<(8@^6TY;M92^|J!HjP%eNdTqjH+u?$$t39nZz1It$(m}=k=_0%dCYPM@A*f zTundW+@iD6`CU?a()!6v3PyMN?eGEC>goRb!=E#RG7YLKE3^F*_*I!nH@mN(Wu1hK zRtq8E7SG|%6NNakdSzea$^~Y$7Pys973-gqg6FN#7Bx{_7@Ozbzd?|qv0;0m0LuAZ z8gp=OtS%FpAu|j~xDaZh&P}CJ077xD=8wTjuPVPp|0V4D5Bz{e^~7~w5xme7xk=2Z zB?R2LWB(on{SPwu;mNyG*9H+RD6?ZI!^Rz$dL;-V3kv@RGl2ab6TYS4-M4n%z1vYc zTd8GvEx$K8IeCBV9W)=A?K2f)Et>^B$rHJVO2KDrts z6z-aJLL)`hB=)vwa zO}n&&?Fg9CCOCG-pA^mFRj8xo$z5Bs{3#@oEJ|)4SzcattE*sIv&5V;pkrw7W2BdC zl{9w|^qQvc^Tz5(fl&m%vdRlfZElaaP7~p-_WQwZ6#CaO=g&KFN||l?uq0uHZys~0u6KC; z`poM|HnIXRIP5}OeR{4E>6=zGn$=_p%W@W7k8~r^fk(~TtJ|4NzdvtGGm^{&6M@9Y z$UHVwSmD2mq*RhzPecFa%&J#`A_%XvLvH@&-Bv9 zSBR0jVYmmNl~YL=>9NfR4iPa!6dUF+)3s-en9+mgB-55yQjQuM?}z@C;650-SnVo2 z!l^wq{i>DVWSm@AS62erFa>$3-&uaYTB2cJ!yMn?C7g2ReTfqPP3Cv_cW$JncR5`Y z;hUHQ^hz(i*_-}1WzP8WCS1+|HHMUQD+6Dem>eS5;_9=>OSwp?oc@MXF9Cbm~*$e&DAgMooE_ZU3B4G2^46vf%AVAy-9?>Y8LURahDaO}5Ycd#6 zn_s2&s8D$J{U}UX0jq6=790=c+=HREnNs6I?r+UzO9rYjbaZg$Bdy-_)lBs@{Nt`q z6AI&gK!dvXlNNb?H2_~3a{`r!CkglY1TbECp_brjXs1|FClW=j0nB^6NKUy&?muSE zi&=>HX`G0Y7J^F$|EV+F%MxY)GLuGHj!f8nDd_L(UzVM6?MqDhNt_$w2JzAM@n_pa z;HR+xg9LW?=E9MGLEOrEvj>r%B|F=zg zefZZu6U9ZY1cj=N=UQFh6Zcshsj)?pGDT#OmP&mza+d{TeWo1rh8<2`V$fH?Ue~Y; zn@%7?zC1>oSqZPGYh$B|qJ#>;JyZ~R=)ppDmN9KTqgNg`D$YyK$ zz2<8o6_K#1S85ccd|9Icsr8BqWq9oycZM`1c;J$cWICuU_If(*ioaM)qoH z(D;zvrbhpTyD~|Yf%~5Bz8w|U?#n6wi1vH)PwO*X8%QXYh=d+-uui~keI*?SeE;^z z@p$Ob%4j=S?)?Mo2ZnDR2AhV_v{W2CJLwRfaW;7zK>tu@)!jidmiNlyWwVj~>qpKU zTt8v(dvA@icTRmf_bqLlgP1D+ z$uQ~xbDE79M+k({B-q#_J4f8|hn#lcq!z@7n}Rvubk(MlaE-wxC;xO=Dp$ClFyhrZ zGk9;97*DQCZ_w&q*$HIvq@yM_p4t-vLT3LH9ajLYYEtAu6rrHDoU54ef$7d;nZMl= zYkLL?y`r-}j^#@hHN~1WOytUne7zI!T|c}s_t_Foss`ebj;_eCQPhOLFKACs z3P@u)&J2rW4Ne~Ck?;qXL|MYmyr?XP=5T`grJd-iAon9@tZcl$fRecgiR^gsgv$p!?gH%+eD= zzP|3m7L7OL>aij%dy^E8BzEglTnc`vaVT+{CC}fWABUb5lS==U5$AAcSFu$RXCLko zQt}8+LmcbGYB5-KgLmeju>@I{<_yc6j4rNBOk3O@G$L&+*muIHO0;uxiv?@%Asl+O z7_J=ass*FB`-CkD0(w>nr6gd`6y1eCG`Xs#z}M{u?V%?+(;8pT-|xUeF1d#3 z?6)-ZOrIwIumH& z!rdiZ0vAF-I!i&q!N~}2YUn7Rj>~okx!mshb#WZ?SrJVgQ(EkkNe9Q#GZx9 zhOQJ5)R%Nsz;HiO>W}%tLOWp{;lF-3L|#{Hj=9Bq;+9xNshE?QtO@8|URv}^5%$PD zfkZL;+-$jp7l5R+sbr9Pu6oqm#hG3Pvabo?0L+_Hb!BnOiT%8;t|4SaHtMJ~dD>jc zqS2W9yIr!u!sIBX2$M}$14A=>4Ak3o{poz7DUNMQwI=g~KcS0YbXiD4JmsafxhrXj zT^UVBe~fELtaSV_rNd<4Dz{tig``!K}TAd`7>FzJB@#8`O^W4>>O%^JR<%8gl-# zOR;!X13emuM=n66D6jp2 zWdx@rIf9rL&*)7(<&$j1n!?EkqE;8EwL?P(NzA*NGN;4&chb87nkujo?bww;MeM#i zzY5WfQ63`KA%cm53h(Xh_0O*fN8bm*TjoxbyySd_s#r;CDqBMpj6X`p);xRj@`ECwAMOG<*|e|=3P>G>FrW?$wTuLNkk-n~4 zU`bA9W26N#<6yQ@!+b_fr@KnQ$G^0a7~0OJ!f0+m(sx3uU6LPL!|o`GZ!9Pc-eE&+c@;y>-Vm%Z!=D`zl= zPsX7t4hn z+36*s@w#?+4jIibJAC*M5qU)#UYv3&Mix(Q(+Mrq{Y1f3898g~O&KXMW@|HP&5bE4QQ5IOC0y|+Cq-oidQn{-_A zCgIN4Wrk^e=+jJ2bF9kRW#o(*i{ABIQ${7jSh?vx@2V~w#4om9%b}q`nVUM)1*7mc zKkn{iJA2($+}=6N&ujKp4m8SIHLr!elMq!^SmDsR)F*124U#aoF8#W!yO32*hv{G6 z8qwQ=Of-_XL7xtE*kuz2YTit#&0l7suqu!6cYr(uIQ1X-tg+?aF1pbDh)?)WatNFG z`z9b8$e);RpYTME)A-Rh{i|HkmSUSsI*h1@vp0Q0A6MAy8ir)l&mh}p=85zfJxlok z_OFx!2HU-=2JYH4N$i~wzp>dlGle@)UIck2qBUGYexhP6}z*!2863}9|-ZPaYwo&0~% CrZ^P< literal 1449 zcmV;a1y=frP)zs}v|HDFrc-hzT#gh&~y7Ly3t7qk>Rx(HIkm z62M4;FC<_hFD4igee!`sF(?wTkwWh@P+IA3cei_X&wXb6XZCbygJOK}B>&DiGv9pQ zf0_BS0RQtt9<(^HbzRz^{&U1IUck=|!g#%$7aA>qfMMbLUm3(W*LLxb{C^U-($kYj z8ume<(|xJ6oiw?jGahMf1}za+>&&vipZXKZ{R4LS#vlX6kEBHLlh#X<_P+{Tf4sAe zaq@kly`!aJ`?feW5K_*8aLNGOuYhO-NGu7EOapg0+tX!FBUO}B31Hfz#op)huItSLA1jj5p_bmB5c(T@3-(57e*ejM+nj5I7#Do58fu;L*O1V9KZg zO9^<&87|hGlO8R zHb|Q}aSZ&~EX2}{u=UtU$Tl@A+j{gQMAK=tHgn>56)(-p%s{-cF~K<9CAoF^<1?~e zk47Pw%3|Rd5Iije3+mpw4U_L4gw{hxAkxqPTMi$s)T^cjy)D3<_xcn@$WtW?FUNcl z-cI6N8tY*Ys=gtNK%RW&xQg>$1RQdXY2*DN zRZpZ?+4Ui_WGOsx@(YM!isS*17Ok&`Z8(>0TBb03VHC*Wlq?7YnXL*4K?cl%iQ-xX z z7E#{ta6`{q`@yKK1wWsMkyrMDH9i5>*i9ID^)>KiO>j+OBzAtE&?9iSV3iyJXR88% z;NQ#^9ViFbW{6%5cVu55m{rhp?k%|ja;5_o!1+bJ z==0W%@28^1!Bw@1BsYsdI8(ii%AzZjsDee<#$;_dj zS5J|AX0^IcJ*)V{>fkKNZz zrP!V&YaVKkBz|cy5;bW<*C6olnsWsrM8Lua4@N~uwsGBnoaYC5*EWaQ+~!l6u?d-Z zwH%7Xr2S@PeS>P>)j@PeDG+guM0JLzBEY8Sb7{0P3LSh5-lsa)_*`_>`?d9mPVyf*J#TQNSnmBs;h5L(N3RpPoLW(;cXfhwk*q$ z30X>PEaMWXBeJ}j5G>@JhrxLejD=vc00$^Q7?DT{5={~ijS!-8%GJ~JO=>I zCl{Q9r`OEM2?Y&AKtg#S!CVl<52Lpi+PU+#dg7GMOsj`m_Gcw-e0RygSNd-d;0=y* z8)~a1AALUoc`(#a$3iO_L%#Ada5V}R9RN$lLBIh@KnT+FILH&AJF~NP!pXUVx-)Uk zCrIF0bAa*mG(J-aG?WLLUknn6z-VuWdZtNBp1VN6$gPdxBsXuh_*&76K;`o|1ir=65gd7b1ap5gH z!@ha*V0E;D#YcqmT_izf!zZo*=egJ0PvS0k0e&sU(3N}p1S!85a#yXC zsUJrC$-fuW;GIW+rgaS!T*hz0l~qd$cJ2tV(SBIHodEa*&>{(3xu5`o;S*HgdKEyd z{%bde9Fw_w28B{q36hhKk(XcAl2_Y0DR7tI4c<8fIJ2?-K0?WN^4Dz$=hW9xqwO+S zJSs}NYZfG4Pyi5ktAKd+XHWpq3jotpe@0^nml_CufpO5BJou`rp4$u zKh*NQcN786Y-;#lDHwcL$!)iXB%cg(418FY_xYZ&;ss?8fcJ3!nctdwcLO33uG<)L zOz{bj75Ek|g_SbU|J*Yw(^8*Uak%AOZ+il8fSg`e|1r5B@2}?FeNV_9?uXUW2||TR z7uz{Xyl(Z}$}p)25L7@=fJ|*b=57E0T)?|3T`-2OTu=$OG5}EKEda?YME}!It7bI% zqZLP*|AGMQZApM1Jql@ATm84>Ii(Mj?z}Z*_jJG>?05I_Qw<%(bs9eL82||GKQsQK z7Z5-fI)Z79p*t5zA-0TwR9p&qj0pWNzmzn3d-jcl)CacDkU1nX>GUN_uWB)d5A4^} z_O_FeA$@1{l`A^lCB%ZxFFFi3<_0}{0;B{uad zwl5NreL3N<6b=x7UIb&$T%a=tTmT~QQ`$ifV>k`?>De9{gr3q-uxWFUS=Q-q@? z?k50y%PYX~wRNBJ&zbY*bGGjY8J91Bsc{f^T;fo889rB43*JC<{urOln2JR2kgoNQ z7|gOMk?09-vcn*}i8FGQaP%rB9SUk%GF@edH!R7OEhS7i4Fh~0qkJg{ZIEQTn%is* z^+_yPQm6!r@&bW^T!)EVJpYACck*eBq1Y)*m`@tcfxo&2y}NfM_5Qx^uRYrG7jJ0- z9N$p?KXPvVyXW0{d&s*sZsL0zPrZ4cVGpgWsiHpmClvH=e4$V%w{lKSAV0@3bWG?708D#h z2m$=5U58Xy1i8EtJil`M2GkgZL<{zFq-%p+BF< zMUzLp4WE(JFxuXeFx6CwbN=3f5&f%aIiJanrs|ctCm>57lKo0?!J_hrKN12MbIE)L zV+berZaJM6u?##ELC=fNCy2#Yu07HGO4brUbo`9yCyLgss|ywsNcxqFQ{057P4 zpa7TxKF!TXtfR{uz0%&5%u#EFmTAWCH4d+?dz4c0xnMzlD1X7cpd=H(cBz5r353fg z&V}67aisl#HaN(JPMo+jIGS2{*BeZ7iZ>xl=pPMMR4fk7FO!VcE6)1}Z4*3NC`?uk zXX67l1DI>=NNv%k&5FOMuq2qs`NS-LOyQfxRO}NMU|{{`|QCFnju{cT2u- z>Eu=c8VY*(snxD@e0tnJ?B6WH0O*d6asT8cf9szhK7w+giNRgQc z#34ah1-Q?Tw%@*xv<&mft*2Ukl^vhA7v-5G^gT&YZkoHeG7O4wB|}EAok_?Y(#Z2G zU`rG|d-rvZ#`HzPQIH)+fC244f)$m;{%{0lUypd6P3FRpAm*Zh5?d#M%?B(M`vj@3suzb=xG>9~k1G#b`+Mj(c$#mAZt*NOsdlZ0^ z&*eAP`&eugES?x=J3QE)Q4RQ{0>E1l;H)PGYz8xJl;+JN#r1W$0NItk*+Z7Z){{+N zv@PpTds{n_mSuxe3E=!1s(uoD?hwI_#ehT{g>`j)$oOK`907Y)H`LNVaC>f9g=}_o zWOlijd@cgdK|~^m8{$a@W}47nxr~CErE=ba1!blc`0cKnZP`CeK;|wi$6lUB4r2PNxm5q-gi$bTqrxK&lkz`EeP?V{153i~hloJ3q z3|J$>$Xl|+M`V0()(Eg`<;r}>%40cY^X2ijPhc{f92pdVP%sV*boOb?Vh?OT-TYzO zw!hWa*{^a2U>e|&fe`8Y2a-%;!M05y5PW0T^4g8alDPH6iKuOndk4GvH0S+YU{6!^ z5cds8t3Yl=g#?0o_O4o0GCK-j+mA=)&$n4L3T9d^;F0-Ua}j|k3I@9eG{*7e9cRxS z0f617oBzSk%>x5{gBo`MEP$So5Jqz+Q*Dpbq#Ezz>6E@>t9eeL2 zWLYST41NidInxbrRYhd(JZ{miH`In9)0fBmN&&JYd@1Aq)o4O9 zGy_DE1+X*tCD%Tu&0tPhc@PADH{%3&si9#p4F#(Mp&+bS-1|mL>~lp0NLPRFK%8;= zAGf!(B;bnM&z@CH)7lvwiI2vkDi?w0Y$_qrYlx(FBkCpDxP!9;LIriA%BuvUM5*X!vJG0 zlQNa1fLEUjK$f7X8VubW-hZ~`NAQR{&Y$mLjPD%iA5l}9K3NSywM5LM95%PGX zq{L?q4>`DIzTXy)1(I(2`iA0`&HgJb`O})Frluyw_`}`ZgGs}%0AZ6v(BW}BFinHe z*^Y{Js{%?+=&l!6toQ)3Aky#6EdH+Hv3(%2A_9L+ikj{Q#)z#@g2!fz0KXYKOS#Wi zsrZ!i<_bSN(@QuBm7wcpy8884ZS7Bi%yCY~Q`xV!#(;qlpxeq-y{k;O?9;a8*U9puixOb@Pl6fNxjc=&;Gk<*n4{WMl?6*ZooxSh{Npdfn=Ge zT)Q$v3H|wRYgR19EQbYrV{|meIhCgzr5u8RhWGaZD;h(%pfCc4yJv&|9Jn)(mrGe9 z;R4?KvPUEWsDxxv2LmqOd*)2n^`4p0NcfRNQok}Z6f@lYvN+sTBM!5x3&BtT<&8BF zB4hWjm#!(sEXF-!pLGc*msB+gI4$9|C_s8lT!9Dk^9Vq0ebWiBtEwtMWM#fgWw2CA z1m3lVClS)}pNJ9F3{W1@I(T?1?CA4($ zf?}#zFQnfKvlxuA@2Lq*Cz9mVGH3i=z>-NQ!5}!L#ba%5ScNO4mBuV#G4~ZU^R*vw#-Tb6Xw5wcD=Fn~w9I z?_Pb~J1$jCKtSyD`~VOlop?=fsUU!p&E-h(RoxYU5Zf##V@lsoPg5EpkT4K#y>bcR&#X| zN32r#Z%?mIPJ)5}>$hE<6C}RzovW_D8jEa-`99ANTqdEeswOthe zvnqfDSgH=U`mibx2}N}%)#D@zG#ou|4x3Q!PvVF<8Nn(5yZA)L(sK@^)N({U`Y zow-m##MZN>>cK>{=BY#`=!8n(-2Q@82u_|tvD`yL>sIwSZ2suG+qdViSf*$+l1ebq ztRpFHnHYeIV+bLjK>6+pKyi*hfK=@ds1<^C{+|e}U=Uk%birP@|DFjc)f0y+Zmr>k z+CWDVireV$1*cA-f8~%_9vZkJZpPpJ3SMboQOu}I#Rd`SYbhGyIg#N=5Wtk_ZW91x zs3in-{s)9^)lPDs5KCpE2QIo~FW3kvSlW5S}=Jl^fPLx!&Sq z#FqVkh($5C9xG)fmd7X4zMlB@LmY!ZP>k*hK!Gg+k{KXfsmXl;7;Jj?tPjvdd)5Bk z|D}X{*Rk=s8%dc$HWJ_ts32%9D_ein6}e0<^Omn}x&DLbvIYCDbCpsS0R3;6(&=WY z&=LTc{&M?vtBa!milmePk&gKEwn{NTMvSZP&!Wrriu>>Vmss-e9UW^lRWilvX9~5) zmFu-;5U;p)bKWqF-}uVr>t2K|nt$EC43iOq=h?S910pD;07d-nd+v$4*#!71l7KJ( zW_{HU=MbNm-6G=1P?;Vqg1utj?k|P0y7Aa#!%Hm+r68_WLCrcgUb`_T4C7zFvT^HH zbjb=$N@D${b$JN&!>??*eg(Qe-X79Gh%LQq$%qfDS;N1q0FO81fmD zR;*i90?|*ty?OJ3i>p_W>9{I`K&#O9>}q z*-Bv(7SUdReD8FO_$k8`uTl4+xut)lnL-{OLI0AXxn!t+b%4xw7J7K72GEMCV1oN!rOBF@PSXP#RYp}@n`kCROV)5ML)4uBm zvAzjV=@mnk62b5=R<0a$a;4&<nE{5#^9$o8AoswX@0--ObgS7?*~dL-qBqF5cavQ?~!Sy-M~TXQ(=f~)`4W+ z{tJM(G$Ppj6&3TZAD;4BvxgUAT{pQTy#VppI5uopoi{D>%m2Fm`j=fi`5?t~O*Ugg z1%Wn$>V0QVHchy0;Ks}kbXNe32R%Pzn3itsnm#KeiWLSFEX!6KH*UQSm&jgwX!ox~ zlD~Ph61d!<0oFq!2<5uqY6TlMtgg#FXHYpyj-p#;#LXiM)`0UhFm zX~GXe34wiG6@ZkrgQ1LbPz(|xF*?x`f38pY0g463l8T>>OKA0y@wR3pcb%#S0nW=- zDNvm?0xR&bVg1S+1aAG;bvLZR!!$CD7ZnS6O9g?R^t6gAQ42vBW*tZF@2UXadi1DI zicYyr50uHIRH(FKXbGSvpUV*8^|*v~rdrli=JTe!`1F_;$#bGz57jA>_Bw(rDO$B= zS&>QI_Lu9om+&x5D7?1ZlXH}xb_tx`C!7p?HvoW%nPG3E>&wCw_~v?}sf6u7TeV6N zgY>);9W<_ASqnyjfF= zPf!2rx35-Ytj}d_NY9&L2G9Q1U$ky?L-7 z07~gdPn{b$!$YMR)FY;w7DWIQQhR{N=igy<5;(>FPq6ZFZze|H+%_muwQ81%?$79FBdX#y^$V7 zIv)|pFi>{`C$hwCiz0xx9^F+T(9veY?dS)jrz&*x0~|rf<+J(v`U9`QWngbUw)>lk z_!kb=qNb8+?&}9sqS6^gkQ3wBxN0zO*ygAIe(iM^{BEm`RbQ9OWlT#5DBqtO>C7GN zzw7!S=F{($f9G|8b}x zn~DKWpD@y1hba93T&ZC5>cJcg^KbuV_14E@7CV#ui22u7^cQ>LYHiM>BjFR-ET(GB zP%(XFQST2RrTmA5%z6g7uR{$?tep;8m0@7Rv^D`(%t;{%FGn2WKr8`@c2N+mp=*K-L>ca_3f6Wq`6d zj5Yjb%<9iB&0WGw<15pCY(=pGoD38b7&N;WH2!dM3abao85q_(|7`WP?U#)RPV79* zz_X6J>^5Ts))1^GD*>etPEBJdXW8Xa{>n_$^REohpRL;VL^8}bt{f<3qKT>VUqj7K zI)k8?0LwuP!gMn-5SjmhhiL{b!oD{>9K4{kYy-2ps;4J!NY4l3j8O|rq`fCSB|TC? z2tuJ;GN-DI7r(G?#owHHU0eqC-O9+wbIU`!s}a4p*Mx0AZ#?V9S;2cAmMke+)ljYZ z-~7OkLHOm3EBeZI;J311@)QPlp56k1&jwd}-zb$ZRu5t~iof;l6FdItlHDrSp!k=@ zn}L*MfK9ulPKC2zwD#LzkoFSpc&dV;U>fQx^^#QohRev_cWl>S*N!rRCQP(B^#35z-HSo&f-W+S_zi(TVJkFzI^e9qKoyy>R)n3j@ygDkHby zGO-&g!#{m~d1z%LrmL2iY}5I14lt*u2dTh;k0qwE`j_^b!SD!J%JyMhl(&%dw_*15 zVA2g_BM5JO_sLydL4JaGjUW^QVT6HY1NKDS zf5dYOLya4&!#~B`j1mwD7|HEh z1;GZ+SbE@VBUmx(2u~418)&ut6LmLkhS85daB|1*<08$#0@(|SOYdw%@_nUj))qui zkxY<_a|F@3pUeg-h#&|U80xpiYwq)(mLI6yS{vP+PLh^%tq3&Y(I3;i#{RG_d#&vE zdMW#QTOgYyP+OZxq7>)?(XEN_M3k$&woF;C~lL1RBEi$90c; z+={o(>G`pV%&Q85ZHqdIRI^03N)dz7pW7({5->|8oS3XPL&d-O!DBnVg9R`H3uuq7 zZobPZcyDzKqioqWsW8&^1=0kO6oHU2hE@()4KLdE6sP}jkx)NA5;WySh`^X*`cD7RU@N zu-#H0KK`7ZrF~u)U03euv0EfE0Me)a6j8LGq8L%Vf!_YIQR*$`EDtY#e71M!RM^}x zDI=br2vVAW`DYR1j>g!1k1Y%=36!y^Y>=gmetny+PxrbeLKrZ63OF%CeiX<5_~BDK z(}sPQUH~mR>xJ9aS4j$mi>r;0)`qFMuvZPBt7OHDyy%av4k!zQ~h zzRR6DCIMsqBG6;5E;>p=dOpr_o`~_pK0V}b`!pYtVK_E2 zO9$W!fg`6UyhgoIJ?uCB?C+Kadw)HQoAI-Dov15CQX2q7~ggb={^bR`;}sw*$_Po50jAMf*PyKZlc9E{VWKb3qFphxHWSKpB9 zf7EizdAeg+D+l{}X=z{CvKR;^r&`Su6enLmPqc*aN%N zgN7eqs#cFGbvO20UwA4$RF%=8sn|b05(lRzq(5C#p;wFIU{rc;$*`@wVc5&ee6i24 z%L7Jc>7e1PDO>jD3>jBsG8t7a70kX;!OCYdh-;13Tz}+xfQH2LE5S5-`@)^aU>Yzo zS)8cX+*%ZV^@}4rKLtQ(1fT;ih5#syY~8UeV0?P%)<0b0IL}^@D`w-s2c+yESs&q? z61MuL0fJ!WbFd0|82K#Nvf+9jd_P3f4?;Ka<2aNQOCr#Dshk{A(Po8TSFf$pPYSz747~KA=BRk*a0r4D& zmk(D2v|!|?3&JSEu|7F?<=+%-`;kM1o-79uIF_A}PqRe6RvfyYU6bog1BTfk@ztv63_3Rujch3>k!welP+orF{Spk54`PG0g{G7XSpW3<`u z>tVS24=VS)aXbk86v9(Q&@BNN>4c|?q5#|a*x;4FTC$vHFDn#t6hu%m2Boz5Y5jt< zFF+6XTl2gRrDg->^gaOtEinqm#_2PW9|iyY$D{Xua1vpdPImf!7wQ1>B3`>6LelNc z(VtwKSz<}4t}8fMlSqK2nyn7d=}$%w&N-fVzV^HpFn8$7x}D(j{YrCgTET}b8*G{_ z@~7h9d%rol`!fwlsn^`R_PLt^m@E0(WB==p?bza!0u`%m8QV53!-7h*t2zSFF)>0w z8rfRGXo*Py&LD+Q4f!b(Knmx~0+N8RZ3JMPcI*CV?ETGejqUwC3Gh6L<*o}rGas+n zPC2H*UGDgOWy8L&z{ZnU2qSAbqP^f!6WRKxPZa@@g1N9zE;yry6!LYztdS2PAS@fT zI8@_)!#@yKf8oz3AN=Y963z?V1WwCu?V{R+FGu zLl|^XuOT==)`A0Ppb>~J8|X6uOcM|W#>1vR9r~wkX`FiJck9P@=?YI8Qh7exmr4LM zpXZHBKe)@CxOt;lEGSkRO~X3#N9{$G^Gp5E_!kQLNgXZu+Nd``rUj2BM*XHg8hSVW z>BPOCIuzBX=g=ilT7L?5yuu(0JM-qU&yz`E)6`du=c|x!+KQSm=S{M7{Jf}n|RXDLkskU z`C&bWzzO0(Kt1+VGY+DGw`&F%5W@fvyzBqp zoD_h-beWXY4&~rz?d+Dy!w)vA5M$dq2n}{v0#jNJt>=pmgeC_=>7q3d)?xjR5}M7Q zTkZ!>;fK#VSprvtU>&9#)<&Gh=dA|`@K`v6AFqM52tKv|00u9$KA->KH6X45i{K&% z;4gy^yb!)1fgl1m{b&LB900006VoOIv0RI600RN!9r;`8x1<^@F zK~zY`#Z_rcR96(HwWRKf62dw#FfcH0o%e=enT0{1Rs)4PqKF%)afxD0TbF7;ZEd2q z+6D^+B(cRE-dY>83j;6rlq>XTI@pNOAhHS6$mupKXVXW{Wsw=!nr++msMuajSvaK<0q3Ln* zR%nS|3N35qLer`laChERxII0v`?fydMP2j<(6lnrJZp(x25pGjuyTQ^Oi4bz=I7xs zq;bho;5T;YNsW2kJjXNG;}ND~mYK73SKTXf4-rLc`op zc(4eCeZ2v&_Ns!oc}F67|BZl)Jdtocd`f5Ymm8pQb~rRfhe7kYIH+4P&vcn1YA;Hq zV_x5o?mg6Beu*QEw?7K%!5XZ+7B;!_GAsMyHS-G;WmO<&gvPa>Lj7z#RELE?na=-3 zLv%R&v3V`rjGESYo~80LBO`~saper5E@a7$>abv_pQ8utQ7C8H^I3L$AL%SfE-3mi zL}-Xx1~s90;Q#4sq9N=%NkBWeMYd(Qd^8x9a`i4iO)br|?7`U$0z*&|zW=ZK~ zuVz^iMt;Kh(*r=Q=N z6%FNn{*XiS#zP*|ih<(8Zd62;C)-i3QA70%J(Nt-_hfo94-HZ^h?B-eAmjZPVS1P3L|x=bl6l&k!qQm==?;3?e)C3Iz~JwFo9 z54cgOXDGf0dz6Mo0OI!_k-?S8El>wTsh<|kQylDdWgcc)y!lA(b7c%!Qh7(2(hn-a z!r{15*STNJ z=oM?#e=;mp9~l@MaCx zVvk)S`MNjW#!W7|;XCZPDucVa`y`=*Y_Sr4bx}Z)1J|+Bo@?D|&+OT3ORwH+%dFjQ z#~Kh<$Z+DiPKXs|F4pXKSHIX{$5kW_^|3?Ca_&TTuWfeRlQd_wDa&04Sz>?468XX} zPCk(C=ncvCitZE#g$dV(P!G?{9K=m?R&{T)<=W<0i>26Wpz%8hqYx${I0TNi4cKJE zHEg%@?aC0LT{#DU!AT1SM-3Pp)GvW+)Wfq3Q2=bWS9Wc(;p+p&*lDmwuh*zvZ;N*a z1|Uf6EJrGqPauAbw^np+u~ByIwAI27wgHf07ib2qciL*;D;wX=1Z#y6aZ{}=NAg%Z zR6ySmA>ePmbuURwSWfhg9qXC!`FO5)y_Mq8`U&19jCH8~Y`nZEW~^7d)N-5xb9*(` zy&jepZ?W);hHn=BnU6*ohhWuPNkl$k5?k@RrmuquAq?u|swNtZ9F<0I@-;;A%=E;6-)3x`Ef6c1LBu->iVW`5M zeDm@8DV7-PEFsn=)m<{~V3i?A(#^neEHNsU5M~_9k%0JrlnT%nkKFbI>uc*s2>~D^ zA(Y)g65z7mAt}-5$b7>;Z1F6JgzL$k7gG4vngM~gK6{q0e)yPGK((sligkLMpJwD1 zx}Oc-9uQ(xu)Zp^PwEkSN82M)m539NNC;dGJFZJvb!hBtASX3v3VWPklMsnnJ>|du zI)+n^J&z8Q0O*T@lRbRD^*xdjA|a)QAlFHRoZIW%mdmcgNp1d)u!)493LAL&XIhUr z{kRLb@zPrWKmsT&U}#w07R)x|+ry{bCMoPgq69#XUT)UQ7U&l&qEvv@+jp7udR&wW zFn98-fA$YRmdK$p1I#yv7nprPwv`HS^tBB@=%}6n3d&o+kqXfT`40k=J-|@V60TmQ zL<1``z)%oR7Z4=mIixQ7s@Jtl|8_`2^Z>D_WSz; zB&1RSmag;xa`)(4|L3rOF3tO!j3qolDQg;vtZETY^(^@(M zDW#e~c?}#CIhk=+=Cc90-EAS4JAIStTwfMJ!$BZIqA!`s<=zA3EKL{t5sR`3RG%eK zcd%^gIg!$gd7uP9MrK~}rH;9vN2a^n?l-F^xvgvhhewbt#eH*gK{x4Wle2@wG))LB za0o1W0A+f04~>2H1)*k|#vRL_vI!ip|BIkX9X-7zi>1t`I|xEArnAxfzbmOMf|QfF z>3cw}viwKq4q!Yxgi!fp&~glg5fDOc`gWqtH3k?CNtn4T$xjm?>UzQ~jdA57DnJQ< zj`H8q{|&b}xnSUG7aAWk!{oA=Apvq-A~CKH#gJzk?Is3X1eE{?LZ$XrAcPvC@l(Qy zGjkh;xhIW}3F0}3yZeo%`@j-da32CleznRlKu22zxancmXCuz%AB1X7Xqf{xF8@S^ zCxNr?M~Vs%!~+756Gvn}CYJ>qp6(}6V;0m#&miOoG&h@QaNUDkOgnZ%I}ZPs@y8Ey zXsH8Wa&YY>LpKiE^R@ANy#X@$*$`cU6gqQHw?_?d!X%XUe)C=b!Ra1qO`E{--$Wpy zDB6gDlm~P5Gd=O&gK+JAnbP?5U;j@xy!J2$mLdQQUCBU*FTS#cQ1thPIEXAaLmy492CB$KbI zyN`7A`~KhY({7yx?lyL(oB`soIE_t>VE=qwvFpbiykweyn#$y()4t#=QTQo9YikRO z-f#~EImK8y{o{CVxq@PBy@CiXdLCFAxP5V~T*w|?8KVS8Im*h2ZQ@`N+68I#* zl|x7K!8^W6D3sj|^3_AOk9@FYEzvrjs^1E#7z_xWTRjX0gSd5yVgPmPjTlh1gd5Mz zAx0B)#9N7`qCN;3oB&NPx~yy*Hx9i$<9mF@XERDL_Pw}`eYI5pAk>EvX3~xy^U5VD zfVaP$(CN!%jUaad+&pR~^Jjbm1GVzZkLyy(fz8;?8;c+#;%l=Gbp02mL! zDhe1>LB+UbkP?YouHLI+x&-19ABmmEXc7SseDD$I=Rf_4+;9;^IsHJ>>q3%^gJa9A z=z*~0*iLCkvKTjHCXN#Z;N`k!*jTj&1%Rj#Gi%pUp1hK8+1(owZ(TZb}c&~!!)oC?5&=y_Id{tF$E3jhe*TeZx5 zr$=2CJ8cO!spISb@%edS5!Y!=E|&0W^acUM>28;l(4FR52TXcp}D{ZGWS&=?p0> zuU=-}322WJ0Kk+lgyswS5a8tJ6!MAr-=eH=AOH>R$2ojEw052)p%<|b5N{$wCqEEfgxYiv=^9+7_@ZAa%^S>&D;5xPvQVRJ*t49Y z$6o{hWM5}Na;BXL>{$Y^BZIF3-v#JjI)snS{sy@@`Jiy@TrH>0zi0_Zz_#H6c-wHn z-|6#;A+1?RXv`fkL=$ZQh@=zV?Rz6LIzTs~Kd?Vw-N5ZMzW%Dk0BSAYJDcYbNQ!L5 zMm=a+bI{g#me$x=Hzz@)i?6Lm=sr9|LjdV&%QFf=m9S*HkzbrU2ozpAUCV|YYe50! zf`rVpsvlAd(BlPg(?`h4Es-Zc-hewioWbmAAGF7-o~qwQduLN1`GAdXH`P^#S1bl& z5;R3m(2;1f#QRCNPnlhy`_WIjt$WkjRj1(3iwYA*%w=fN)u_VRmXoYp{|}PMB!E$s zc{P>EwY}=|0w#Z+awp5#g>o&xZIj={l(Dy>Kr9*M(CLkICL;i8;?t^EO_f@7+G;6phV)W)YfexX<|O|J?*_E-Prn$#CaMzj#)-Te8dO3 z0Eozc-2p7CelY|$1K#m|Me$f}9C8}~@nnn@8~#FLQv(1ff2*!E@9Wi{7&7$>Ob2Hp zkP{At`OxgIGPM5{0JL<}@l3;Z{G$LxE%}I@GA5E}p)qm{6@rO(lL4g5f4d6+3gBn!;KAVGPb7;N5G@M_VozTSVZ5Q4`4 zdEsJaR4gJVRDc3Cwd>h;Xg4Vwcfw}k&hOLsn)%G2Xe^leNgwkAfD$uN>e~;KB!SrI7oQ7&h-7pD`7aCugGl$;y)O@8$zs}w1r%iu z0N{lahgiSW_VLA+8ZunSn?1Ns4YAQ>D$37-7}G;{Qe3bzcI%beS>LuSJ0P#n?t;0Vg%seZYdHkPw zm}l!p6pdxVfLj5$7?1McV}GK#sR;mtKUFU^9|HP5H*oqAMjOYe21)@I-tj4}9X=if z+GEYso>}is@77&7Ox$!>vI8UE>kI(FdFV$CszoZ(Cw@^%~vVT@tz z)_-#B*vkMYvc0t+`IcwDL99;zDNO!S_^pmHj{xDUa26k&_az3GRRBt3$8q+YUQKiK zBshM;gUJtY0b6G4Z8n1gWQczM!jA3nhf0_>Y#~{pJW$wv;4$_ec#;%el#rQR^#fV} z`UH?RM-ciD=pO)z3(ENL{4Z0KUkVuZ)<4X1joa{Bzc}3{-&f~z0U;PZvLSGK*S>}& zhp9ssQV=dfQJy*aBpbFoMhfR7`5)x}n8N^l0tlQVaDIaFIe@_fhV%Zr?*TDHldT*$ z^BAYvpYyl-ubTFYhM-|$FoK7EN?`O04z~=PN59<5065inlof0LNzxdAxDn^JT}u<2 z`;LZXKy|)ZGBqMsfXqJAc#1XK{>rV>=YhZtgKniW(N6QlSFi*I6HajdAjAAX`jgM^ zGw&Es1VI^H{(Ac7x#V*`(!{#;%e%-2;WOPKzwdbXH!xWRx(GM~@chw3Y~S}70OEwW zW$0`Qv&z!w5CMGA9-Ov9@jL|g;Yd)OE%!DxINM)?KvdTcJ#M}LK%W4*kLsn=31&7B0oYRWI49~3 zgFsFA6AFrs)YSCvi-Ug`5D#9J@eBtA=b{LxSFNWy)DxS{{u6ogAa;AF!QHg8=|3UN{M zwwh%e1?UsNf4ey_%LIM{(B6KYb(`)Zk&FW{s(c1R3rFIIB@GKp9)Y6;0lx!y+yUR$ zjxKwHJKG0vuDyXZk3NVo3INC_sw&w=4}n7uK(y6-7IY&(eZy(i?_2{42=07)Y0eM? zfDBH6koN2+-}mr!9xW~}yqOUN;{k}qBCLGmJ~}%u0)X=U>Sf74@;{3{0qp-h@kFP- z4R{9N#UszM`_NVZ90_yNpxN#=>tHJgF2s|6r8RLI0Z^9egS;D^#ZX!`7)|4R$P z<%}=C!-`|`u63L^ev%Xp6{s%e8<;);{4ZihCC41hJfIWciA`&$J9`|!9g^KJple75 z0P5e$W0Q&{98Fu(S7R4;Y+1JCabwwB!jcWZ-e z8kP3~npDH;Cm!T{TQdLy@~&WH*-QvN){XiK(}-6B9_ltR*O$*GH(U(BvAXBkymb>P zbRuT1J+t2fA@n%deTCmp<=+6xO3PU==fmXX<|DwfEn7Kx;UFTU4e2EF4kGYFVQlGb z49OdbD(1!IncO{ z#?GU!zEX(I6WtC>)KCm&@Y^Db_rYq@cOB5;ihp@5g?juXII0&QoD!+gy8505G;zb1~Re#I|)e^ zC_J`v1y9x10)WW=&iv#Idu+RhL+AyVyo8aC2iIIa1`%kDHL$1QAq?^K z=qFtWUC0R+@VfpB$PE<%u;=M5Y}>w-6zWXEOtic|G*`ZLFch7l0 zLk0{7fioR1aj5AL5Dnf9B-lx%Ndw+NN%mj>j-Gy=6>IJX1t6-%%&hqld+9|GdJ(35 zA@l)7{{&EwU&NyMAEvmV1c0M$dpO)$ooPRyyRYdQTI>18gMTC*j{_(w@2aj$ zK145r(91CO9%m`S7XSwKAH=(6e~|2~90aIseuBElb0FY99(GO1RIV<59RL?PTlvR| z-_zdK4uA+>u3Bn-NH2s#FGF>q`7-EgfU`{vJhEvy#uyYB*Y7RvDxRu>!A|%L%DtAW zQsl>zG1jcV&yo-Py$6xsCjh>IF$rA=vIpSh6ECr2&jwHsb+}=`-Q1$ zw}Rs4*Y8|K-RXJ&K&p#7%}40P5PB)5e~uw0%h?T70K9qT9ZVQG5x~7Oa990(I1*yY zkcI9=O#)OO+DOgrDpEMEY9`fGa<)$ZnQsF74e*gm-Ax?FVg8*9sTh1UBH+j2Q?;yn zbQL`SFQ}TCR+yK-xquJ$gr>w8!`6eVnfJ!`QCJ$EfU2SX!ePdb z8&6AF{NLHT3mn_Fn~CE;pZhU0glPhaFe3=eAUx1aBFxMn2y^=%ZY@b$>8po*rRPSM zy+l=K^LE+oschiJ0Fe*~0zfDMbix7PdIXJtpZxU4zV+R&fyt9c_h!(m{`d9X`S$mE zChTMp0zdracYXio zUt%zv(>nq8`50~tjC;Jo7y#4?0|-FG3QVjJVJHOI4Fq+Nks#dX5k(uJEGlgPDu8=@ zMJS}B)+qu@go;@GK>$gfp)CMu0)qemGZbgT+yKVznn77(5C%#Eh|t7Q3nBp_c4HC* zh?8h?3IcW`aN@^bh?Cr-t`$TDw%{cH9uq4f5%kCfPzdDwe>eyNU_ix;jhUesDg#o( zuw|rxm5B-iDih(JJP4x5LGDUw6)QHdEwCw^f{86+41mCJ{i(-Eeuy}+AQX|{aSLF( zv#psMsKAIu69WK*!4yvK-eo9&Y=8nY2N@H4XLmJZ-R&CLO|vR(vbNZm6e4jw0Fq^| zCxEj+0HHvbh8ds%VGJkvkpvr15jk6~^%Pdwo^Zf*=PLt>b+)<^@cZF)-sBTNVYQ5dv9FhYQ00)zri%r)7; zS=(?ypo?`uL;wYPdOtzd;D*r4DS&YiAq?7eH_P3)8|HdmFT+6Y@x=hhVuC=8CKJK{ zg@7<62*psN0MP&ef^Y&wIkDhriHA5-C_u@>Q3eBm9@SaE8~*ui{`Vi=VjhsnJXD); z=D}Po84UvgGXMxM7YxBeaKM5HalQ5d;^BIeuV-vX)L>l1fBfC6@oLX6E<`W@n6t+T zo_&`&&&4t1I_f%qdiT(Xp8wXj=P!Uq7C{-9QNRoW8pOZ^3I;AM-N$p>fL;(41Q0wA z+t_D#Ox)+c@+n{Z+Go8IFH+Q_6~IsMFR**(m3Z-Ef8(c*K>)$-eCT%Tz13g<$^gg! zaE*7_bJ2IX{yL9w6}iSo*RU@7F7qK=_YuI1>pmCw(Ld&M-}(66htc`-ay}C{&+&)n z-wW3{F8;zijj#b-{0-1`{xJT$dar-HoC4sQgd2X_z8ULK48kyw|NrR68#=m3SKR`w zy^w}3$Vak}p+LCb=cZHh0R#eup^d-vTl~Mzt6*fJzugfF^92O4`YQ2!Z_j7p!hCOf zt{#9e+ruCrIBqV0-1tFb07Ax2lUIez(HP`jF&KhxyXfz^&(A$qc>sfeBEP>f8RSbn zFZ&7r3WR749SxIxKFk;AogjzJmu7c15SM*#K8Jv}1FQldWJ8<5~V)W!n@+}zw;TwI)BASnq{B_JUou&15lU^Cm= z3hp&k-20o^545r$XyaO3$Z@EJYefm?p*HS=ZCtC%IM-EhY_8)3vbWW79%=^(9&G12 z&;}IYJlM*4pq2Ab2lv5N4xq^4Zs8OCQb09_yG4%l0+HykUXkMyrA|#%Jv~+VU>opCXZEq~MyRp*o<}$OJtDJ7G za=y9B<8p@I9u@R&a7W|=KQ)l|JS_*zwRyi|NsBgqMC+6cQE|5fu}cl982HP*Bozarf{{P0J|ipE7mfinW`zpTG3r z;ge_YKYsr5Fwb$x-0w{Xdo+5{su!Jatb(cyVj%{R8WB7xT6*h)YyvJL$;yV&%@eb2l>ZT?yEA zHt(Lk@%z1@ITlv?^}c7N7VYKx=AXN;`1x^`3DX$%A7JCRsI&dYIODHx>BV&hpLYms zDri0SfQ`#1Dt+ehr(G33q3KK-A2hZD)z3k85pUKwCM1p+0w0Hwk_2Tzm`V!o$9LO4MZf2zXdFG8Pcg~)<6C;=; w6qvS1=v|&zFc%-|9;S|&5)C_V{<*%7k+ZR1X^D0&D627ey85}Sb4q9e0B}rzRsaA1 diff --git a/launcher/icons/mod-enabled.png b/launcher/icons/mod-enabled.png index 40204a56f4f2a67fae6c199ac8ac30be8dea745f..0089197c205e2e73867083514b58000d8a3b3388 100644 GIT binary patch literal 5840 zcmV;>7BA_EP)7XO>t0_dTSl`}EaJ)$ObE zullWK`}?Z;e`Zo46A=*+5fKp)5fKp)5fKp)5qa^VHh=7`Wrvk@<=x6{#7lzZT}p5H zVR?U9r{&Y^)ft&(BnF^)+8X=WRd3*6tMkG2S>? ztg7tw?3ERf+FJIe(hjAcKv7mA1=n0<9Bc`3PS) z@~lQYJJEd855Ql?vv$ZgkuNimmuJ*=c?W@3-F4qZ_p!@SWX5zqj&_>G;kz;r5@GNC>2Sre{(lhKbdU4gv07aJ$b48kQlOpBxrKqf zj)}Z9DQ=POC~lFVb@fAY5j@wX6FAohM>K<^&7i}OLx*A?J>E*%p4C*yhD-1HE0wK) z<{K2XD6^S}`6+Id{?3=Nt?OfOM5?LqRvp)wGE7HPpOG_`O9#QmU1K!j-GPSdzxzxF z;5sH^ZdTI=eTtgpAp))2Pp^jmT#JtHY&E7LsbtG@azyj#AXM$qc;*m>j=;P!f% zh`A|hkvH?@?>qJdcw+TbRFjS~T0jMFe!-m4B04lx`Z*f4*L)4!?z2q9yr|9ZeQ#lt z>?hEA$evEcHR^cI?8jtyQvx=Ft~Jb?2<(R1k^=p1X@H5Cm!c+RH(!4BRo{m9OdXX} zuQL_N#6);w+$JOG@SZi!J95WwxbjJ}RKY~dNnySG@xn&=0)bY~R59oP=s2U>F&^5G z5La}UVcvkV7K)gOvJ30e)+ov4f4|jGm4s0VE1f;CswU99Vx+Ba9u)N(LIKF4-anv z?c>GrYm<_hh&jn`knSSTy8OO>g5EXLam5Z`G`NneiQ7at+c+<3!`|bc2fsV7K`Le< z=A@v(GAqAcf|j-QBNz|trh+PTCPFzF39L@Q8aSi-4D)U|wHUOI=g4f6-yxbYAu4^= zEw@1$%A*^vb@PcOpl7F!BeIK%T$PZ?P(DA8{%se^+CK_@cYd8^DHAa#d391cf!2<$ z&tfXP56ab^3_bltY^RciJV&L0)f_J8mXF@6OrsH`FnK3pC*`*SD%7DX8|UuAgz%=1_r!K5;7iC4fF0ESP9z4 zi)B?>6lOw1z+RVKE!|C^b^NYBQ$ag)CPL*@QY{uzw; zt)Q1@odM4(^tuRmlKOuHsnqgkgbSCIc5A?f9mHaDaPDC;)EVj%F3$*qh`zpQEmm2iBm!iitFK)f= z#dN)Dm{)(z_rdSZs*tW==0qgRCVeuaLb^zY09yACufs^7L}$>u8K+%y6Eft>;OEhf z)yU-bk|)wClrJ)KB9d_^>9UMN7HHL9^CJxVi}iekIPIK|Q_eYY>v1jR=aC}pJ@Q59 zcN3eXf|(PM^n=n5(hpglCYX^`so=z9Diu_y)9+bJWzJ5>kT=sX@0L^ZK>PG6EYU3o zB$=5L@j;(-o8>_Qt*+aC3%kESXULb0lg`;>R@{2s%MJ4ey*Vgt`2_gg^a_y6%!x>< zEong--E^(I+K-^enMsA`>-4ym;e_K~37AD?8|Phi-=DzmCR3};`=F2bL5^t$lg85y zTA+31{ePo^a&-ngsZ``Y6VmHmX_(jJ+=9HC4}#lGlIAmWB0@Jjmq5$f{7Lk=GeIxU zIwu_q@YwV};&x(s79AerytbQuW+O?W)7Me!VWVtGc(v>W;kZ%OZ{K}baHnGtk{mNo$q1Eq9iDk#^wn@a#K*xd#R3Ms^$p9WFE z%b}G2a!`@E`pQ*eFPKu-HR6&Fa;&qJ(vhiHo>j$AN?xYe2|Fm)$Pdaf$d*-yyW+4GWD6em`qAYVgTTNd zQ}D`Nuy^Cfel&e)E#iG6o(RPe<+54%ntzt1W@v83I_&3E%EZ>6rH=~CHprH!`PHf5 zg*Or&U<2znVxFpY^wkf|s6xy(`ZqP{iEILIGe0a912j z0hxwpK$h`WKyTn*fmzmRALDoJ;CBii&x|E?aGm$T!x~>((8a^(0+LxoPyholUbMG( zZ(G?~Tx9FuK%K95$E5xZ=w0|{8M{MrEf%Ge#6DSr&p+^S?7cFC6@V?+`bX3Gr~T~W z$_p>S-suNk=yWGx4g9jK9TZ2APmW#{-TzZSMc{E@wo{W**_kqoJl=omnosH4%gF*4 zo(`n*Px=-ajFZ~S+0e-(>vR zKV2VHvRl9QDg6A?)^7kfdefDzB0;uXe(pi%kW4#3_m2|n9lSP7Hs`&aTOx}#dtdVxG(5a zRImdKme`v>@yqIo^G!E$6-SX@hCbRa-5{R4U9Bnq`S?Oyd@_b|H#cLi%gHeE*=?gz zjDp>+yq};fCpvY{Lx}Ifli_scQE$7r{A`q9Z_AlpvU&c-KjjCyV|0F|-Ubu;8$Zc} z6%FX((=l}A`8X--Pxhq145v30!Y}>PwVuWG&~f)<2p~Kk5T|7Zq&( zLwI|b|7ePyUtLz@p^77DVzN_3pETo@Z<;~2gwLr?r|x^8BgVXyy#<3PVs_x%jWfzotGTpaq8E7 zQ;n1S1Ow8YXm9=?R{ihAiMy^8zr2Bs4FS7v71=`{-*n?8Z*%SOE_@uge!J7j2R-fL z?4zN)Jv4wj1!q?h=Hr)c9icdad{gu}KB)%rtUKNn3ouIH+~eW6zIsVtWB)yGcN@W$ z4G(>i)z6h8$~(=N!P|;iP#eh}Da3I4VL!W)f9gSRj2G?A+1^|-59LJlLs9#j85F|fd%W0LU5J7hq2*Qcbp32+fI5^d0HsvI1i{9r$C7)zt2|qS|Sp$hrPdb6ZL~KO`F%{NzG&s?d>J!_eIxwxA%~==i;!bnISt9_$AF@w&S(hH>(~ zE1uAO_Ld?r&P+~z^G~B9#!vCSe-;{pF5H_xQ1Er?;b0bzU7UU>&UyQVUb2|W|3e>k z8lRkG9GIM}lP#!hOq$&XyYV3Tz3J%PZf^pw_o6coU8G}AgQW-BG5gGqj9*Ml)VoOw zAXz`izdv(BW6=+MAG_O~#ZqK2H)+hV3u}?EMoC(xQr1nw#a^T z1Pk>Ju$XK&7%H{F*oKY@&aV8XBKRkg9j(}i6$Sr3c0E3LbC4v){wxN&IEC)#?X5o6 zQ5NHG*v_exXH7~p2B8361F|J;?PoXzkKn<=4y40(x)ud=RDY>0#)0btXlh<<=2K3h zw!tsX`hE806a4#4{`L7gS_(E<(ZR1hVEgYQ&iU>zTneiSu}w4oe6FlI-zdv_>hZES24gTQTce-i)SgR&~q zvD;#t@MTYopete&?d9!iDU0cm3qIQ@=LbJ)y-A5W*%FXm2~Y9*v1AqE1QzD-oo;jp z3uPx5-yOTbU}jIs$|KI?lVW9Yycf$3wBv2S{y@9qJ9@W|VDI3~0pyqJB>GR%hbmBc z-~I=nv&fdb-OaIxLj;c8=}iZ3buI?jLib}frEI^@gF>*~a&ZYn%&CDx-e7(_64}kJ zxDMUwDvc*&{bz#j35muT$9UeKXze#KK_^@0?P$stRtC1nUUcAQr(yxNU~`bv&w=ax zXvUIyHgSopJJDGfcjR_od*i{_K7zd+mwFJIg!lb=LXzHEaRiNxv(%b^N!j9;R*}}9 z>WD5KDCIB~dH>DMpwkC);8r*6ECb}e?hK^a+nS==SX_mfwy3Ub3=-MJ&N#YA?M+`= zSMWVPQCqJ#lE%mDmnX#QR0vFT&bDSqHg2UP{C5%D=uG==bo^kLokQq8*p;&CXnS0P zEB=3MlatsZ-)_SD4&Lf%cMLNBYfp4w{&@b%nnrOXO^nxiq6l6C;)%oK)qU4{LS@H}kJCv;#H{MH{Zcn9OkWx3;I7411h6I87bxZ!4&Lf5*jv1>rDQFPUrtU_ zD=3btaWgcxaWnPb1LE;bsff?nopDRlTLu!)o%URFE)I|sT$4o~CE**pTNlCJzH7b6 zKdll8>ky|0D2}eN)2#K!#c6lP&D4m8bpiVZ@PQk>r0l`fr1E7I7QkifbnQ=o zc>HiKSaqy5lHFAX64jA*=jgC_rkD0DL1;jHh z&Y-zFo1inhyn#-%J-;1jTUI~;w3o&jHNU1XztPjw)ru(;LF^CoG1IgofMmoit%t>B z+kPhr9clZOcC_tEo3a23po0+Ol7lT|^ZM(AssH~+ET&vsl&_7Rrl*a@;>d`^hclZl z;QERMmVhE?OWQ8D{-|uf+*XY3N(Tzgsv^#5x|*zrGBtXN>N$F<_7^}reyNpc)$x`{ zb_XfjuoG-WB0ds`!C8nYciU$q&PD%)SDf}kMJ`jLr(2qhnyNhq#4~QDLGyNhfsSi0 zWh=UH%cWMO&elt9gjhCTXp7JFok*OA>Z6!?yT-+S-#RK*JuzyEMm(&G5?0isEf?Eh z@#Sp3*b1~PEu=9dudXk|4(@fqUq&gW-YvFJUa{KjkytnxQS)lhhI2^trPfk5U2Fwf zmNX~;(f69uEpU%-Na9xeD@Bv3Q8C)&k+Is}0rB|aT(IJJQydUmN!fUzC1_ESNc~R9 zt3_hG>Iua@nevKNov|DI6cEqYnO2+&KBo;x_M2%@LWsT=9cqkD*ZDaA?HOaVQ0$i} zoSv(C#ab?T#i+zH3X7b$x-M-v-~6K!l3j(w7_}A3hs#voK;>I(G1;QZh+R;f)}Cof z>(4d&D9qZ?NEX*$Mn|hPl;V>qPn-)pqt$-^;$dGsUv{i9twTaeleK4?l6P`NAs)n< zpcKDMc}810c}8nLmleT(KQGwxDN9PJk+Qy?n0&-%KJ+O;xrb@hJ)*RHk0_OR*!G*c zzAmjf)1<^%ak4Q!-7|z3+@rNgim8&73;wpxBg(RcEw~K!W6mp2H>TA{R7o*yX)T%W zyXHfm($iPmqts~kNcG=qXY7`Y5JKS8m~IU$;p0 zx3VIbFw;u&_co$cr@kmw!e>__(VuoqG4*le8TrHdZV~DoKs>Bd(>KugtFHm^1Z7vIB}YF+A$(>J*h%UNHo;$pMQPO(Q)NePVVa9;nEEF`JmY6N(Y$>P zX&Dk)6qX+Ul*ZvqA=G7+ zOqERy_5XqH5^6c(5~>mhlBdzs#WiTju}|Jf-l0aUXha(!+IYoO+5htCh)^{Rg+MYw za;wmyqmABL08#U+$;RGbww3ZBQ|MUF5h0ep0OFaLV8ywh0WC%$@XX!YfSvS77#CWh zmr}lDYIvBX8It!L5D%Ug;9O9L79D9=h``KBB)-4Gex-cMl#8FW((qu*SwK84VHS#8 zRg)GX@r>m4wS@P8e+>;%KUd1HOtIhN8y=!AVhNQoex{Ws#9Ptns^oQbvEmpqg--Sv z7G(K5p!Z>TkmWaQ2T>eHrbYy+9g*Ch0eT1j9ulDTRUA*I2K#B%hXz{m0lk6W3=62> zrZ}?9+r(<$85&q2a#(0tFiqx|hd}<3erfn=qt&NE_Y22jAp4`vw+1+!_%=off)+BAv_0d24 zABLIve$4m(7~ua}r%1U1FMM=|PJOY{0I3sPygpr3``M8vkMQC?Ef*lw=u2Cw>l&VW zxTCVZx~98kX>z=)r)}4N0@!zG=LSZ|Tf3WEjewCsNBeHQqkT^eW%#CeMkxoN5I51% z(4_cv0o(Z#0AOV;p;Gd5*)MqhaNA~8)t=eW*kt6~2~gsLkYW5Va5nEaqO)v(kJ1m? zo0@zeOW?wW#^N|LJmh$u^JUM0Gb3dIx_Vl6=!&+hv96A#b4duHW7(GI`}LA1^ZD0G z&;E0O1W{Gi`@r^X{=A!l<7UA~6@I)hXiLrycE5Pu{M($?(nusgQ?b@pDJ6Pz#&|c8 zIN@DOPH*cY!BFt_+GrKYWG_QuLCh`NxRji5xHR5hskP<{X5;t19j&NH)W$ZxF?UnG z@7WLA;sCJstG!I2^y8h4n}c?K2CnCUkqAx={gUAlZywrzBE2eUtNm^3&=lpBJ@;%g zG?ijF8Qgwucx&Me}#_(mnD-x)f2VdR(x?lsrn8cb)W;Rz0%`O!CgG0i>sa_RSQLyIUSL%$^_ zb3&>Rl48kDA{21RL(L6F+t!+(u5;MVA_(zgEM-c|&W`pR=>PV5nOFt5x}o;LDRbe| z;{(GP$MJ)}hji8im$TSZ87Ap$3Lcl>o{Dq7CvDF8)Box>-QU}?Poc`emMzu(3O|r@ z7eNSxlpMMm!FVd?j84uS>+bA-;zj_r29N?!&wf8Oc-Q@#PS04@V+x~6BoLyGmxYuR zTI#u+$ncFl~X9VsORK!gxPN{LV?L~PqeDd3tlkw}C{ zDT$Pll+I^%BAuNY%za&bckt#}+pS-oci%br`IVmtA%YOXDW!r^DilTGnx+ZMvIGDQ zK#&#wvqIBYEXFwJR0u(f&;l5Q5Ls+WsbGu=(=<7NqA)McgRGOV(q0*9Q4lHZRrMEM WTe#;$n{L(s0000n9V(0lC8VS~h5~|wq%s;21nCk6NC-%$0vpmjl%I4; zs&pgq^8Rsme_cFx&&B7tH;;8SDB#R+001boG*u05BFyQW%b%}!{_Q-<$gDM|@h zaI85>D(fM#5c&c{3KA2JaZzLKe_e$=7^D&#p;4=jIQ{yEPp`%Dwq!c2!};?R#0?TW zgh}}(*{eSk5tWE(10O$CiYDCmKHzR`5W??Ko|^fK$6J;{O#qVuIjUWDQa9|hhPzc_ z))zpkK?)L{>fgp*Auj4ft2fj5J`FkzE$VZwTk#rE9bEospjx2cqrn}QzSQa4Ip8^$@|Vi5*!2w5RbFGCEAY*bl4%^6z5f@(ual@hY45{RRrY5S!^!fPF+L zKOwmDspaQ49BkGRaAlg;zlt?Z89{+&n5Tb^7DrDbFgW1%GgrZu-Ted8hS$RO4>{3c z?CfgY4s_h#EuvsQIbDCpRm(FaP2<|mElD*L4JQ-;%xM-QjEw&Ol}Ot_?>Qv*xa^qzzF;!=J2{zrP=q!p4)Rg8d;DeON~6S0Pz zIpeZb?LUXh+1mI_j$o%7ItjbWq&)ZqOBIKo%U|*TIXOw2c;F)b%a#U%@pQh=su@$Y z>gW&#Tr62N&sYe$tTdMqoiEr!o>6sjzaZ(@Nyr=A`8)f@d>Nb(pX08)%ZAN=swO<+ z(Hc8|Vmn(F8BbtgA{tIoIlY)1-ii?yl^=^9xTEd9`%Ht%g}uHuxX10burX+RYQzJ6 zY6aP^sFU%YcVgrc7R8W$Vct*^Oy`LQ1WgnE8xI@Fn#MFy#qS<^e{ihTZ7QF9@z3F} zwE@@#apJMACpEjYXKMK`_pMpO3kf8ur8&H^=-)HnNq9Ni*{(RqgQ*#4oPJ}yE_Hu)9<JBU{)Ln0q;;5{W~M@zI^=TKLB%2Jc8vnT7D3- zo9@ums8mK}8I8`}S^3-+E=MXedk9OoJF3YL6DsRRv{S`*vfoZ+qoZ(o`Cza^5iXzF zwYe2lOOND9w`vWQD*tmIezktJWoZNkXB5qQ5Xl6z{Z#Gn|oRP=0I*>`?Sw%cU_Y0wx^22 zB87NM@O+KCAbVAtHR)C3WHI2aWGK*10+Futus>izhgUzYiP5?o9HO94SdOZ*J?rztLxxdAFm(s)sgeOS0H8B+9~$~({fR;ofx++@$3+JhS_9tPDp7j+yHh_3n5)5zPXWcUgdv5947nlVIEJUHX|My%KIZRr!Zv1@?0F zzrdc`X5~tCEyw6q4}D1UKXVa4q)w=R6J6OGcjZ5BxgsR(BX8b}Qj3L`04~oe3O)}z zhE_dAkcnU-Jb;`p4NM+bsgSO({z7N~NUa-dVFl26^ORXXwikNdLFpH_*>c|5W~YQn zj9P~88WqsK@DbP5Uv}=$6744k!1P)m!Zgjt05w4P>^uyPl#&72|2S6TvB%+ zf}y!pr#n9ja{>{V=}8T{=&buvF@V3oSPdVLEiK836*C-_IuO7=nD}vf@fl{A#RPfZ z*m(-Q#=&>Vk4=GAw>H1Og0IT)hx_qd{hu6)3ZZd3Y3t^SA@}B zMezeSEu-4$yH@Jo4k38*;LnYfc8xGkN?qzzAu%GG%)nhS{r4|`Cym6QfzX3>HGl%# z%xdfFiuemR5(k;<(+C~$19*$4l?$Np36rdQ5$2xVtuW7PX<`?}6!L)qj_#(c zr09b^`bb=i+NH(ojlAHpUx55BL5vwX1oj`pP1a!YLkBp1~=;#M@DCm)G zrH(Z9*5`((H>60nJh@aTjCk<90aoWP9Dx_&v6Vs@`^uSG`$+5X=hwY>{H&i0)9cZ= zR`R;eO)?u!gL)(lq#?i|kyLi6N_SMW^6BMS1bxm-FEm*`^n+LG06GDT7_6*37{;#@ zNSGq$(YRyozh??|q2Oc0*y3%ffipS-+Cv8f%?GVyG(TgQde(Pk+trd#TP&+>_nZt( zP8|S#0vd+~V*p|JoFQW*v~I)MIHVtgEPj6tL_Iaf}ydI%@s<;z#^&W^u!yQAE96?Ua-4KLop? zzW@rxKySC|3e32IkYv<=4n1bV0RotSau8CO-Hn5bT{&n3 zsuw^3AY*`i1}r)KLNA9ODK*l%{Bf)XG``5PL9p0ZnY@@V98hBc;cxt#X%Z8VK>bfF zJxspc<4NAX!T5gSVmuF&^00KynB1JIv2P!xisZ`G0j=j17hc^Dyk zC&@twu1n0e{Y{%{58+}}4ScHw`qnJ*2w_KVKItRIAGKYL7+UT-b7kAcwDU7=WgbyD+XVrdXjY*9QSdexC5m#9jO@_j8W@PRGea8`G5fRCS^IfMk~G9X zG8Af$CY8ns*`9PAZ=&}_8z3<^aH`q*%en~0UKDRC`=&#OTd3oOl3WJ07$KB-{w;r6 z{hd)7dZeCoD11vvPr5D|3xrSE+>{s=F+qZw?24 zAWbF3#eBF@t{;tteOo^ozttT}dZ_y2J9vglfJ8UyVuKNkZ{4@Xw})*LIaVp7pETJ$A*HLfP_ekS zjY~7uiP?wuMGeE~jRoP9@>3a1ADqX9ZJqnu{AIQ~N}MGom`NW|>(fJ!l5|iC=6L~A zfMS$rM*i!!oLB6``b?;JztC(Yqo&aMcf!6-_ReO`aJf|>bE(hg)^`0|9|Lv}s09=R zH6>>)bdju-RRZei)biRS2WsVEsMjBuH^r3H$~V1RnDm_^qQ4Fqs2}0Nn5Uw3$wwV_ z)88BahvWesyt2bg3|VNB4Fm5baix2-&@zo^?g|$V)mxzA3d6$7Vy2H!7-68^i6Jsr z+eHRJ9T}f02lkIw)EG(Bqc9xbHbv}TeM;M6kq2*5B#?hC8up!7W1Lj8uj=8EvCF%rS2dO>ij}Ov$6XLbs{^^G19e^NI+z*u)#|8pV17~pf;mj*77*a) z{}_+%&0E4bD9-y`LyrS&x)iPlX=yHauI^DSw=BCNAv}>lc_p>&zHi;fA993X^gQlS zh9r)!)z=oX`UNm8N`XdT|8_2PdhfB>2F&kurskH1Fz)zScz z)bGUq>#|qljY_y=&=t@Yb7;s2@lN^PIzL9Vd+eVSLSl*nX*2i(lhEDoqCtQ*{j(~U zLesH+eeWjQ#^&fe(cj*1ed}D&tK*lH)Nj$i)#Tr4k$M1JAEgLv1P4jlkePlikAro` z9$e%}{NwnCrV|GLP5q+;W7XIjaGe9%!0in#qVdl@t%P7q0QOhgfD46zeU+s}E4cNF zZPx0#|2p#E2kzTeaD;t#nd?Aa&(%e0r>eu#dgt}wghVq*kiy|Yv%#(!iX!386t0O1 zFf&Xb|7nooqO*omP})9Ie6?=T)k4?8+pc~bn$7nl!pW|o3S{ecU#pkp6@Y`~jpA6- zO?v0+!g2IjqW3Oz?6tir-v&)iAh8_0K$0WRh-XCcUX9A0QZbLedP5MRIUx=G_AP zuN2EcvPT}UFt7}xgf0r1`> zcHKrExVt#IPl5S$8}-`kR9N`b57V0)lAF}(shB^l+jWlZTXqL{}2HWBpBbB%~jYj8= z&c`cWAXXV;^G{5S|5P@SiK@i^DpHq_u{e{ht2D{}?t{}!ir=ij&6Au8H+qb(|=#exmU&#=>yw>Z_ zjx~k$?a-XNDR3@2N#5Ue=fHSm$z&%u49CTBabZZG2b^K`81a%Xo{+UCGwiOyr{g#jZ+^7Tc9`s81#9na0)d^(H-7KfY81C~~sZc-gza`xThL1%~_*+uJH zB!hhy(LP&5qE4#+b~7euz)b=En0D9u*YW2R6O)w^NXZ}IS+LKikhsC26R&}2Io^p= zl6iJwo#4AYCD*%ZxtR>RP->;ex4Z%gXzs2Fkzbuhs~0r@?gp~@_GblK0oVe&*-nzj zo3|gq`G@DUW@cBDfw*@)!}C{;HS5ph{iyb?uQsKQ+f^_}_kuqclhv4lS2T|67e~xv zM)Ugld8KwI(i|!9#lA34Lm9WZ6k}H^ap>|I#fITtoSOEgC5~2HNme$ zhX{6cW^%r42$+AZFwsDA=F9H_lvb55P76vSNypZBc{B)>Z<*P8*w~bNxv~5V+JQ~KS>F5V6cg?#-$|C(yo#T@bo3Uf z)Usr9CJJL4QNehQlImEYqR+Oz4)S1wfmOBf` zC-<^$|E^?zxx*xxs*q*L*YDSUBpKoB8&bF5`Sv|NP*UH}z_AiRV?n;Az5a9+G}7_*wSSEmjNdq3Au5q!q3Vwr>y~Gybj2%D*BqNF3XdikI|Bm zaA#4IOo+wK3<=Rt;qUJAjH{f#JJ|r+IuH3Ru;0=pOfWjz@`e54d$-8HQq1ds6&E;DQBD%zVGAmu{$&s?;Y*}|TsKurA zbTEUk!D8gM{+5Uzlx<5wR&zHiWy8)SB*K5mIA}@nCBr2Y4Ln$tYZDt(fcE)q5G87C z8valAIZ963BUxfa-4ZHh*t5}8b(}V=8QmwrU022zo zH}5>jfQZvy8PlR@5aY!}i;cC52EEg2jVj48oXZmOsF&8eqs$1!izlNCV0-r~mNl8H z-W5jg3eoYwmrhMNqTHczGO=o7ObPzN!2l9Q`2zIqUHC2-pC}6A)E1EKfT8Z@o_8Yh zz`0*fM*LjSw73ta!`;8>u2=yVE``V^K=DZWQMWIhjna*-6Ahk{1o(OHGOCp8i=TpP z_0j%qPvE>`+Y+$#h!0ZVxsc&iQsn!>Muj3-t{w3J4ka*_Ce#PFPp85a|J(k4W_MWP gjzZmCN~lpx86IFPd%awK^N|Cz)O1xVm2JcR2QPOD7XSbN literal 1341 zcmYjR3p7-D7@x5i?!4~2%vf2m)=G73hj4nVW{lUV5I1-UB5ex=H zbavvp!=0tNw7!5kT-MzQH|#`Tp^I8t&0DORVK8b1 zu7^DBVd?WY;e$_(BteJgh7_ez?q^WoIrlR9`3&C^$%r9C6-1Fsv#58{R5Sm_&14G9 z7bKw2=kCFAY;Y(MOC@7<8ESe=wePlRK!zT}r=BH21uTGo+;6D~2VRRM2f8EKapZdf z3T$`Si-SDnry4u$Pk=3D+0=?0Dm0z;<9rWkL*~b$fCv@Xy4h<%!ob-8Li{Px8J?=b zB#`kws9l((s=;3POW{NS`sFGW5aHM>CyALCRId-NQ7dz)huK6$Q*jg9QlJeR?B=<&zfvxfspCv`YKVaU(d7}&$OA$w3$jfc1k$R8lI=*?~`nKOgKIkVO{6RhxARh{z8xETr37;Q}oF6;4 zFrKt9Ay|@JUy|f4&z7&s>lF)sDHeMai+#$Km&%p#5AWY@Y$!K2K5TAo;*a?D!6$Vl z%H72SgH==4z~QvCw6qZfPau&|ltQ6U=?s>hp1!_;vB@^G?K^i{^LRl){NM{0V=rHc zPt47$t*x(bXl!lk9~>GP9eXuC^?G_nDwEI6%`ZW``xwhBA7d3_ZB3z2u0wn`;-nIuo0j;$-S-j9Nx{S_(*u zYEF6kh{Pjy?5uvn4DWPF0G&rwUJ6sz*I6X%|JXoYBRAXL?m4p zyJ5Z5E7lx_YGX#?j%)G>1Kct~xsiLr8*#BHrv{ Date: Sat, 28 Jan 2023 01:04:41 +0200 Subject: [PATCH 27/79] Added icons to mod action buttons --- launcher/modManager/cmodlistview_moc.cpp | 4 +- launcher/modManager/cmodlistview_moc.ui | 54 +++++++++++++++++++++++- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/launcher/modManager/cmodlistview_moc.cpp b/launcher/modManager/cmodlistview_moc.cpp index a7bcf0101..6ebfad9c8 100644 --- a/launcher/modManager/cmodlistview_moc.cpp +++ b/launcher/modManager/cmodlistview_moc.cpp @@ -71,11 +71,11 @@ void CModListView::setupModsView() else //default //TODO: default high-DPI scaling { ui->allModsView->setColumnWidth(ModFields::NAME, 185); - ui->allModsView->setColumnWidth(ModFields::STATUS_ENABLED, 30); - ui->allModsView->setColumnWidth(ModFields::STATUS_UPDATE, 30); ui->allModsView->setColumnWidth(ModFields::TYPE, 75); ui->allModsView->setColumnWidth(ModFields::VERSION, 60); } + ui->allModsView->setColumnWidth(ModFields::STATUS_ENABLED, 24); + ui->allModsView->setColumnWidth(ModFields::STATUS_UPDATE, 24); ui->allModsView->setUniformRowHeights(true); diff --git a/launcher/modManager/cmodlistview_moc.ui b/launcher/modManager/cmodlistview_moc.ui index d9a893edf..4b8060ed7 100644 --- a/launcher/modManager/cmodlistview_moc.ui +++ b/launcher/modManager/cmodlistview_moc.ui @@ -135,8 +135,8 @@ - 32 - 32 + 24 + 24 @@ -388,6 +388,16 @@ p, li { white-space: pre-wrap; } Uninstall + + + icons:mod-delete.pngicons:mod-delete.png + + + + 20 + 20 + + @@ -413,6 +423,16 @@ p, li { white-space: pre-wrap; } Enable + + + icons:mod-enabled.pngicons:mod-enabled.png + + + + 20 + 20 + + @@ -438,6 +458,16 @@ p, li { white-space: pre-wrap; } Disable + + + icons:mod-disabled.pngicons:mod-disabled.png + + + + 20 + 20 + + @@ -463,6 +493,16 @@ p, li { white-space: pre-wrap; } Update + + + icons:mod-update.pngicons:mod-update.png + + + + 20 + 20 + + @@ -488,6 +528,16 @@ p, li { white-space: pre-wrap; } Install + + + icons:mod-download.pngicons:mod-download.png + + + + 20 + 20 + + From 42df5626d9a454ad6caa1630f716c7b251ddc503 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Mon, 30 Jan 2023 00:12:43 +0200 Subject: [PATCH 28/79] Added Color class to replace SDL_Color --- client/CPlayerInterface.cpp | 7 +-- client/CVideoHandler.cpp | 2 + client/battle/BattleProjectileController.cpp | 9 +-- client/battle/CreatureAnimation.h | 2 + client/gui/CAnimation.cpp | 9 +-- client/gui/CAnimation.h | 1 - client/gui/CGuiHandler.cpp | 11 ++-- client/gui/Canvas.cpp | 4 +- client/gui/Canvas.h | 3 +- client/gui/CursorHandler.cpp | 2 + client/gui/Fonts.cpp | 5 +- client/gui/SDL_Extensions.cpp | 16 +++++ client/gui/SDL_Extensions.h | 8 ++- client/widgets/AdventureMapClasses.cpp | 21 +------ client/widgets/Images.h | 3 +- client/windows/CCastleInterface.cpp | 6 +- client/windows/CSpellWindow.cpp | 3 +- cmake_modules/VCMI_lib.cmake | 1 + lib/CCreatureHandler.cpp | 16 ++--- lib/CCreatureHandler.h | 7 ++- lib/Color.h | 62 ++++++++++++++++++++ lib/TerrainHandler.h | 5 +- mapeditor/maphandler.cpp | 2 +- 23 files changed, 137 insertions(+), 68 deletions(-) create mode 100644 lib/Color.h diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 2076695b7..bb7cbd2e7 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -63,7 +63,6 @@ #include "../lib/CPathfinder.h" #include "../lib/RoadHandler.h" #include "../lib/TerrainHandler.h" -#include #include "CServerHandler.h" // FIXME: only needed for CGameState::mutex #include "../lib/CGameState.h" @@ -342,7 +341,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose) auto unlockPim = vstd::makeUnlockGuard(*pim); while(frameNumber == GH.mainFPSmng->getFrameNumber()) - SDL_Delay(5); + boost::this_thread::sleep(boost::posix_time::milliseconds(5)); }; //first initializing done @@ -1514,7 +1513,7 @@ void CPlayerInterface::centerView (int3 pos, int focusTime) { auto unlockPim = vstd::makeUnlockGuard(*pim); IgnoreEvents ignore(*this); - SDL_Delay(focusTime); + boost::this_thread::sleep(boost::posix_time::milliseconds(focusTime)); } } CCS->curh->show(); @@ -2276,7 +2275,7 @@ void CPlayerInterface::waitForAllDialogs(bool unlockPim) while(!dialogs.empty()) { auto unlock = vstd::makeUnlockGuardIf(*pim, unlockPim); - SDL_Delay(5); + boost::this_thread::sleep(boost::posix_time::milliseconds(5)); } waitWhileDialog(unlockPim); } diff --git a/client/CVideoHandler.cpp b/client/CVideoHandler.cpp index b3dbe9563..8d3d37ad5 100644 --- a/client/CVideoHandler.cpp +++ b/client/CVideoHandler.cpp @@ -15,6 +15,8 @@ #include "CPlayerInterface.h" #include "../lib/filesystem/Filesystem.h" +#include + extern CGuiHandler GH; //global gui handler #ifndef DISABLE_VIDEO diff --git a/client/battle/BattleProjectileController.cpp b/client/battle/BattleProjectileController.cpp index 429d11fc1..c71d09ee7 100644 --- a/client/battle/BattleProjectileController.cpp +++ b/client/battle/BattleProjectileController.cpp @@ -116,10 +116,7 @@ void ProjectileRay::show(Canvas & canvas) for (size_t i = 0; i < rayConfig.size(); ++i) { auto ray = rayConfig[i]; - SDL_Color beginColor{ ray.r1, ray.g1, ray.b1, ray.a1}; - SDL_Color endColor { ray.r2, ray.g2, ray.b2, ray.a2}; - - canvas.drawLine(Point(x1, y1 + i), Point(x2, y2+i), beginColor, endColor); + canvas.drawLine(Point(x1, y1 + i), Point(x2, y2+i), ray.start, ray.end); } } else // draw in vertical axis @@ -133,10 +130,8 @@ void ProjectileRay::show(Canvas & canvas) for (size_t i = 0; i < rayConfig.size(); ++i) { auto ray = rayConfig[i]; - SDL_Color beginColor{ ray.r1, ray.g1, ray.b1, ray.a1}; - SDL_Color endColor { ray.r2, ray.g2, ray.b2, ray.a2}; - canvas.drawLine(Point(x1 + i, y1), Point(x2 + i, y2), beginColor, endColor); + canvas.drawLine(Point(x1 + i, y1), Point(x2 + i, y2), ray.start, ray.end); } } diff --git a/client/battle/CreatureAnimation.h b/client/battle/CreatureAnimation.h index cdead9c79..482b12b87 100644 --- a/client/battle/CreatureAnimation.h +++ b/client/battle/CreatureAnimation.h @@ -13,6 +13,8 @@ #include "../widgets/Images.h" #include "../gui/CAnimation.h" +#include + class CIntObject; class CreatureAnimation; class Canvas; diff --git a/client/gui/CAnimation.cpp b/client/gui/CAnimation.cpp index 50052fe48..448f0b389 100644 --- a/client/gui/CAnimation.cpp +++ b/client/gui/CAnimation.cpp @@ -17,10 +17,11 @@ #include "../CBitmapHandler.h" #include "../Graphics.h" -#include "../lib/filesystem/Filesystem.h" -#include "../lib/filesystem/ISimpleResourceLoader.h" -#include "../lib/JsonNode.h" -#include "../lib/CRandomGenerator.h" +#include "../../lib/filesystem/Filesystem.h" +#include "../../lib/filesystem/ISimpleResourceLoader.h" +#include "../../lib/JsonNode.h" +#include "../../lib/CRandomGenerator.h" +#include "../../lib/vcmi_endian.h" class SDLImageLoader; diff --git a/client/gui/CAnimation.h b/client/gui/CAnimation.h index d0e4ab84c..62793903d 100644 --- a/client/gui/CAnimation.h +++ b/client/gui/CAnimation.h @@ -9,7 +9,6 @@ */ #pragma once -#include "../../lib/vcmi_endian.h" #include "../../lib/GameConstants.h" #ifdef IN diff --git a/client/gui/CGuiHandler.cpp b/client/gui/CGuiHandler.cpp index ced56145f..a2ea6c00a 100644 --- a/client/gui/CGuiHandler.cpp +++ b/client/gui/CGuiHandler.cpp @@ -11,8 +11,6 @@ #include "CGuiHandler.h" #include "../lib/CondSh.h" -#include - #include "CIntObject.h" #include "CursorHandler.h" #include "SDL_Extensions.h" @@ -24,6 +22,9 @@ #include "../CPlayerInterface.h" #include "../battle/BattleInterface.h" +#include +#include + extern std::queue SDLEventsQueue; extern boost::mutex eventsM; @@ -641,12 +642,11 @@ const Point & CGuiHandler::getCursorPosition() const void CGuiHandler::drawFPSCounter() { - const static SDL_Color yellow = {255, 255, 0, 0}; static SDL_Rect overlay = { 0, 0, 64, 32}; Uint32 black = SDL_MapRGB(screen->format, 10, 10, 10); SDL_FillRect(screen, &overlay, black); std::string fps = boost::lexical_cast(mainFPSmng->fps); - graphics->fonts[FONT_BIG]->renderTextLeft(screen, fps, yellow, Point(10, 10)); + graphics->fonts[FONT_BIG]->renderTextLeft(screen, fps, Colors::YELLOW, Point(10, 10)); } SDL_Keycode CGuiHandler::arrowToNum(SDL_Keycode key) @@ -751,7 +751,8 @@ void CFramerateManager::framerateDelay() // FPS is higher than it should be, then wait some time if(timeElapsed < rateticks) { - SDL_Delay((Uint32)ceil(this->rateticks) - timeElapsed); + int timeToSleep = (Uint32)ceil(this->rateticks) - timeElapsed; + boost::this_thread::sleep(boost::posix_time::milliseconds(timeToSleep)); } currentTicks = SDL_GetTicks(); diff --git a/client/gui/Canvas.cpp b/client/gui/Canvas.cpp index adc443924..95d2f555c 100644 --- a/client/gui/Canvas.cpp +++ b/client/gui/Canvas.cpp @@ -76,9 +76,9 @@ void Canvas::draw(Canvas & image, const Point & pos) CSDL_Ext::blitAt(image.surface, renderOffset.x + pos.x, renderOffset.y + pos.y, surface); } -void Canvas::drawLine(const Point & from, const Point & dest, const SDL_Color & colorFrom, const SDL_Color & colorDest) +void Canvas::drawLine(const Point & from, const Point & dest, const ColorRGBA & colorFrom, const ColorRGBA & colorDest) { - CSDL_Ext::drawLine(surface, renderOffset.x + from.x, renderOffset.y + from.y, renderOffset.x + dest.x, renderOffset.y + dest.y, colorFrom, colorDest); + CSDL_Ext::drawLine(surface, renderOffset.x + from.x, renderOffset.y + from.y, renderOffset.x + dest.x, renderOffset.y + dest.y, CSDL_Ext::toSDL(colorFrom), CSDL_Ext::toSDL(colorDest)); } void Canvas::drawText(const Point & position, const EFonts & font, const SDL_Color & colorDest, ETextAlignment alignment, const std::string & text ) diff --git a/client/gui/Canvas.h b/client/gui/Canvas.h index d4fcc1619..39a4df9fa 100644 --- a/client/gui/Canvas.h +++ b/client/gui/Canvas.h @@ -11,6 +11,7 @@ #include "TextAlignment.h" #include "../../lib/Rect.h" +#include "../../lib/Color.h" struct SDL_Color; struct SDL_Surface; @@ -56,7 +57,7 @@ public: void draw(Canvas & image, const Point & pos); /// renders continuous, 1-pixel wide line with color gradient - void drawLine(const Point & from, const Point & dest, const SDL_Color & colorFrom, const SDL_Color & colorDest); + void drawLine(const Point & from, const Point & dest, const ColorRGBA & colorFrom, const ColorRGBA & colorDest); /// renders single line of text with specified parameters void drawText(const Point & position, const EFonts & font, const SDL_Color & colorDest, ETextAlignment alignment, const std::string & text ); diff --git a/client/gui/CursorHandler.cpp b/client/gui/CursorHandler.cpp index 39c19b860..b7392ff14 100644 --- a/client/gui/CursorHandler.cpp +++ b/client/gui/CursorHandler.cpp @@ -16,6 +16,8 @@ #include "CAnimation.h" #include "../../lib/CConfigHandler.h" +#include + #ifdef VCMI_APPLE #include #endif diff --git a/client/gui/Fonts.cpp b/client/gui/Fonts.cpp index 277a5bd51..6b46818c1 100644 --- a/client/gui/Fonts.cpp +++ b/client/gui/Fonts.cpp @@ -268,10 +268,7 @@ size_t CTrueTypeFont::getStringWidth(const std::string & data) const void CTrueTypeFont::renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const { if (color.r != 0 && color.g != 0 && color.b != 0) // not black - add shadow - { - SDL_Color black = { 0, 0, 0, SDL_ALPHA_OPAQUE}; - renderText(surface, data, black, pos + Point(1,1)); - } + renderText(surface, data, Colors::BLACK, pos + Point(1,1)); if (!data.empty()) { diff --git a/client/gui/SDL_Extensions.cpp b/client/gui/SDL_Extensions.cpp index 0d6a41e2e..62c2c5450 100644 --- a/client/gui/SDL_Extensions.cpp +++ b/client/gui/SDL_Extensions.cpp @@ -66,6 +66,22 @@ SDL_Rect CSDL_Ext::toSDL(const Rect & rect) return result; } +ColorRGBA CSDL_Ext::fromSDL(const SDL_Color & color) +{ + return { color.r, color.g, color.b, color.a }; +} + +SDL_Color CSDL_Ext::toSDL(const ColorRGBA & color) +{ + SDL_Color result; + result.r = color.r; + result.g = color.g; + result.b = color.b; + result.a = color.a; + + return result; +} + void CSDL_Ext::setColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors) { SDL_SetPaletteColors(surface->format->palette,colors,firstcolor,ncolors); diff --git a/client/gui/SDL_Extensions.h b/client/gui/SDL_Extensions.h index 8d5ff8859..4dbec2382 100644 --- a/client/gui/SDL_Extensions.h +++ b/client/gui/SDL_Extensions.h @@ -9,10 +9,10 @@ */ #pragma once -#include #include #include "../../lib/GameConstants.h" #include "../../lib/Rect.h" +#include "../../lib/Color.h" struct SDL_Window; struct SDL_Renderer; @@ -79,6 +79,12 @@ Rect fromSDL(const SDL_Rect & rect); /// creates SDL_Rect using provided rect SDL_Rect toSDL(const Rect & rect); +/// creates Color using provided SDL_Color +ColorRGBA fromSDL(const SDL_Color & color); + +/// creates SDL_Color using provided Color +SDL_Color toSDL(const ColorRGBA & color); + void setColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors); void warpMouse(int x, int y); bool isCtrlKeyDown(); diff --git a/client/widgets/AdventureMapClasses.cpp b/client/widgets/AdventureMapClasses.cpp index e507e99ff..1b9b828b3 100644 --- a/client/widgets/AdventureMapClasses.cpp +++ b/client/widgets/AdventureMapClasses.cpp @@ -355,13 +355,11 @@ void CTownList::update(const CGTownInstance *) const SDL_Color & CMinimapInstance::getTileColor(const int3 & pos) { - static const SDL_Color fogOfWar = {0, 0, 0, 255}; - const TerrainTile * tile = LOCPLINT->cb->getTile(pos, false); // if tile is not visible it will be black on minimap if(!tile) - return fogOfWar; + return Colors::BLACK; // if object at tile is owned - it will be colored as its owner for (const CGObjectInstance *obj : tile->blockingObjects) @@ -494,21 +492,8 @@ std::map > CMinimap::loadColors() for(const auto & terrain : CGI->terrainTypeHandler->objects) { - SDL_Color normal = - { - ui8(terrain->minimapUnblocked[0]), - ui8(terrain->minimapUnblocked[1]), - ui8(terrain->minimapUnblocked[2]), - ui8(255) - }; - - SDL_Color blocked = - { - ui8(terrain->minimapBlocked[0]), - ui8(terrain->minimapBlocked[1]), - ui8(terrain->minimapBlocked[2]), - ui8(255) - }; + SDL_Color normal = CSDL_Ext::toSDL(terrain->minimapUnblocked); + SDL_Color blocked = CSDL_Ext::toSDL(terrain->minimapBlocked); ret[terrain->getId()] = std::make_pair(normal, blocked); } diff --git a/client/widgets/Images.h b/client/widgets/Images.h index 2b4b1bd24..626f1fb34 100644 --- a/client/widgets/Images.h +++ b/client/widgets/Images.h @@ -12,13 +12,12 @@ #include "../gui/CIntObject.h" #include "../battle/BattleConstants.h" -#include - VCMI_LIB_NAMESPACE_BEGIN class Rect; VCMI_LIB_NAMESPACE_END struct SDL_Surface; +struct SDL_Color; class CAnimImage; class CLabel; class CAnimation; diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index 1dafce97f..37025192c 100644 --- a/client/windows/CCastleInterface.cpp +++ b/client/windows/CCastleInterface.cpp @@ -192,9 +192,9 @@ void CBuildingRect::show(SDL_Surface * to) if(border->format->palette != nullptr) { // key colors in glowing border - SDL_Color c1 = {200, 200, 200, 255}; - SDL_Color c2 = {120, 100, 60, 255}; - SDL_Color c3 = {200, 180, 110, 255}; + SDL_Color c1 = {200, 200, 200, 255}; // x2 + SDL_Color c2 = {120, 100, 60, 255}; // x0.5 + SDL_Color c3 = {210, 180, 110, 255}; // x1 ui32 colorID = SDL_MapRGB(border->format, c3.r, c3.g, c3.b); SDL_Color oldColor = border->format->palette->colors[colorID]; diff --git a/client/windows/CSpellWindow.cpp b/client/windows/CSpellWindow.cpp index f18dadaaa..c68e70746 100644 --- a/client/windows/CSpellWindow.cpp +++ b/client/windows/CSpellWindow.cpp @@ -640,9 +640,8 @@ void CSpellWindow::SpellArea::setSpell(const CSpell * spell) SDL_Color firstLineColor, secondLineColor; if(spellCost > owner->myHero->mana) //hero cannot cast this spell { - static const SDL_Color unavailableSpell = {239, 189, 33, 0}; firstLineColor = Colors::WHITE; - secondLineColor = unavailableSpell; + secondLineColor = Colors::ORANGE; } else { diff --git a/cmake_modules/VCMI_lib.cmake b/cmake_modules/VCMI_lib.cmake index 0190221ac..dfdb844f6 100644 --- a/cmake_modules/VCMI_lib.cmake +++ b/cmake_modules/VCMI_lib.cmake @@ -414,6 +414,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE) ${MAIN_LIB_DIR}/CModHandler.h ${MAIN_LIB_DIR}/CondSh.h ${MAIN_LIB_DIR}/ConstTransitivePtr.h + ${MAIN_LIB_DIR}/Color.h ${MAIN_LIB_DIR}/CPathfinder.h ${MAIN_LIB_DIR}/CPlayerState.h ${MAIN_LIB_DIR}/CRandomGenerator.h diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index f5e256301..15d54d74c 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -927,15 +927,15 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c { CCreature::CreatureAnimation::RayColor color; - color.r1 = value["start"].Vector()[0].Integer(); - color.g1 = value["start"].Vector()[1].Integer(); - color.b1 = value["start"].Vector()[2].Integer(); - color.a1 = value["start"].Vector()[3].Integer(); + color.start.r = value["start"].Vector()[0].Integer(); + color.start.g = value["start"].Vector()[1].Integer(); + color.start.b = value["start"].Vector()[2].Integer(); + color.start.a = value["start"].Vector()[3].Integer(); - color.r2 = value["end"].Vector()[0].Integer(); - color.g2 = value["end"].Vector()[1].Integer(); - color.b2 = value["end"].Vector()[2].Integer(); - color.a2 = value["end"].Vector()[3].Integer(); + color.end.r = value["end"].Vector()[0].Integer(); + color.end.g = value["end"].Vector()[1].Integer(); + color.end.b = value["end"].Vector()[2].Integer(); + color.end.a = value["end"].Vector()[3].Integer(); creature->animation.projectileRay.push_back(color); } diff --git a/lib/CCreatureHandler.h b/lib/CCreatureHandler.h index 0958c6eea..a61fb5568 100644 --- a/lib/CCreatureHandler.h +++ b/lib/CCreatureHandler.h @@ -19,6 +19,7 @@ #include "JsonNode.h" #include "IHandlerBase.h" #include "CRandomGenerator.h" +#include "Color.h" VCMI_LIB_NAMESPACE_BEGIN @@ -63,12 +64,12 @@ public: struct CreatureAnimation { struct RayColor { - uint8_t r1, g1, b1, a1; - uint8_t r2, g2, b2, a2; + ColorRGBA start; + ColorRGBA end; template void serialize(Handler &h, const int version) { - h & r1 & g1 & b1 & a1 & r2 & g2 & b2 & a2; + h & start & end; } }; diff --git a/lib/Color.h b/lib/Color.h new file mode 100644 index 000000000..f41f53d46 --- /dev/null +++ b/lib/Color.h @@ -0,0 +1,62 @@ +/* + * Color.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +VCMI_LIB_NAMESPACE_BEGIN + +/// An object that represents RGBA color +class ColorRGBA +{ +public: + enum : uint8_t + { + ALPHA_OPAQUE = 255, + ALPHA_TRANSPARENT = 0, + }; + + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + + //constructors + ColorRGBA() + :r(0) + ,g(0) + ,b(0) + ,a(0) + { + } + + ColorRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a) + : r(r) + , g(g) + , b(b) + , a(a) + {} + + ColorRGBA(uint8_t r, uint8_t g, uint8_t b) + : r(r) + , g(g) + , b(b) + , a(ALPHA_OPAQUE) + {} + + template + void serialize(Handler &h, const int version) + { + h & r; + h & g; + h & b; + h & a; + } +}; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/TerrainHandler.h b/lib/TerrainHandler.h index 648775b42..5d7ba3e1f 100644 --- a/lib/TerrainHandler.h +++ b/lib/TerrainHandler.h @@ -14,6 +14,7 @@ #include #include "GameConstants.h" #include "IHandlerBase.h" +#include "Color.h" VCMI_LIB_NAMESPACE_BEGIN @@ -46,8 +47,8 @@ public: std::vector battleFields; std::vector prohibitTransitions; - std::array minimapBlocked; - std::array minimapUnblocked; + ColorRGBA minimapBlocked; + ColorRGBA minimapUnblocked; std::string shortIdentifier; std::string musicFilename; std::string tilesFilename; diff --git a/mapeditor/maphandler.cpp b/mapeditor/maphandler.cpp index b9799eb0e..0df7b091a 100644 --- a/mapeditor/maphandler.cpp +++ b/mapeditor/maphandler.cpp @@ -433,7 +433,7 @@ QRgb MapHandler::getTileColor(int x, int y, int z) if (tile.blocked && (!tile.visitable)) color = tile.terType->minimapBlocked; - return qRgb(color[0], color[1], color[2]); + return qRgb(color.r, color.g, color.b); } void MapHandler::drawMinimapTile(QPainter & painter, int x, int y, int z) From e35a669eebbd33d29b74f6175789a459507057ac Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Mon, 30 Jan 2023 13:58:13 +0200 Subject: [PATCH 29/79] Refactoring of CPicture class to improve encapsulation --- client/lobby/CBonusSelection.cpp | 4 +- client/lobby/CSelectionBase.cpp | 2 +- client/mainmenu/CMainMenu.cpp | 4 -- client/widgets/AdventureMapClasses.cpp | 6 +- client/widgets/Images.cpp | 85 ++++++++------------------ client/widgets/Images.h | 45 +++++++++----- client/widgets/TextControls.cpp | 9 +-- client/widgets/TextControls.h | 2 +- client/windows/CAdvmapInterface.cpp | 8 +-- client/windows/CCastleInterface.cpp | 10 +-- client/windows/CSpellWindow.cpp | 4 +- client/windows/CTradeWindow.cpp | 2 +- client/windows/CWindowObject.cpp | 9 ++- client/windows/GUIClasses.cpp | 3 +- 14 files changed, 84 insertions(+), 109 deletions(-) diff --git a/client/lobby/CBonusSelection.cpp b/client/lobby/CBonusSelection.cpp index f617c7a10..6d1cd3ef2 100644 --- a/client/lobby/CBonusSelection.cpp +++ b/client/lobby/CBonusSelection.cpp @@ -492,8 +492,8 @@ CBonusSelection::CRegion::CRegion(int id, bool accessible, bool selectable, cons graphicsSelected->disable(); graphicsStriped = std::make_shared(prefix + "Co" + suffix + ".BMP"); graphicsStriped->disable(); - pos.w = graphicsNotSelected->bg->w; - pos.h = graphicsNotSelected->bg->h; + pos.w = graphicsNotSelected->pos.w; + pos.h = graphicsNotSelected->pos.h; } diff --git a/client/lobby/CSelectionBase.cpp b/client/lobby/CSelectionBase.cpp index 71576115b..db012ee8f 100644 --- a/client/lobby/CSelectionBase.cpp +++ b/client/lobby/CSelectionBase.cpp @@ -312,7 +312,7 @@ CChatBox::CChatBox(const Rect & rect) type |= REDRAW_PARENT; const int height = static_cast(graphics->fonts[FONT_SMALL]->getLineHeight()); - inputBox = std::make_shared(Rect(0, rect.h - height, rect.w, height)); + inputBox = std::make_shared(Rect(0, rect.h - height, rect.w, height), EFonts::FONT_SMALL, 0); inputBox->removeUsedEvents(KEYBOARD); chatHistory = std::make_shared("", Rect(0, 0, rect.w, rect.h - height), 1); diff --git a/client/mainmenu/CMainMenu.cpp b/client/mainmenu/CMainMenu.cpp index 094760366..f1a271067 100644 --- a/client/mainmenu/CMainMenu.cpp +++ b/client/mainmenu/CMainMenu.cpp @@ -76,11 +76,7 @@ CMenuScreen::CMenuScreen(const JsonNode & configNode) background = std::make_shared(config["background"].String()); if(config["scalable"].Bool()) - { - if(background->bg->format->palette) - background->convertToScreenBPP(); background->scaleTo(Point(screen->w, screen->h)); - } pos = background->center(); diff --git a/client/widgets/AdventureMapClasses.cpp b/client/widgets/AdventureMapClasses.cpp index 1b9b828b3..a9f269ff3 100644 --- a/client/widgets/AdventureMapClasses.cpp +++ b/client/widgets/AdventureMapClasses.cpp @@ -182,7 +182,7 @@ CHeroList::CEmptyHeroItem::CEmptyHeroItem() { OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); movement = std::make_shared("IMOBIL", 0, 0, 0, 1); - portrait = std::make_shared("HPSXXX", movement->pos.w + 1); + portrait = std::make_shared("HPSXXX", movement->pos.w + 1, 0); mana = std::make_shared("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1 ); pos.w = mana->pos.w + mana->pos.x - pos.x; @@ -213,7 +213,7 @@ void CHeroList::CHeroItem::update() std::shared_ptr CHeroList::CHeroItem::genSelection() { - return std::make_shared("HPSYYY", movement->pos.w + 1); + return std::make_shared("HPSYYY", movement->pos.w + 1, 0); } void CHeroList::CHeroItem::select(bool on) @@ -780,7 +780,7 @@ CInfoBar::VisibleComponentInfo::VisibleComponentInfo(const Component & compToDis { OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared("ADSTATOT", 1); + background = std::make_shared("ADSTATOT", 1, 0); comp = std::make_shared(compToDisplay); comp->moveTo(Point(pos.x+47, pos.y+50)); diff --git a/client/widgets/Images.cpp b/client/widgets/Images.cpp index 88bced4b5..7d17d1f5e 100644 --- a/client/widgets/Images.cpp +++ b/client/widgets/Images.cpp @@ -35,24 +35,34 @@ #include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff #include "../../lib/CRandomGenerator.h" -CPicture::CPicture( SDL_Surface *BG, int x, int y, bool Free ) +CPicture::CPicture(SDL_Surface *BG, const Point & position) + : bg(BG) + , visible(true) + , needRefresh(false) { - init(); - bg = BG; - freeSurf = Free; - pos.x += x; - pos.y += y; + BG->refcount += 1; + pos += position; pos.w = BG->w; pos.h = BG->h; } CPicture::CPicture( const std::string &bmpname, int x, int y ) + : CPicture(bmpname, Point(x,y)) +{} + +CPicture::CPicture( const std::string &bmpname ) + : CPicture(bmpname, Point(0,0)) +{} + +CPicture::CPicture( const std::string &bmpname, const Point & position ) + : bg(BitmapHandler::loadBitmap(bmpname)) + , visible(true) + , needRefresh(false) { - init(); - bg = BitmapHandler::loadBitmap(bmpname); - freeSurf = true; - pos.x += x; - pos.y += y; + pos.x += position.x; + pos.y += position.y; + + assert(bg); if(bg) { pos.w = bg->w; @@ -64,29 +74,12 @@ CPicture::CPicture( const std::string &bmpname, int x, int y ) } } -CPicture::CPicture(const Rect &r, const SDL_Color &color, bool screenFormat) +CPicture::CPicture(SDL_Surface * BG, const Rect &SrcRect, int x, int y) + : CPicture(BG, Point(x,y)) { - init(); - createSimpleRect(r, screenFormat, SDL_MapRGB(bg->format, color.r, color.g,color.b)); -} - -CPicture::CPicture(const Rect &r, ui32 color, bool screenFormat) -{ - init(); - createSimpleRect(r, screenFormat, color); -} - -CPicture::CPicture(SDL_Surface * BG, const Rect &SrcRect, int x, int y, bool free) -{ - visible = true; - needRefresh = false; - srcRect = new Rect(SrcRect); - pos.x += x; - pos.y += y; + srcRect = SrcRect; pos.w = srcRect->w; pos.h = srcRect->h; - bg = BG; - freeSurf = free; } void CPicture::setSurface(SDL_Surface *to) @@ -106,16 +99,7 @@ void CPicture::setSurface(SDL_Surface *to) CPicture::~CPicture() { - if(freeSurf) - SDL_FreeSurface(bg); - delete srcRect; -} - -void CPicture::init() -{ - visible = true; - needRefresh = false; - srcRect = nullptr; + SDL_FreeSurface(bg); } void CPicture::show(SDL_Surface * to) @@ -146,31 +130,16 @@ void CPicture::convertToScreenBPP() void CPicture::setAlpha(int value) { CSDL_Ext::setAlpha (bg, value); + SDL_SetSurfaceBlendMode(bg,SDL_BLENDMODE_BLEND); } void CPicture::scaleTo(Point size) { SDL_Surface * scaled = CSDL_Ext::scaleSurface(bg, size.x, size.y); - if(freeSurf) - SDL_FreeSurface(bg); + SDL_FreeSurface(bg); setSurface(scaled); - freeSurf = false; -} - -void CPicture::createSimpleRect(const Rect &r, bool screenFormat, ui32 color) -{ - pos += r.topLeft(); - pos.w = r.w; - pos.h = r.h; - if(screenFormat) - bg = CSDL_Ext::newSurface(r.w, r.h); - else - bg = SDL_CreateRGBSurface(0, r.w, r.h, 8, 0, 0, 0, 0); - - SDL_FillRect(bg, nullptr, color); - freeSurf = true; } void CPicture::colorize(PlayerColor player) diff --git a/client/widgets/Images.h b/client/widgets/Images.h index 626f1fb34..08d547486 100644 --- a/client/widgets/Images.h +++ b/client/widgets/Images.h @@ -27,11 +27,20 @@ class IImage; class CPicture : public CIntObject { void setSurface(SDL_Surface *to); -public: + SDL_Surface * bg; - Rect * srcRect; //if nullptr then whole surface will be used - bool freeSurf; //whether surface will be freed upon CPicture destruction - bool needRefresh;//Surface needs to be displayed each frame + + void convertToScreenBPP(); + +public: + /// if set, only specified section of internal image will be rendered + boost::optional srcRect; + + /// If set to true, iamge will be redrawn on each frame + bool needRefresh; + + /// If set to false, image will not be rendered + /// Deprecated, use CIntObject::disable()/enable() instead bool visible; SDL_Surface * getSurface() @@ -39,24 +48,28 @@ public: return bg; } - CPicture(const Rect & r, const SDL_Color & color, bool screenFormat = false); //rect filled with given color - CPicture(const Rect & r, ui32 color, bool screenFormat = false); //rect filled with given color - CPicture(SDL_Surface * BG, int x = 0, int y=0, bool Free = true); //wrap existing SDL_Surface - CPicture(const std::string &bmpname, int x=0, int y=0); - CPicture(SDL_Surface *BG, const Rect &SrcRext, int x = 0, int y = 0, bool free = false); //wrap subrect of given surface + /// wrap existing SDL_Surface + /// deprecated, do not use + CPicture(SDL_Surface * BG, const Point & position); + + /// wrap section of existing SDL_Surface + CPicture(SDL_Surface *BG, const Rect &SrcRext, int x = 0, int y = 0); //wrap subrect of given surface + + /// Loads image from specified file name + CPicture(const std::string & bmpname); + CPicture(const std::string & bmpname, const Point & position); + CPicture(const std::string & bmpname, int x, int y); + ~CPicture(); - void init(); - //set alpha value for whole surface. Note: may be messed up if surface is shared - // 0=transparent, 255=opaque + /// set alpha value for whole surface. Note: may be messed up if surface is shared + /// 0=transparent, 255=opaque void setAlpha(int value); - void scaleTo(Point size); - void createSimpleRect(const Rect &r, bool screenFormat, ui32 color); + void colorize(PlayerColor player); + void show(SDL_Surface * to) override; void showAll(SDL_Surface * to) override; - void convertToScreenBPP(); - void colorize(PlayerColor player); }; /// area filled with specific texture diff --git a/client/widgets/TextControls.cpp b/client/widgets/TextControls.cpp index 38c971aa6..7c0d634ed 100644 --- a/client/widgets/TextControls.cpp +++ b/client/widgets/TextControls.cpp @@ -415,7 +415,7 @@ CGStatusBar::CGStatusBar(int x, int y, std::string name, int maxw) { //execution of this block when maxw is incorrect breaks text centralization (issue #3151) vstd::amin(pos.w, maxw); - background->srcRect = new Rect(0, 0, maxw, pos.h); + background->srcRect = Rect(0, 0, maxw, pos.h); } autoRedraw = false; } @@ -502,12 +502,7 @@ CTextInput::CTextInput(const Rect & Pos, SDL_Surface * srf) pos += Pos.topLeft(); captureAllKeys = true; OBJ_CONSTRUCTION; - background = std::make_shared(Pos, 0, true); - Rect hlp = Pos; - if(srf) - CSDL_Ext::blitSurface(srf, hlp, background->getSurface(), Point(0,0)); - else - SDL_FillRect(background->getSurface(), nullptr, 0); + background = std::make_shared(srf, Pos); pos.w = background->pos.w; pos.h = background->pos.h; background->pos = pos; diff --git a/client/widgets/TextControls.h b/client/widgets/TextControls.h index 064e47536..c946bf8b2 100644 --- a/client/widgets/TextControls.h +++ b/client/widgets/TextControls.h @@ -218,7 +218,7 @@ public: CTextInput(const Rect & Pos, EFonts font, const CFunctionList & CB); CTextInput(const Rect & Pos, const Point & bgOffset, const std::string & bgName, const CFunctionList & CB); - CTextInput(const Rect & Pos, SDL_Surface * srf = nullptr); + CTextInput(const Rect & Pos, SDL_Surface * srf); void clickLeft(tribool down, bool previousState) override; void keyPressed(const SDL_KeyboardEvent & key) override; diff --git a/client/windows/CAdvmapInterface.cpp b/client/windows/CAdvmapInterface.cpp index 29e5e7d1d..ba1085b4d 100644 --- a/client/windows/CAdvmapInterface.cpp +++ b/client/windows/CAdvmapInterface.cpp @@ -478,8 +478,8 @@ CResDataBar::CResDataBar(const std::string & defname, int x, int y, int offx, in background = std::make_shared(defname, 0, 0); background->colorize(LOCPLINT->playerID); - pos.w = background->bg->w; - pos.h = background->bg->h; + pos.w = background->pos.w; + pos.h = background->pos.h; txtpos.resize(8); for (int i = 0; i < 8 ; i++) @@ -502,8 +502,8 @@ CResDataBar::CResDataBar() background = std::make_shared(ADVOPT.resdatabarG, 0, 0); background->colorize(LOCPLINT->playerID); - pos.w = background->bg->w; - pos.h = background->bg->h; + pos.w = background->pos.w; + pos.h = background->pos.h; txtpos.resize(8); for (int i = 0; i < 8 ; i++) diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index 37025192c..19e40fc21 100644 --- a/client/windows/CCastleInterface.cpp +++ b/client/windows/CCastleInterface.cpp @@ -1168,7 +1168,7 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst garr->addSplitBtn(split); Rect barRect(9, 182, 732, 18); - auto statusbarBackground = std::make_shared(panel->getSurface(), barRect, 9, 555, false); + auto statusbarBackground = std::make_shared(panel->getSurface(), barRect, 9, 555); statusbar = CGStatusBar::create(statusbarBackground); resdatabar = std::make_shared("ARESBAR", 3, 575, 32, 2, 85, 85); @@ -1365,7 +1365,7 @@ CHallInterface::CHallInterface(const CGTownInstance * Town): resdatabar->moveBy(pos.topLeft(), true); Rect barRect(5, 556, 740, 18); - auto statusbarBackground = std::make_shared(background->getSurface(), barRect, 5, 556, false); + auto statusbarBackground = std::make_shared(background->getSurface(), barRect, 5, 556); statusbar = CGStatusBar::create(statusbarBackground); title = std::make_shared(399, 12, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, town->town->buildings.at(BuildingID(town->hallLevel()+BuildingID::VILLAGE_HALL))->getNameTranslated()); @@ -1588,7 +1588,7 @@ CFortScreen::CFortScreen(const CGTownInstance * town): Rect barRect(4, 554, 740, 18); - auto statusbarBackground = std::make_shared(background->getSurface(), barRect, 4, 554, false); + auto statusbarBackground = std::make_shared(background->getSurface(), barRect, 4, 554); statusbar = CGStatusBar::create(statusbarBackground); } @@ -1729,7 +1729,7 @@ CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner,std::string imagem) Rect barRect(7, 556, 737, 18); - auto statusbarBackground = std::make_shared(background->getSurface(), barRect, 7, 556, false); + auto statusbarBackground = std::make_shared(background->getSurface(), barRect, 7, 556); statusbar = CGStatusBar::create(statusbarBackground); exit = std::make_shared(Point(748, 556), "TPMAGE1.DEF", CButton::tooltip(CGI->generaltexth->allTexts[593]), [&](){ close(); }, SDLK_RETURN); @@ -1796,7 +1796,7 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, CreatureID creMachineID, Art Rect barRect(8, pos.h - 26, pos.w - 16, 19); - auto statusbarBackground = std::make_shared(background->getSurface(), barRect, 8, pos.h - 26, false); + auto statusbarBackground = std::make_shared(background->getSurface(), barRect, 8, pos.h - 26); statusbar = CGStatusBar::create(statusbarBackground); animBG = std::make_shared("TPSMITBK", 64, 50); diff --git a/client/windows/CSpellWindow.cpp b/client/windows/CSpellWindow.cpp index c68e70746..4dc525baf 100644 --- a/client/windows/CSpellWindow.cpp +++ b/client/windows/CSpellWindow.cpp @@ -206,9 +206,9 @@ CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _m temp_rect = CSDL_Ext::genRect(36, 56, 549 + pos.x, 330 + pos.y); interactiveAreas.push_back(std::make_shared(temp_rect, std::bind(&CSpellWindow::selectSchool, this, 4), 458, this)); - temp_rect = CSDL_Ext::genRect(leftCorner->bg->h, leftCorner->bg->w, 97 + pos.x, 77 + pos.y); + temp_rect = CSDL_Ext::genRect(leftCorner->pos.h, leftCorner->pos.w, 97 + pos.x, 77 + pos.y); interactiveAreas.push_back(std::make_shared(temp_rect, std::bind(&CSpellWindow::fLcornerb, this), 450, this)); - temp_rect = CSDL_Ext::genRect(rightCorner->bg->h, rightCorner->bg->w, 487 + pos.x, 72 + pos.y); + temp_rect = CSDL_Ext::genRect(rightCorner->pos.h, rightCorner->pos.w, 487 + pos.x, 72 + pos.y); interactiveAreas.push_back(std::make_shared(temp_rect, std::bind(&CSpellWindow::fRcornerb, this), 451, this)); //areas for spells diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index 4f5bc7ffc..d12bbf7c6 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -679,7 +679,7 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket * Market, const CGHeroInsta // create image that copies part of background containing slot MISC_1 into position of slot MISC_5 // this is workaround for bug in H3 files where this slot for ragdoll on this screen is missing - images.push_back(std::make_shared(background->bg, Rect(20, 187, 47, 47), 18, 339 )); + images.push_back(std::make_shared(background->getSurface(), Rect(20, 187, 47, 47), 18, 339 )); sliderNeeded = false; break; default: diff --git a/client/windows/CWindowObject.cpp b/client/windows/CWindowObject.cpp index a4c801fba..48a3495f0 100644 --- a/client/windows/CWindowObject.cpp +++ b/client/windows/CWindowObject.cpp @@ -213,11 +213,14 @@ void CWindowObject::setShadow(bool on) { OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - shadowParts.push_back(std::make_shared(shadowCorner, shadowPos.x, shadowPos.y)); - shadowParts.push_back(std::make_shared(shadowRight, shadowPos.x, shadowStart.y)); - shadowParts.push_back(std::make_shared(shadowBottom, shadowStart.x, shadowPos.y)); + shadowParts.push_back(std::make_shared(shadowCorner, Point(shadowPos.x, shadowPos.y))); + shadowParts.push_back(std::make_shared(shadowRight, Point(shadowPos.x, shadowStart.y))); + shadowParts.push_back(std::make_shared(shadowBottom, Point(shadowStart.x, shadowPos.y))); } + SDL_FreeSurface(shadowCorner); + SDL_FreeSurface(shadowBottom); + SDL_FreeSurface(shadowRight); } } diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 2b9521c68..0954ac825 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -1208,7 +1208,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, questlogButton[1] = std::make_shared(Point(740, qeLayout ? 39 : 44), "hsbtns4.def", CButton::tooltip(CGI->generaltexth->heroscrn[0]), std::bind(&CExchangeWindow::questlog, this, 1)); Rect barRect(5, 578, 725, 18); - statusbar = CGStatusBar::create(std::make_shared(background->getSurface(), barRect, 5, 578, false)); + statusbar = CGStatusBar::create(std::make_shared(background->getSurface(), barRect, 5, 578)); //garrison interface @@ -1368,7 +1368,6 @@ CPuzzleWindow::CPuzzleWindow(const int3 & GrailPos, double discoveredRatio) piecesToRemove.push_back(piece); piece->needRefresh = true; piece->recActions = piece->recActions & ~SHOWALL; - SDL_SetSurfaceBlendMode(piece->bg,SDL_BLENDMODE_BLEND); } else { From 87218c63c40dd13a9fb8cdeb1ae783098ab85015 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Mon, 30 Jan 2023 17:18:59 +0200 Subject: [PATCH 30/79] CPicture now uses IImage internally --- client/CMessage.cpp | 2 +- client/gui/CAnimation.cpp | 36 ++++++++++++---- client/gui/CAnimation.h | 8 +++- client/gui/SDL_Extensions.cpp | 5 ++- client/lobby/CBonusSelection.cpp | 4 +- client/mapHandler.cpp | 2 +- client/widgets/Images.cpp | 73 ++++++++------------------------ client/widgets/Images.h | 19 +++------ client/widgets/TextControls.cpp | 2 +- client/widgets/TextControls.h | 3 +- client/windows/CWindowObject.cpp | 7 +-- 11 files changed, 73 insertions(+), 88 deletions(-) diff --git a/client/CMessage.cpp b/client/CMessage.cpp index fd39f9a66..ce670af5e 100644 --- a/client/CMessage.cpp +++ b/client/CMessage.cpp @@ -97,7 +97,7 @@ void CMessage::dispose() SDL_Surface * CMessage::drawDialogBox(int w, int h, PlayerColor playerColor) { //prepare surface - SDL_Surface * ret = SDL_CreateRGBSurface(0, w, h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask); + SDL_Surface * ret = CSDL_Ext::newSurface(w,h); for (int i=0; iw)//background { for (int j=0; jh) diff --git a/client/gui/CAnimation.cpp b/client/gui/CAnimation.cpp index 448f0b389..9bb926adf 100644 --- a/client/gui/CAnimation.cpp +++ b/client/gui/CAnimation.cpp @@ -97,7 +97,7 @@ public: void draw(SDL_Surface * where, int posX=0, int posY=0, const Rect *src=nullptr) const override; void draw(SDL_Surface * where, const Rect * dest, const Rect * src) const override; - std::shared_ptr scaleFast(float scale) const override; + std::shared_ptr scaleFast(const Point & size) const override; void exportBitmap(const boost::filesystem::path & path) const override; void playerColored(PlayerColor player) override; void setFlagColor(PlayerColor player) override; @@ -112,6 +112,8 @@ public: void resetPalette(int colorID) override; void resetPalette() override; + void setAlpha(uint8_t value) override; + void setSpecialPallete(const SpecialPalette & SpecialPalette) override; friend class SDLImageLoader; @@ -143,6 +145,11 @@ std::shared_ptr IImage::createFromFile( const std::string & path ) return std::shared_ptr(new SDLImage(path)); } +std::shared_ptr IImage::createFromSurface( SDL_Surface * source ) +{ + return std::shared_ptr(new SDLImage(source, true)); +} + // Extremely simple file cache. TODO: smarter, more general solution class CFileCache { @@ -679,7 +686,11 @@ void SDLImage::draw(SDL_Surface* where, const Rect * dest, const Rect* src) cons if(dest) destShift += dest->topLeft(); - if(surf->format->BitsPerPixel == 8) + uint8_t perSurfaceAlpha; + if (SDL_GetSurfaceAlphaMod(surf, &perSurfaceAlpha) != 0) + logGlobal->error("SDL_GetSurfaceAlphaMod faied! %s", SDL_GetError()); + + if(surf->format->BitsPerPixel == 8 && perSurfaceAlpha == SDL_ALPHA_OPAQUE) { CSDL_Ext::blit8bppAlphaTo24bpp(surf, sourceRect, where, destShift); } @@ -689,9 +700,12 @@ void SDLImage::draw(SDL_Surface* where, const Rect * dest, const Rect* src) cons } } -std::shared_ptr SDLImage::scaleFast(float scale) const +std::shared_ptr SDLImage::scaleFast(const Point & size) const { - auto scaled = CSDL_Ext::scaleSurfaceFast(surf, (int)(surf->w * scale), (int)(surf->h * scale)); + float scaleX = float(size.x) / width(); + float scaleY = float(size.y) / height(); + + auto scaled = CSDL_Ext::scaleSurfaceFast(surf, (int)(surf->w * scaleX), (int)(surf->h * scaleY)); if (scaled->format && scaled->format->palette) // fix color keying, because SDL loses it at this point CSDL_Ext::setColorKey(scaled, scaled->format->palette->colors[0]); @@ -702,11 +716,11 @@ std::shared_ptr SDLImage::scaleFast(float scale) const SDLImage * ret = new SDLImage(scaled, false); - ret->fullSize.x = (int) round((float)fullSize.x * scale); - ret->fullSize.y = (int) round((float)fullSize.y * scale); + ret->fullSize.x = (int) round((float)fullSize.x * scaleX); + ret->fullSize.y = (int) round((float)fullSize.y * scaleY); - ret->margins.x = (int) round((float)margins.x * scale); - ret->margins.y = (int) round((float)margins.y * scale); + ret->margins.x = (int) round((float)margins.x * scaleX); + ret->margins.y = (int) round((float)margins.y * scaleY); return std::shared_ptr(ret); } @@ -721,6 +735,12 @@ void SDLImage::playerColored(PlayerColor player) graphics->blueToPlayersAdv(surf, player); } +void SDLImage::setAlpha(uint8_t value) +{ + CSDL_Ext::setAlpha (surf, value); + SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_BLEND); +} + void SDLImage::setFlagColor(PlayerColor player) { if(player < PlayerColor::PLAYER_LIMIT || player==PlayerColor::NEUTRAL) diff --git a/client/gui/CAnimation.h b/client/gui/CAnimation.h index 62793903d..58894e80b 100644 --- a/client/gui/CAnimation.h +++ b/client/gui/CAnimation.h @@ -44,7 +44,7 @@ public: virtual void draw(SDL_Surface * where, int posX = 0, int posY = 0, const Rect * src = nullptr) const = 0; virtual void draw(SDL_Surface * where, const Rect * dest, const Rect * src) const = 0; - virtual std::shared_ptr scaleFast(float scale) const = 0; + virtual std::shared_ptr scaleFast(const Point & size) const = 0; virtual void exportBitmap(const boost::filesystem::path & path) const = 0; @@ -67,6 +67,8 @@ public: virtual void resetPalette(int colorID) = 0; virtual void resetPalette() = 0; + virtual void setAlpha(uint8_t value) = 0; + //only indexed bitmaps with 7 special colors virtual void setSpecialPallete(const SpecialPalette & SpecialPalette) = 0; @@ -78,6 +80,10 @@ public: /// loads image from specified file. Returns 0-sized images on failure static std::shared_ptr createFromFile( const std::string & path ); + + /// temporary compatibility method. Creates IImage from existing SDL_Surface + /// Surface will be shared, called must still free it with SDL_FreeSurface + static std::shared_ptr createFromSurface( SDL_Surface * source ); }; /// Class for handling animation diff --git a/client/gui/SDL_Extensions.cpp b/client/gui/SDL_Extensions.cpp index 62c2c5450..f1efad669 100644 --- a/client/gui/SDL_Extensions.cpp +++ b/client/gui/SDL_Extensions.cpp @@ -852,7 +852,10 @@ void CSDL_Ext::blitSurface(SDL_Surface * src, const Rect & srcRectInput, SDL_Sur SDL_Rect srcRect = CSDL_Ext::toSDL(srcRectInput); SDL_Rect dstRect = CSDL_Ext::toSDL(Rect(dstPoint, srcRectInput.dimensions())); - SDL_UpperBlit(src, &srcRect, dst, &dstRect); + int result = SDL_UpperBlit(src, &srcRect, dst, &dstRect); + + if (result != 0) + logGlobal->error("SDL_UpperBlit failed! %s", SDL_GetError()); } void CSDL_Ext::blitSurface(SDL_Surface * src, SDL_Surface * dst, const Point & dest) diff --git a/client/lobby/CBonusSelection.cpp b/client/lobby/CBonusSelection.cpp index 6d1cd3ef2..d3a6d7505 100644 --- a/client/lobby/CBonusSelection.cpp +++ b/client/lobby/CBonusSelection.cpp @@ -525,7 +525,7 @@ void CBonusSelection::CRegion::clickLeft(tribool down, bool previousState) if(indeterminate(down)) return; - if(!down && selectable && !CSDL_Ext::isTransparent(graphicsNotSelected->getSurface(), GH.getCursorPosition() - pos.topLeft())) + if(!down && selectable && !graphicsNotSelected->getSurface()->isTransparent(GH.getCursorPosition() - pos.topLeft())) { CSH->setCampaignMap(idOfMapAndRegion); } @@ -535,7 +535,7 @@ void CBonusSelection::CRegion::clickRight(tribool down, bool previousState) { // FIXME: For some reason "down" is only ever contain indeterminate_value auto text = CSH->si->campState->camp->scenarios[idOfMapAndRegion].regionText; - if(!CSDL_Ext::isTransparent(graphicsNotSelected->getSurface(), GH.getCursorPosition() - pos.topLeft()) && text.size()) + if(!graphicsNotSelected->getSurface()->isTransparent(GH.getCursorPosition() - pos.topLeft()) && text.size()) { CRClickPopup::createAndPush(text); } diff --git a/client/mapHandler.cpp b/client/mapHandler.cpp index ae0620877..2d1a4a6e7 100644 --- a/client/mapHandler.cpp +++ b/client/mapHandler.cpp @@ -1434,7 +1434,7 @@ std::shared_ptr CMapHandler::CMapCache::requestWorldViewCacheOrCreate(CM auto iter = cache.find(key); if(iter == cache.end()) { - auto scaled = fullSurface->scaleFast(worldViewCachedScale); + auto scaled = fullSurface->scaleFast(fullSurface->dimensions() * worldViewCachedScale); cache[key] = scaled; return scaled; } diff --git a/client/widgets/Images.cpp b/client/widgets/Images.cpp index 7d17d1f5e..445069d16 100644 --- a/client/widgets/Images.cpp +++ b/client/widgets/Images.cpp @@ -35,15 +35,14 @@ #include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff #include "../../lib/CRandomGenerator.h" -CPicture::CPicture(SDL_Surface *BG, const Point & position) - : bg(BG) +CPicture::CPicture(std::shared_ptr image, const Point & position) + : bg(image) , visible(true) , needRefresh(false) { - BG->refcount += 1; pos += position; - pos.w = BG->w; - pos.h = BG->h; + pos.w = bg->width(); + pos.h = bg->height(); } CPicture::CPicture( const std::string &bmpname, int x, int y ) @@ -55,7 +54,7 @@ CPicture::CPicture( const std::string &bmpname ) {} CPicture::CPicture( const std::string &bmpname, const Point & position ) - : bg(BitmapHandler::loadBitmap(bmpname)) + : bg(IImage::createFromFile(bmpname)) , visible(true) , needRefresh(false) { @@ -65,8 +64,8 @@ CPicture::CPicture( const std::string &bmpname, const Point & position ) assert(bg); if(bg) { - pos.w = bg->w; - pos.h = bg->h; + pos.w = bg->width(); + pos.h = bg->height(); } else { @@ -74,34 +73,14 @@ CPicture::CPicture( const std::string &bmpname, const Point & position ) } } -CPicture::CPicture(SDL_Surface * BG, const Rect &SrcRect, int x, int y) - : CPicture(BG, Point(x,y)) +CPicture::CPicture(std::shared_ptr image, const Rect &SrcRect, int x, int y) + : CPicture(image, Point(x,y)) { srcRect = SrcRect; pos.w = srcRect->w; pos.h = srcRect->h; } -void CPicture::setSurface(SDL_Surface *to) -{ - bg = to; - if (srcRect) - { - pos.w = srcRect->w; - pos.h = srcRect->h; - } - else - { - pos.w = bg->w; - pos.h = bg->h; - } -} - -CPicture::~CPicture() -{ - SDL_FreeSurface(bg); -} - void CPicture::show(SDL_Surface * to) { if (visible && needRefresh) @@ -111,41 +90,25 @@ void CPicture::show(SDL_Surface * to) void CPicture::showAll(SDL_Surface * to) { if(bg && visible) - { - if(srcRect) - CSDL_Ext::blitSurface(bg, *srcRect, to, pos.topLeft()); - else - CSDL_Ext::blitAt(bg, pos, to); - } -} - -void CPicture::convertToScreenBPP() -{ - SDL_Surface *hlp = bg; - bg = SDL_ConvertSurface(hlp,screen->format,0); - CSDL_Ext::setDefaultColorKey(bg); - SDL_FreeSurface(hlp); + bg->draw(to, pos.x, pos.y, srcRect.get_ptr()); } void CPicture::setAlpha(int value) { - CSDL_Ext::setAlpha (bg, value); - SDL_SetSurfaceBlendMode(bg,SDL_BLENDMODE_BLEND); + bg->setAlpha(value); } void CPicture::scaleTo(Point size) { - SDL_Surface * scaled = CSDL_Ext::scaleSurface(bg, size.x, size.y); + bg = bg->scaleFast(size); - SDL_FreeSurface(bg); - - setSurface(scaled); + pos.w = bg->width(); + pos.h = bg->height(); } void CPicture::colorize(PlayerColor player) { - assert(bg); - graphics->blueToPlayersAdv(bg, player); + bg->playerColored(player); } CFilledTexture::CFilledTexture(std::string imageName, Rect position): @@ -264,7 +227,7 @@ void CAnimImage::showAll(SDL_Surface * to) { if(isScaled()) { - auto scaled = img->scaleFast(float(scaledSize.x) / img->width()); + auto scaled = img->scaleFast(scaledSize); scaled->draw(to, pos.x, pos.y); } else @@ -418,9 +381,7 @@ void CShowableAnim::blitImage(size_t frame, size_t group, SDL_Surface *to) auto img = anim->getImage(frame, group); if(img) { - const ColorFilter alphaFilter = ColorFilter::genAlphaShifter(vstd::lerp(0.0f, 1.0f, alpha/255.0f)); - img->adjustPalette(alphaFilter); - + img->setAlpha(alpha); img->draw(to, pos.x, pos.y, &src); } } diff --git a/client/widgets/Images.h b/client/widgets/Images.h index 08d547486..1ac5bbce5 100644 --- a/client/widgets/Images.h +++ b/client/widgets/Images.h @@ -26,11 +26,7 @@ class IImage; // Image class class CPicture : public CIntObject { - void setSurface(SDL_Surface *to); - - SDL_Surface * bg; - - void convertToScreenBPP(); + std::shared_ptr bg; public: /// if set, only specified section of internal image will be rendered @@ -43,25 +39,22 @@ public: /// Deprecated, use CIntObject::disable()/enable() instead bool visible; - SDL_Surface * getSurface() + std::shared_ptr getSurface() { return bg; } - /// wrap existing SDL_Surface - /// deprecated, do not use - CPicture(SDL_Surface * BG, const Point & position); + /// wrap existing image + CPicture(std::shared_ptr image, const Point & position); - /// wrap section of existing SDL_Surface - CPicture(SDL_Surface *BG, const Rect &SrcRext, int x = 0, int y = 0); //wrap subrect of given surface + /// wrap section of an existing Image + CPicture(std::shared_ptr image, const Rect &SrcRext, int x = 0, int y = 0); //wrap subrect of given surface /// Loads image from specified file name CPicture(const std::string & bmpname); CPicture(const std::string & bmpname, const Point & position); CPicture(const std::string & bmpname, int x, int y); - ~CPicture(); - /// set alpha value for whole surface. Note: may be messed up if surface is shared /// 0=transparent, 255=opaque void setAlpha(int value); diff --git a/client/widgets/TextControls.cpp b/client/widgets/TextControls.cpp index 7c0d634ed..55bd3bcf0 100644 --- a/client/widgets/TextControls.cpp +++ b/client/widgets/TextControls.cpp @@ -496,7 +496,7 @@ CTextInput::CTextInput(const Rect & Pos, const Point & bgOffset, const std::stri #endif } -CTextInput::CTextInput(const Rect & Pos, SDL_Surface * srf) +CTextInput::CTextInput(const Rect & Pos, std::shared_ptr srf) :CFocusable(std::make_shared(this)) { pos += Pos.topLeft(); diff --git a/client/widgets/TextControls.h b/client/widgets/TextControls.h index c946bf8b2..cda84bb78 100644 --- a/client/widgets/TextControls.h +++ b/client/widgets/TextControls.h @@ -14,6 +14,7 @@ #include "../gui/SDL_Extensions.h" #include "../../lib/FunctionList.h" +class IImage; class CSlider; /// Base class for all text-related widgets. @@ -218,7 +219,7 @@ public: CTextInput(const Rect & Pos, EFonts font, const CFunctionList & CB); CTextInput(const Rect & Pos, const Point & bgOffset, const std::string & bgName, const CFunctionList & CB); - CTextInput(const Rect & Pos, SDL_Surface * srf); + CTextInput(const Rect & Pos, std::shared_ptr srf); void clickLeft(tribool down, bool previousState) override; void keyPressed(const SDL_KeyboardEvent & key) override; diff --git a/client/windows/CWindowObject.cpp b/client/windows/CWindowObject.cpp index 48a3495f0..c818400c6 100644 --- a/client/windows/CWindowObject.cpp +++ b/client/windows/CWindowObject.cpp @@ -19,6 +19,7 @@ #include "../gui/SDL_Extensions.h" #include "../gui/CGuiHandler.h" #include "../gui/CursorHandler.h" +#include "../gui/CAnimation.h" #include "../battle/BattleInterface.h" #include "../battle/BattleInterfaceClasses.h" @@ -213,9 +214,9 @@ void CWindowObject::setShadow(bool on) { OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - shadowParts.push_back(std::make_shared(shadowCorner, Point(shadowPos.x, shadowPos.y))); - shadowParts.push_back(std::make_shared(shadowRight, Point(shadowPos.x, shadowStart.y))); - shadowParts.push_back(std::make_shared(shadowBottom, Point(shadowStart.x, shadowPos.y))); + shadowParts.push_back(std::make_shared( IImage::createFromSurface(shadowCorner), Point(shadowPos.x, shadowPos.y))); + shadowParts.push_back(std::make_shared( IImage::createFromSurface(shadowRight ), Point(shadowPos.x, shadowStart.y))); + shadowParts.push_back(std::make_shared( IImage::createFromSurface(shadowBottom), Point(shadowStart.x, shadowPos.y))); } SDL_FreeSurface(shadowCorner); From e14290fde07206c0559e50926f132dd92766269f Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Mon, 30 Jan 2023 18:25:47 +0200 Subject: [PATCH 31/79] Removed loading of images from file into SDL_Surface --- client/CMessage.cpp | 12 ++--- client/battle/BattleStacksController.cpp | 8 ++-- client/battle/CreatureAnimation.cpp | 2 +- client/gui/CAnimation.cpp | 8 ++-- client/gui/CAnimation.h | 2 +- client/gui/SDL_Extensions.cpp | 20 -------- client/gui/SDL_Extensions.h | 2 - client/mapHandler.cpp | 12 ++--- client/widgets/AdventureMapClasses.cpp | 21 ++++----- client/widgets/AdventureMapClasses.h | 8 ++-- client/widgets/Images.cpp | 14 +++--- client/widgets/Images.h | 4 +- client/windows/CAdvmapInterface.cpp | 15 ++---- client/windows/CAdvmapInterface.h | 5 +- client/windows/CCastleInterface.cpp | 58 ++++++++++-------------- client/windows/CCastleInterface.h | 5 +- 16 files changed, 75 insertions(+), 121 deletions(-) diff --git a/client/CMessage.cpp b/client/CMessage.cpp index ce670af5e..01d42cb97 100644 --- a/client/CMessage.cpp +++ b/client/CMessage.cpp @@ -64,7 +64,7 @@ namespace std::array, PlayerColor::PLAYER_LIMIT_I> dialogBorders; std::array>, PlayerColor::PLAYER_LIMIT_I> piecesOfBox; - SDL_Surface * background = nullptr;//todo: should be CFilledTexture + std::shared_ptr background;//todo: should be CFilledTexture } void CMessage::init() @@ -84,27 +84,27 @@ void CMessage::init() } } - background = BitmapHandler::loadBitmap("DIBOXBCK.BMP"); + background = IImage::createFromFile("DIBOXBCK.BMP"); } void CMessage::dispose() { for(auto & item : dialogBorders) item.reset(); - SDL_FreeSurface(background); } SDL_Surface * CMessage::drawDialogBox(int w, int h, PlayerColor playerColor) { //prepare surface SDL_Surface * ret = CSDL_Ext::newSurface(w,h); - for (int i=0; iw)//background + for (int i=0; iwidth())//background { - for (int j=0; jh) + for (int j=0; jheight()) { - CSDL_Ext::blitSurface(background, ret, Point(i,j)); + background->draw(ret, i, j); } } + drawBorder(playerColor, ret, w, h); return ret; } diff --git a/client/battle/BattleStacksController.cpp b/client/battle/BattleStacksController.cpp index b25861676..369554ed1 100644 --- a/client/battle/BattleStacksController.cpp +++ b/client/battle/BattleStacksController.cpp @@ -89,10 +89,10 @@ BattleStacksController::BattleStacksController(BattleInterface & owner): static const auto shifterNegative = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 1.0f, 0.2f, 0.2f ); static const auto shifterNeutral = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 1.0f, 1.0f, 0.2f ); - amountNormal->adjustPalette(shifterNormal); - amountPositive->adjustPalette(shifterPositive); - amountNegative->adjustPalette(shifterNegative); - amountEffNeutral->adjustPalette(shifterNeutral); + amountNormal->adjustPalette(shifterNormal, 0); + amountPositive->adjustPalette(shifterPositive, 0); + amountNegative->adjustPalette(shifterNegative, 0); + amountEffNeutral->adjustPalette(shifterNeutral, 0); //Restore border color {255, 231, 132, 255} to its original state amountNormal->resetPalette(26); diff --git a/client/battle/CreatureAnimation.cpp b/client/battle/CreatureAnimation.cpp index 0dda6089a..c5d7abbc0 100644 --- a/client/battle/CreatureAnimation.cpp +++ b/client/battle/CreatureAnimation.cpp @@ -345,7 +345,7 @@ void CreatureAnimation::nextFrame(Canvas & canvas, const ColorFilter & shifter, genSpecialPalette(SpecialPalette); image->setSpecialPallete(SpecialPalette); - image->adjustPalette(shifter); + image->adjustPalette(shifter, 8); canvas.draw(image, pos.topLeft(), Rect(0, 0, pos.w, pos.h)); diff --git a/client/gui/CAnimation.cpp b/client/gui/CAnimation.cpp index 9bb926adf..efaea8da1 100644 --- a/client/gui/CAnimation.cpp +++ b/client/gui/CAnimation.cpp @@ -108,7 +108,7 @@ public: void verticalFlip() override; void shiftPalette(int from, int howMany) override; - void adjustPalette(const ColorFilter & shifter) override; + void adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) override; void resetPalette(int colorID) override; void resetPalette() override; @@ -807,15 +807,15 @@ void SDLImage::shiftPalette(int from, int howMany) } } -void SDLImage::adjustPalette(const ColorFilter & shifter) +void SDLImage::adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) { if(originalPalette == nullptr) return; SDL_Palette* palette = surf->format->palette; - // Note: here we skip the first 8 colors in the palette that predefined in H3Palette - for(int i = 8; i < palette->ncolors; i++) + // Note: here we skip first colors in the palette that are predefined in H3 images + for(int i = colorsToSkip; i < palette->ncolors; i++) { palette->colors[i] = shifter.shiftColor(originalPalette->colors[i]); } diff --git a/client/gui/CAnimation.h b/client/gui/CAnimation.h index 58894e80b..e5881c65f 100644 --- a/client/gui/CAnimation.h +++ b/client/gui/CAnimation.h @@ -63,7 +63,7 @@ public: //only indexed bitmaps, 16 colors maximum virtual void shiftPalette(int from, int howMany) = 0; - virtual void adjustPalette(const ColorFilter & shifter) = 0; + virtual void adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) = 0; virtual void resetPalette(int colorID) = 0; virtual void resetPalette() = 0; diff --git a/client/gui/SDL_Extensions.cpp b/client/gui/SDL_Extensions.cpp index f1efad669..abfc10d17 100644 --- a/client/gui/SDL_Extensions.cpp +++ b/client/gui/SDL_Extensions.cpp @@ -880,26 +880,6 @@ void CSDL_Ext::fillRect( SDL_Surface *dst, const Rect & dstrect, const SDL_Color SDL_FillRect(dst, &newRect, sdlColor); } -void CSDL_Ext::fillTexture(SDL_Surface *dst, SDL_Surface * src) -{ - SDL_Rect srcRect; - SDL_Rect dstRect; - - SDL_GetClipRect(src, &srcRect); - SDL_GetClipRect(dst, &dstRect); - - for (int y=dstRect.y; y < dstRect.y + dstRect.h; y+=srcRect.h) - { - for (int x=dstRect.x; x < dstRect.x + dstRect.w; x+=srcRect.w) - { - int xLeft = std::min(srcRect.w, dstRect.x + dstRect.w - x); - int yLeft = std::min(srcRect.h, dstRect.y + dstRect.h - y); - SDL_Rect currentDest{x, y, xLeft, yLeft}; - SDL_BlitSurface(src, &srcRect, dst, ¤tDest); - } - } -} - SDL_Color CSDL_Ext::makeColor(ui8 r, ui8 g, ui8 b, ui8 a) { SDL_Color ret = {r, g, b, a}; diff --git a/client/gui/SDL_Extensions.h b/client/gui/SDL_Extensions.h index 4dbec2382..b63ab8fef 100644 --- a/client/gui/SDL_Extensions.h +++ b/client/gui/SDL_Extensions.h @@ -128,8 +128,6 @@ typedef void (*TColorPutterAlpha)(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, void fillSurface(SDL_Surface *dst, const SDL_Color & color); void fillRect(SDL_Surface *dst, const Rect & dstrect, const SDL_Color & color); - //fill dest image with source texture. - void fillTexture(SDL_Surface *dst, SDL_Surface * sourceTexture); void updateRect(SDL_Surface *surface, const Rect & rect); diff --git a/client/mapHandler.cpp b/client/mapHandler.cpp index 2d1a4a6e7..3c0c053f9 100644 --- a/client/mapHandler.cpp +++ b/client/mapHandler.cpp @@ -899,22 +899,22 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn { if(parent->map->getTile(int3(pos.x, pos.y, pos.z)).blocked) //temporary hiding blocked positions { - static SDL_Surface * block = nullptr; + static std::shared_ptr block; if (!block) - block = BitmapHandler::loadBitmap("blocked"); + block = IImage::createFromFile("blocked"); - CSDL_Ext::blitSurface(block, targetSurf, realTileRect.topLeft()); + block->draw(targetSurf, realTileRect.x, realTileRect.y); } } if (settings["session"]["showVisit"].Bool()) { if(parent->map->getTile(int3(pos.x, pos.y, pos.z)).visitable) //temporary hiding visitable positions { - static SDL_Surface * visit = nullptr; + static std::shared_ptr visit; if (!visit) - visit = BitmapHandler::loadBitmap("visitable"); + visit = IImage::createFromFile("visitable"); - CSDL_Ext::blitSurface(visit, targetSurf, realTileRect.topLeft()); + visit->draw(targetSurf, realTileRect.x, realTileRect.y); } } } diff --git a/client/widgets/AdventureMapClasses.cpp b/client/widgets/AdventureMapClasses.cpp index a9f269ff3..6a6fd19bd 100644 --- a/client/widgets/AdventureMapClasses.cpp +++ b/client/widgets/AdventureMapClasses.cpp @@ -23,6 +23,7 @@ #include "../gui/CGuiHandler.h" #include "../gui/SDL_Pixels.h" +#include "../gui/CAnimation.h" #include "../windows/InfoWindows.h" #include "../windows/CAdvmapInterface.h" @@ -1168,9 +1169,9 @@ void CInGameConsole::refreshEnteredText() statusbar->setEnteredText(enteredText); } -CAdvMapPanel::CAdvMapPanel(SDL_Surface * bg, Point position) - : CIntObject(), - background(bg) +CAdvMapPanel::CAdvMapPanel(std::shared_ptr bg, Point position) + : CIntObject() + , background(bg) { defActions = 255; recActions = 255; @@ -1178,17 +1179,11 @@ CAdvMapPanel::CAdvMapPanel(SDL_Surface * bg, Point position) pos.y += position.y; if (bg) { - pos.w = bg->w; - pos.h = bg->h; + pos.w = bg->width(); + pos.h = bg->height(); } } -CAdvMapPanel::~CAdvMapPanel() -{ - if (background) - SDL_FreeSurface(background); -} - void CAdvMapPanel::addChildColorableButton(std::shared_ptr button) { colorableButtons.push_back(button); @@ -1206,7 +1201,7 @@ void CAdvMapPanel::setPlayerColor(const PlayerColor & clr) void CAdvMapPanel::showAll(SDL_Surface * to) { if(background) - CSDL_Ext::blitAt(background, pos.x, pos.y, to); + background->draw(to, pos.x, pos.y); CIntObject::showAll(to); } @@ -1219,7 +1214,7 @@ void CAdvMapPanel::addChildToPanel(std::shared_ptr obj, ui8 actions) addChild(obj.get(), false); } -CAdvMapWorldViewPanel::CAdvMapWorldViewPanel(std::shared_ptr _icons, SDL_Surface * bg, Point position, int spaceBottom, const PlayerColor &color) +CAdvMapWorldViewPanel::CAdvMapWorldViewPanel(std::shared_ptr _icons, std::shared_ptr bg, Point position, int spaceBottom, const PlayerColor &color) : CAdvMapPanel(bg, position), icons(_icons) { OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); diff --git a/client/widgets/AdventureMapClasses.h b/client/widgets/AdventureMapClasses.h index 921f5ca1e..81bc9727f 100644 --- a/client/widgets/AdventureMapClasses.h +++ b/client/widgets/AdventureMapClasses.h @@ -35,6 +35,7 @@ class CComponent; class CHeroTooltip; class CTownTooltip; class CTextBox; +class IImage; /// Base UI Element for hero\town lists class CList : public CIntObject @@ -370,10 +371,9 @@ class CAdvMapPanel : public CIntObject std::vector> colorableButtons; std::vector> otherObjects; /// the surface passed to this obj will be freed in dtor - SDL_Surface * background; + std::shared_ptr background; public: - CAdvMapPanel(SDL_Surface * bg, Point position); - virtual ~CAdvMapPanel(); + CAdvMapPanel(std::shared_ptr bg, Point position); void addChildToPanel(std::shared_ptr obj, ui8 actions = 0); void addChildColorableButton(std::shared_ptr button); @@ -394,7 +394,7 @@ class CAdvMapWorldViewPanel : public CAdvMapPanel std::shared_ptr backgroundFiller; std::shared_ptr icons; public: - CAdvMapWorldViewPanel(std::shared_ptr _icons, SDL_Surface * bg, Point position, int spaceBottom, const PlayerColor &color); + CAdvMapWorldViewPanel(std::shared_ptr _icons, std::shared_ptr bg, Point position, int spaceBottom, const PlayerColor &color); virtual ~CAdvMapWorldViewPanel(); void addChildIcon(std::pair data, int indexOffset); diff --git a/client/widgets/Images.cpp b/client/widgets/Images.cpp index 445069d16..4e2f32652 100644 --- a/client/widgets/Images.cpp +++ b/client/widgets/Images.cpp @@ -113,21 +113,21 @@ void CPicture::colorize(PlayerColor player) CFilledTexture::CFilledTexture(std::string imageName, Rect position): CIntObject(0, position.topLeft()), - texture(BitmapHandler::loadBitmap(imageName)) + texture(IImage::createFromFile(imageName)) { pos.w = position.w; pos.h = position.h; } -CFilledTexture::~CFilledTexture() -{ - SDL_FreeSurface(texture); -} - void CFilledTexture::showAll(SDL_Surface *to) { CSDL_Ext::CClipRectGuard guard(to, pos); - CSDL_Ext::fillTexture(to, texture); + + for (int y=pos.top(); y < pos.bottom(); y+= texture->height()) + { + for (int x=pos.left(); x < pos.right(); x+=texture->width()) + texture->draw(to, x, y); + } } CAnimImage::CAnimImage(const std::string & name, size_t Frame, size_t Group, int x, int y, ui8 Flags): diff --git a/client/widgets/Images.h b/client/widgets/Images.h index 1ac5bbce5..be23dfec9 100644 --- a/client/widgets/Images.h +++ b/client/widgets/Images.h @@ -68,11 +68,11 @@ public: /// area filled with specific texture class CFilledTexture : public CIntObject { - SDL_Surface * texture; + std::shared_ptr texture; public: CFilledTexture(std::string imageName, Rect position); - ~CFilledTexture(); + void showAll(SDL_Surface *to) override; }; diff --git a/client/windows/CAdvmapInterface.cpp b/client/windows/CAdvmapInterface.cpp index ba1085b4d..0b76b654a 100644 --- a/client/windows/CAdvmapInterface.cpp +++ b/client/windows/CAdvmapInterface.cpp @@ -566,10 +566,10 @@ CAdvMapInt::CAdvMapInt(): pos.h = screen->h; strongInterest = true; // handle all mouse move events to prevent dead mouse move space in fullscreen mode townList.onSelect = std::bind(&CAdvMapInt::selectionChanged,this); - bg = BitmapHandler::loadBitmap(ADVOPT.mainGraphic); + bg = IImage::createFromFile(ADVOPT.mainGraphic); if(!ADVOPT.worldViewGraphic.empty()) { - bgWorldView = BitmapHandler::loadBitmap(ADVOPT.worldViewGraphic); + bgWorldView = IImage::createFromFile(ADVOPT.worldViewGraphic); } else { @@ -579,7 +579,7 @@ CAdvMapInt::CAdvMapInt(): if (!bgWorldView) { logGlobal->warn("bgWorldView not defined in resolution config; fallback to VWorld.bmp"); - bgWorldView = BitmapHandler::loadBitmap("VWorld.bmp"); + bgWorldView = IImage::createFromFile("VWorld.bmp"); } worldViewIcons = std::make_shared("VwSymbol");//todo: customize with ADVOPT @@ -712,11 +712,6 @@ CAdvMapInt::CAdvMapInt(): addUsedEvents(MOVE); } -CAdvMapInt::~CAdvMapInt() -{ - SDL_FreeSurface(bg); -} - void CAdvMapInt::fshowOverview() { GH.pushIntT(); @@ -976,7 +971,7 @@ void CAdvMapInt::deactivate() void CAdvMapInt::showAll(SDL_Surface * to) { - blitAt(bg,0,0,to); + bg->draw(to, 0, 0); if(state != INGAME) return; @@ -1507,7 +1502,7 @@ void CAdvMapInt::startHotSeatWait(PlayerColor Player) void CAdvMapInt::setPlayer(PlayerColor Player) { player = Player; - graphics->blueToPlayersAdv(bg,player); + bg->playerColored(player); panelMain->setPlayerColor(player); panelWorldView->setPlayerColor(player); diff --git a/client/windows/CAdvmapInterface.h b/client/windows/CAdvmapInterface.h index b605137ba..6b1ae0ddc 100644 --- a/client/windows/CAdvmapInterface.h +++ b/client/windows/CAdvmapInterface.h @@ -132,7 +132,6 @@ class CAdvMapInt : public CIntObject public: CAdvMapInt(); - ~CAdvMapInt(); int3 position; //top left corner of visible map part PlayerColor player; @@ -170,8 +169,8 @@ public: WorldViewOptions worldViewOptions; - SDL_Surface * bg; - SDL_Surface * bgWorldView; + std::shared_ptr bg; + std::shared_ptr bgWorldView; std::vector> gems; CMinimap minimap; std::shared_ptr statusbar; diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index 19e40fc21..f3d397bcf 100644 --- a/client/windows/CCastleInterface.cpp +++ b/client/windows/CCastleInterface.cpp @@ -24,6 +24,8 @@ #include "../CPlayerInterface.h" #include "../Graphics.h" #include "../gui/CGuiHandler.h" +#include "../gui/CAnimation.h" +#include "../gui/ColorFilter.h" #include "../gui/SDL_Extensions.h" #include "../widgets/MiscWidgets.h" #include "../widgets/CComponent.h" @@ -68,24 +70,16 @@ CBuildingRect::CBuildingRect(CCastleBuildings * Par, const CGTownInstance * Town } if(!str->borderName.empty()) - border = BitmapHandler::loadBitmap(str->borderName); + border = IImage::createFromFile(str->borderName); else border = nullptr; if(!str->areaName.empty()) - area = BitmapHandler::loadBitmap(str->areaName); + area = IImage::createFromFile(str->areaName); else area = nullptr; } -CBuildingRect::~CBuildingRect() -{ - if(border) - SDL_FreeSurface(border); - if(area) - SDL_FreeSurface(area); -} - const CBuilding * CBuildingRect::getBuilding() { if (!str->building) @@ -127,7 +121,7 @@ void CBuildingRect::clickLeft(tribool down, bool previousState) { if(previousState && getBuilding() && area && !down && (parent->selectedBuilding==this)) { - if(!CSDL_Ext::isTransparent(area, GH.getCursorPosition() - pos.topLeft())) //inside building image + if(!area->isTransparent(GH.getCursorPosition() - pos.topLeft())) //inside building image { auto building = getBuilding(); parent->buildingClicked(building->bid, building->subId, building->upgrade); @@ -139,7 +133,7 @@ void CBuildingRect::clickRight(tribool down, bool previousState) { if((!area) || (!((bool)down)) || (this!=parent->selectedBuilding) || getBuilding() == nullptr) return; - if( !CSDL_Ext::isTransparent(area, GH.getCursorPosition() - pos.topLeft()) ) //inside building image + if( !area->isTransparent(GH.getCursorPosition() - pos.topLeft()) ) //inside building image { BuildingID bid = getBuilding()->bid; const CBuilding *bld = town->town->buildings.at(bid); @@ -186,33 +180,27 @@ void CBuildingRect::show(SDL_Surface * to) if(stateTimeCounter >= BUILD_ANIMATION_FINISHED_TIMEPOINT) { if(parent->selectedBuilding == this) - blitAtLoc(border,0,0,to); + border->draw(to, pos.x, pos.y); return; } - if(border->format->palette != nullptr) - { - // key colors in glowing border - SDL_Color c1 = {200, 200, 200, 255}; // x2 - SDL_Color c2 = {120, 100, 60, 255}; // x0.5 - SDL_Color c3 = {210, 180, 110, 255}; // x1 - ui32 colorID = SDL_MapRGB(border->format, c3.r, c3.g, c3.b); - SDL_Color oldColor = border->format->palette->colors[colorID]; - SDL_Color newColor; + auto darkBorder = ColorFilter::genRangeShifter(0.f, 0.f, 0.f, 0.5f, 0.5f, 0.5f ); + auto lightBorder = ColorFilter::genRangeShifter(0.f, 0.f, 0.f, 2.0f, 2.0f, 2.0f ); + auto baseBorder = ColorFilter::genEmptyShifter(); - if (stateTimeCounter < BUILDING_WHITE_BORDER_TIMEPOINT) - newColor = multiplyColors(c1, c2, static_cast(stateTimeCounter % stageDelay) / stageDelay); - else - if (stateTimeCounter < BUILDING_YELLOW_BORDER_TIMEPOINT) - newColor = multiplyColors(c2, c3, static_cast(stateTimeCounter % stageDelay) / stageDelay); - else - newColor = oldColor; + float progress = float(stateTimeCounter % stageDelay) / stageDelay; - CSDL_Ext::setColors(border, &newColor, colorID, 1); - blitAtLoc(border, 0, 0, to); - CSDL_Ext::setColors(border, &oldColor, colorID, 1); - } + if (stateTimeCounter < BUILDING_WHITE_BORDER_TIMEPOINT) + border->adjustPalette(ColorFilter::genInterpolated(lightBorder, darkBorder, progress), 0); + else + if (stateTimeCounter < BUILDING_YELLOW_BORDER_TIMEPOINT) + border->adjustPalette(ColorFilter::genInterpolated(darkBorder, baseBorder, progress), 0); + else + border->adjustPalette(baseBorder, 0); + + border->draw(to, pos.x, pos.y); } + if(stateTimeCounter < BUILD_ANIMATION_FINISHED_TIMEPOINT) stateTimeCounter += GH.mainFPSmng->getElapsedMilliseconds(); } @@ -224,7 +212,7 @@ void CBuildingRect::showAll(SDL_Surface * to) CShowableAnim::showAll(to); if(!active && parent->selectedBuilding == this && border) - blitAtLoc(border,0,0,to); + border->draw(to, pos.x, pos.y); } std::string CBuildingRect::getSubtitle()//hover text for building @@ -256,7 +244,7 @@ void CBuildingRect::mouseMoved (const SDL_MouseMotionEvent & sEvent) { if(area && pos.isInside(sEvent.x, sEvent.y)) { - if(CSDL_Ext::isTransparent(area, GH.getCursorPosition() - pos.topLeft())) //hovered pixel is inside this building + if(area->isTransparent(GH.getCursorPosition() - pos.topLeft())) //hovered pixel is inside this building { if(parent->selectedBuilding == this) { diff --git a/client/windows/CCastleInterface.h b/client/windows/CCastleInterface.h index 6b9f7f7e8..5cb817058 100644 --- a/client/windows/CCastleInterface.h +++ b/client/windows/CCastleInterface.h @@ -56,13 +56,12 @@ public: CCastleBuildings * parent; const CGTownInstance * town; const CStructure* str; - SDL_Surface* border; - SDL_Surface* area; + std::shared_ptr border; + std::shared_ptr area; ui32 stateTimeCounter;//For building construction - current stage in animation CBuildingRect(CCastleBuildings * Par, const CGTownInstance *Town, const CStructure *Str); - ~CBuildingRect(); bool operator<(const CBuildingRect & p2) const; void hover(bool on) override; void clickLeft(tribool down, bool previousState) override; From 57df0a699584ebbabc39a6ca86cf5297589af21c Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Mon, 30 Jan 2023 19:00:51 +0200 Subject: [PATCH 32/79] Fix crash on hovering prison --- lib/mapObjects/CGHeroInstance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index a97d4a6a3..70daaf19d 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -472,7 +472,7 @@ std::string CGHeroInstance::getObjectName() const return hoverName; } else - return CGObjectInstance::getObjectName(); + return VLC->objtypeh->getObjectName(ID, 0); } ui8 CGHeroInstance::maxlevelsToMagicSchool() const From 9c3030603d862adf449c993e5d4c66e50a928ccf Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Mon, 30 Jan 2023 19:55:32 +0200 Subject: [PATCH 33/79] Removed most SDL includes from headers, removed SDL int's --- client/CMT.cpp | 4 +- client/CMakeLists.txt | 1 - client/CMessage.cpp | 2 + client/CPlayerInterface.cpp | 1 + client/CServerHandler.cpp | 2 + client/CVideoHandler.cpp | 1 + client/ClientCommandManager.cpp | 2 + client/StdInc.h | 2 - client/battle/BattleInterfaceClasses.cpp | 3 + client/battle/BattleWindow.cpp | 3 + client/battle/CreatureAnimation.h | 2 +- client/gui/CAnimation.cpp | 2 + client/gui/CGuiHandler.cpp | 5 +- client/gui/CGuiHandler.h | 4 +- client/gui/CIntObject.cpp | 2 + client/gui/CursorHandler.cpp | 1 + client/gui/Fonts.cpp | 16 ++-- client/gui/SDL_Compat.h | 25 ------- client/gui/SDL_Extensions.cpp | 66 ++++++++--------- client/gui/SDL_Extensions.h | 16 ++-- client/gui/SDL_Pixels.h | 93 ++++++++++++------------ client/lobby/CSelectionBase.cpp | 2 + client/lobby/SelectionTab.cpp | 1 + client/mainmenu/CMainMenu.cpp | 1 + client/widgets/AdventureMapClasses.cpp | 14 ++-- client/widgets/AdventureMapClasses.h | 2 +- client/widgets/Buttons.cpp | 2 + client/widgets/Buttons.h | 2 + client/widgets/CGarrisonInt.cpp | 4 +- client/widgets/TextControls.cpp | 2 + client/widgets/TextControls.h | 2 + client/windows/CAdvmapInterface.cpp | 3 + client/windows/CCastleInterface.cpp | 10 ++- client/windows/CSpellWindow.cpp | 2 + client/windows/CSpellWindow.h | 2 +- client/windows/CWindowObject.cpp | 6 +- client/windows/GUIClasses.cpp | 2 + client/windows/InfoWindows.cpp | 2 + 38 files changed, 168 insertions(+), 144 deletions(-) delete mode 100644 client/gui/SDL_Compat.h diff --git a/client/CMT.cpp b/client/CMT.cpp index 58a171592..5eb2f6b9a 100644 --- a/client/CMT.cpp +++ b/client/CMT.cpp @@ -713,7 +713,7 @@ static bool recreateWindow(int w, int h, int bpp, bool fullscreen, int displayIn if(nullptr == mainWindow) { #if defined(VCMI_ANDROID) || defined(VCMI_IOS) - auto createWindow = [displayIndex](Uint32 extraFlags) -> bool { + auto createWindow = [displayIndex](uint32_t extraFlags) -> bool { mainWindow = SDL_CreateWindow(NAME.c_str(), SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex), SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex), 0, 0, SDL_WINDOW_FULLSCREEN | extraFlags); return mainWindow != nullptr; }; @@ -723,7 +723,7 @@ static bool recreateWindow(int w, int h, int bpp, bool fullscreen, int displayIn SDL_SetHint(SDL_HINT_RETURN_KEY_HIDES_IME, "1"); SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); - Uint32 windowFlags = SDL_WINDOW_BORDERLESS | SDL_WINDOW_ALLOW_HIGHDPI; + uint32_t windowFlags = SDL_WINDOW_BORDERLESS | SDL_WINDOW_ALLOW_HIGHDPI; if(!createWindow(windowFlags | SDL_WINDOW_METAL)) { logGlobal->warn("Metal unavailable, using OpenGLES"); diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 8eb0f16e5..f9404f59d 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -110,7 +110,6 @@ set(client_HEADERS gui/CIntObject.h gui/Fonts.h gui/TextAlignment.h - gui/SDL_Compat.h gui/SDL_Extensions.h gui/SDL_Pixels.h gui/NotificationHandler.h diff --git a/client/CMessage.cpp b/client/CMessage.cpp index 01d42cb97..9559045be 100644 --- a/client/CMessage.cpp +++ b/client/CMessage.cpp @@ -22,6 +22,8 @@ #include "widgets/Buttons.h" #include "widgets/TextControls.h" +#include + const int BETWEEN_COMPS_ROWS = 10; const int BEFORE_COMPONENTS = 30; const int BETWEEN_COMPS = 30; diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index bb7cbd2e7..17689f6e0 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -68,6 +68,7 @@ #include "../lib/CGameState.h" #include "gui/NotificationHandler.h" +#include // The macro below is used to mark functions that are called by client when game state changes. // They all assume that CPlayerInterface::pim mutex is locked. diff --git a/client/CServerHandler.cpp b/client/CServerHandler.cpp index bf20cee36..1f1836119 100644 --- a/client/CServerHandler.cpp +++ b/client/CServerHandler.cpp @@ -60,6 +60,8 @@ #include #endif +#include + template class CApplyOnLobby; const std::string CServerHandler::localhostAddress{"127.0.0.1"}; diff --git a/client/CVideoHandler.cpp b/client/CVideoHandler.cpp index 8d3d37ad5..177754ccc 100644 --- a/client/CVideoHandler.cpp +++ b/client/CVideoHandler.cpp @@ -16,6 +16,7 @@ #include "../lib/filesystem/Filesystem.h" #include +#include extern CGuiHandler GH; //global gui handler diff --git a/client/ClientCommandManager.cpp b/client/ClientCommandManager.cpp index 1e8c9f30f..0fb190826 100644 --- a/client/ClientCommandManager.cpp +++ b/client/ClientCommandManager.cpp @@ -33,6 +33,8 @@ #include "../lib/ScriptHandler.h" #endif +#include + void ClientCommandManager::handleGoSolo() { Settings session = settings.write["session"]; diff --git a/client/StdInc.h b/client/StdInc.h index 8e35b9a2d..1f4e8bafc 100644 --- a/client/StdInc.h +++ b/client/StdInc.h @@ -2,8 +2,6 @@ #include "../Global.h" -#include "gui/SDL_Compat.h" - // This header should be treated as a pre compiled header file(PCH) in the compiler building settings. // Here you can add specific libraries and macros which are specific to this project. diff --git a/client/battle/BattleInterfaceClasses.cpp b/client/battle/BattleInterfaceClasses.cpp index 5c5031ef7..0cc04e03a 100644 --- a/client/battle/BattleInterfaceClasses.cpp +++ b/client/battle/BattleInterfaceClasses.cpp @@ -48,6 +48,9 @@ #include "../../lib/CondSh.h" #include "../../lib/mapObjects/CGTownInstance.h" +#include +#include + void BattleConsole::showAll(SDL_Surface * to) { CIntObject::showAll(to); diff --git a/client/battle/BattleWindow.cpp b/client/battle/BattleWindow.cpp index f47a559ac..7c711ef8c 100644 --- a/client/battle/BattleWindow.cpp +++ b/client/battle/BattleWindow.cpp @@ -36,6 +36,9 @@ #include "../../lib/CConfigHandler.h" #include "../../lib/filesystem/ResourceID.h" +#include +#include + BattleWindow::BattleWindow(BattleInterface & owner): owner(owner) { diff --git a/client/battle/CreatureAnimation.h b/client/battle/CreatureAnimation.h index 482b12b87..d9858aae8 100644 --- a/client/battle/CreatureAnimation.h +++ b/client/battle/CreatureAnimation.h @@ -13,7 +13,7 @@ #include "../widgets/Images.h" #include "../gui/CAnimation.h" -#include +#include class CIntObject; class CreatureAnimation; diff --git a/client/gui/CAnimation.cpp b/client/gui/CAnimation.cpp index efaea8da1..589e300e8 100644 --- a/client/gui/CAnimation.cpp +++ b/client/gui/CAnimation.cpp @@ -23,6 +23,8 @@ #include "../../lib/CRandomGenerator.h" #include "../../lib/vcmi_endian.h" +#include + class SDLImageLoader; typedef std::map > source_map; diff --git a/client/gui/CGuiHandler.cpp b/client/gui/CGuiHandler.cpp index a2ea6c00a..12bfe6ed0 100644 --- a/client/gui/CGuiHandler.cpp +++ b/client/gui/CGuiHandler.cpp @@ -24,6 +24,7 @@ #include #include +#include extern std::queue SDLEventsQueue; extern boost::mutex eventsM; @@ -643,7 +644,7 @@ const Point & CGuiHandler::getCursorPosition() const void CGuiHandler::drawFPSCounter() { static SDL_Rect overlay = { 0, 0, 64, 32}; - Uint32 black = SDL_MapRGB(screen->format, 10, 10, 10); + uint32_t black = SDL_MapRGB(screen->format, 10, 10, 10); SDL_FillRect(screen, &overlay, black); std::string fps = boost::lexical_cast(mainFPSmng->fps); graphics->fonts[FONT_BIG]->renderTextLeft(screen, fps, Colors::YELLOW, Point(10, 10)); @@ -751,7 +752,7 @@ void CFramerateManager::framerateDelay() // FPS is higher than it should be, then wait some time if(timeElapsed < rateticks) { - int timeToSleep = (Uint32)ceil(this->rateticks) - timeElapsed; + int timeToSleep = (uint32_t)ceil(this->rateticks) - timeElapsed; boost::this_thread::sleep(boost::posix_time::milliseconds(timeToSleep)); } diff --git a/client/gui/CGuiHandler.h b/client/gui/CGuiHandler.h index f5133ac01..ae4220008 100644 --- a/client/gui/CGuiHandler.h +++ b/client/gui/CGuiHandler.h @@ -10,8 +10,7 @@ #pragma once #include "../../lib/Point.h" - -#include +#include "SDL_keycode.h" VCMI_LIB_NAMESPACE_BEGIN @@ -20,6 +19,7 @@ template struct CondSh; VCMI_LIB_NAMESPACE_END union SDL_Event; +struct SDL_MouseMotionEvent; class CFramerateManager; class IStatusBar; diff --git a/client/gui/CIntObject.cpp b/client/gui/CIntObject.cpp index 07b97286e..9a1c00794 100644 --- a/client/gui/CIntObject.cpp +++ b/client/gui/CIntObject.cpp @@ -15,6 +15,8 @@ #include "../CMessage.h" #include +#include +#include IShowActivatable::IShowActivatable() { diff --git a/client/gui/CursorHandler.cpp b/client/gui/CursorHandler.cpp index b7392ff14..e15203fed 100644 --- a/client/gui/CursorHandler.cpp +++ b/client/gui/CursorHandler.cpp @@ -17,6 +17,7 @@ #include "../../lib/CConfigHandler.h" #include +#include #ifdef VCMI_APPLE #include diff --git a/client/gui/Fonts.cpp b/client/gui/Fonts.cpp index 6b46818c1..adc843b79 100644 --- a/client/gui/Fonts.cpp +++ b/client/gui/Fonts.cpp @@ -136,7 +136,7 @@ void CBitmapFont::renderCharacter(SDL_Surface * surface, const BitmapChar & char CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface, 0); - Uint8 bpp = surface->format->BytesPerPixel; + uint8_t bpp = surface->format->BytesPerPixel; // start of line, may differ from 0 due to end of surface or clipped surface int lineBegin = std::max(0, clipRect.y - posY); @@ -149,8 +149,8 @@ void CBitmapFont::renderCharacter(SDL_Surface * surface, const BitmapChar & char //for each line in symbol for(int dy = lineBegin; dy pixels; - Uint8 *srcLine = character.pixels; + uint8_t *dstLine = (uint8_t*)surface->pixels; + uint8_t *srcLine = character.pixels; // shift source\destination pixels to current position dstLine += (posY+dy) * surface->pitch + posX * bpp; @@ -159,7 +159,7 @@ void CBitmapFont::renderCharacter(SDL_Surface * surface, const BitmapChar & char //for each column in line for(int dx = rowBegin; dx < rowEnd; dx++) { - Uint8* dstPixel = dstLine + dx*bpp; + uint8_t* dstPixel = dstLine + dx*bpp; switch(srcLine[dx]) { case 1: //black "shadow" @@ -307,7 +307,7 @@ void CBitmapHanFont::renderCharacter(SDL_Surface * surface, int characterIndex, CSDL_Ext::getClipRect(surface, clipRect); CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface, 0); - Uint8 bpp = surface->format->BytesPerPixel; + uint8_t bpp = surface->format->BytesPerPixel; // start of line, may differ from 0 due to end of surface or clipped surface int lineBegin = std::max(0, clipRect.y - posY); @@ -320,8 +320,8 @@ void CBitmapHanFont::renderCharacter(SDL_Surface * surface, int characterIndex, //for each line in symbol for(int dy = lineBegin; dy pixels; - Uint8 *source = data.first.get() + getCharacterDataOffset(characterIndex); + uint8_t *dstLine = (uint8_t*)surface->pixels; + uint8_t *source = data.first.get() + getCharacterDataOffset(characterIndex); // shift source\destination pixels to current position dstLine += (posY+dy) * surface->pitch + posX * bpp; @@ -333,7 +333,7 @@ void CBitmapHanFont::renderCharacter(SDL_Surface * surface, int characterIndex, // select current bit in bitmap int bit = (source[dx / 8] << (dx % 8)) & 0x80; - Uint8* dstPixel = dstLine + dx*bpp; + uint8_t* dstPixel = dstLine + dx*bpp; if (bit != 0) colorPutter(dstPixel, color.r, color.g, color.b); } diff --git a/client/gui/SDL_Compat.h b/client/gui/SDL_Compat.h deleted file mode 100644 index 79c7d37d2..000000000 --- a/client/gui/SDL_Compat.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SDL_Compat.h, part of VCMI engine - * - * Authors: listed in file AUTHORS in main folder - * - * License: GNU General Public License v2.0 or later - * Full text of license available in license.txt file, in main folder - * - */ -#pragma once - -#include - -#if (SDL_MAJOR_VERSION == 2) - -#include -typedef int SDLX_Coord; -typedef int SDLX_Size; - - -#else -#error "unknown or unsupported SDL version" -#endif - - diff --git a/client/gui/SDL_Extensions.cpp b/client/gui/SDL_Extensions.cpp index abfc10d17..c5aea27fb 100644 --- a/client/gui/SDL_Extensions.cpp +++ b/client/gui/SDL_Extensions.cpp @@ -146,12 +146,12 @@ SDL_Surface * CSDL_Ext::copySurface(SDL_Surface * mod) //returns copy of given s template SDL_Surface * CSDL_Ext::createSurfaceWithBpp(int width, int height) { - Uint32 rMask = 0, gMask = 0, bMask = 0, aMask = 0; + uint32_t rMask = 0, gMask = 0, bMask = 0, aMask = 0; - Channels::px::r.set((Uint8*)&rMask, 255); - Channels::px::g.set((Uint8*)&gMask, 255); - Channels::px::b.set((Uint8*)&bMask, 255); - Channels::px::a.set((Uint8*)&aMask, 255); + Channels::px::r.set((uint8_t*)&rMask, 255); + Channels::px::g.set((uint8_t*)&gMask, 255); + Channels::px::b.set((uint8_t*)&bMask, 255); + Channels::px::a.set((uint8_t*)&aMask, 255); return SDL_CreateRGBSurface(0, width, height, bpp * 8, rMask, gMask, bMask, aMask); } @@ -230,28 +230,28 @@ SDL_Surface * CSDL_Ext::horizontalFlip(SDL_Surface * toRot) return ret; } -Uint32 CSDL_Ext::getPixel(SDL_Surface *surface, const int & x, const int & y, bool colorByte) +uint32_t CSDL_Ext::getPixel(SDL_Surface *surface, const int & x, const int & y, bool colorByte) { int bpp = surface->format->BytesPerPixel; /* Here p is the address to the pixel we want to retrieve */ - Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; + uint8_t *p = (uint8_t *)surface->pixels + y * surface->pitch + x * bpp; switch(bpp) { case 1: if(colorByte) - return colorToUint32(surface->format->palette->colors+(*p)); + return colorTouint32_t(surface->format->palette->colors+(*p)); else return *p; case 2: - return *(Uint16 *)p; + return *(uint16_t *)p; case 3: return p[0] | p[1] << 8 | p[2] << 16; case 4: - return *(Uint32 *)p; + return *(uint32_t *)p; default: return 0; // shouldn't happen, but avoids warnings @@ -366,13 +366,13 @@ int CSDL_Ext::blit8bppAlphaTo24bppT(const SDL_Surface * src, const Rect & srcRec return -1; //if we cannot lock the surface const SDL_Color *colors = src->format->palette->colors; - Uint8 *colory = (Uint8*)src->pixels + srcy*src->pitch + srcx; - Uint8 *py = (Uint8*)dst->pixels + dstRect->y*dst->pitch + dstRect->x*bpp; + uint8_t *colory = (uint8_t*)src->pixels + srcy*src->pitch + srcx; + uint8_t *py = (uint8_t*)dst->pixels + dstRect->y*dst->pitch + dstRect->x*bpp; for(int y=h; y; y--, colory+=src->pitch, py+=dst->pitch) { - Uint8 *color = colory; - Uint8 *p = py; + uint8_t *color = colory; + uint8_t *p = py; for(int x = w; x; x--) { @@ -399,9 +399,9 @@ int CSDL_Ext::blit8bppAlphaTo24bpp(const SDL_Surface * src, const Rect & srcRect } } -Uint32 CSDL_Ext::colorToUint32(const SDL_Color * color) +uint32_t CSDL_Ext::colorTouint32_t(const SDL_Color * color) { - Uint32 ret = 0; + uint32_t ret = 0; ret+=color->a; ret<<=8; //*=256 ret+=color->b; @@ -432,7 +432,7 @@ static void drawLineX(SDL_Surface * sur, int x1, int y1, int x2, int y2, const S uint8_t b = vstd::lerp(color1.b, color2.b, f); uint8_t a = vstd::lerp(color1.a, color2.a, f); - Uint8 *p = CSDL_Ext::getPxPtr(sur, x, y); + uint8_t *p = CSDL_Ext::getPxPtr(sur, x, y); ColorPutter<4, 0>::PutColor(p, r,g,b,a); } } @@ -449,7 +449,7 @@ static void drawLineY(SDL_Surface * sur, int x1, int y1, int x2, int y2, const S uint8_t b = vstd::lerp(color1.b, color2.b, f); uint8_t a = vstd::lerp(color1.a, color2.a, f); - Uint8 *p = CSDL_Ext::getPxPtr(sur, x, y); + uint8_t *p = CSDL_Ext::getPxPtr(sur, x, y); ColorPutter<4, 0>::PutColor(p, r,g,b,a); } } @@ -461,7 +461,7 @@ void CSDL_Ext::drawLine(SDL_Surface * sur, int x1, int y1, int x2, int y2, const if ( width == 0 && height == 0) { - Uint8 *p = CSDL_Ext::getPxPtr(sur, x1, y1); + uint8_t *p = CSDL_Ext::getPxPtr(sur, x1, y1); ColorPutter<4, 0>::PutColorAlpha(p, color1); return; } @@ -579,9 +579,9 @@ CSDL_Ext::TColorPutterAlpha CSDL_Ext::getPutterAlphaFor(SDL_Surface * const &des #undef CASE_BPP } -Uint8 * CSDL_Ext::getPxPtr(const SDL_Surface * const &srf, const int x, const int y) +uint8_t * CSDL_Ext::getPxPtr(const SDL_Surface * const &srf, const int x, const int y) { - return (Uint8 *)srf->pixels + y * srf->pitch + x * srf->format->BytesPerPixel; + return (uint8_t *)srf->pixels + y * srf->pitch + x * srf->format->BytesPerPixel; } std::string CSDL_Ext::processStr(std::string str, std::vector & tor) @@ -629,9 +629,9 @@ void CSDL_Ext::VflipSurf(SDL_Surface * surf) } } -void CSDL_Ext::putPixelWithoutRefresh(SDL_Surface *ekran, const int & x, const int & y, const Uint8 & R, const Uint8 & G, const Uint8 & B, Uint8 A) +void CSDL_Ext::putPixelWithoutRefresh(SDL_Surface *ekran, const int & x, const int & y, const uint8_t & R, const uint8_t & G, const uint8_t & B, uint8_t A) { - Uint8 *p = getPxPtr(ekran, x, y); + uint8_t *p = getPxPtr(ekran, x, y); getPutterFor(ekran, false)(p, R, G, B); switch(ekran->format->BytesPerPixel) @@ -642,7 +642,7 @@ void CSDL_Ext::putPixelWithoutRefresh(SDL_Surface *ekran, const int & x, const i } } -void CSDL_Ext::putPixelWithoutRefreshIfInSurf(SDL_Surface *ekran, const int & x, const int & y, const Uint8 & R, const Uint8 & G, const Uint8 & B, Uint8 A) +void CSDL_Ext::putPixelWithoutRefreshIfInSurf(SDL_Surface *ekran, const int & x, const int & y, const uint8_t & R, const uint8_t & G, const uint8_t & B, uint8_t A) { const SDL_Rect & rect = ekran->clip_rect; @@ -665,7 +665,7 @@ void CSDL_Ext::applyEffectBpp(SDL_Surface * surf, const Rect & rect, int mode ) { for(int yp = rect.y; yp < rect.y + rect.h; ++yp) { - Uint8 * pixel = (ui8*)surf->pixels + yp * surf->pitch + xp * surf->format->BytesPerPixel; + uint8_t * pixel = (ui8*)surf->pixels + yp * surf->pitch + xp * surf->format->BytesPerPixel; int r = Channels::px::r.get(pixel); int g = Channels::px::g.get(pixel); int b = Channels::px::b.get(pixel); @@ -698,7 +698,7 @@ void CSDL_Ext::applyEffectBpp(SDL_Surface * surf, const Rect & rect, int mode ) { for(int yp = rect.y; yp < rect.y + rect.h; ++yp) { - Uint8 * pixel = (ui8*)surf->pixels + yp * surf->pitch + xp * surf->format->BytesPerPixel; + uint8_t * pixel = (ui8*)surf->pixels + yp * surf->pitch + xp * surf->format->BytesPerPixel; int r = Channels::px::r.get(pixel); int g = Channels::px::g.get(pixel); @@ -744,8 +744,8 @@ void scaleSurfaceFastInternal(SDL_Surface *surf, SDL_Surface *ret) origY = static_cast(floor(factorY * y)); // Get pointers to source pixels - Uint8 *srcPtr = (Uint8*)surf->pixels + origY * surf->pitch + origX * bpp; - Uint8 *destPtr = (Uint8*)ret->pixels + y * ret->pitch + x * bpp; + uint8_t *srcPtr = (uint8_t*)surf->pixels + origY * surf->pitch + origX * bpp; + uint8_t *destPtr = (uint8_t*)ret->pixels + y * ret->pitch + x * bpp; memcpy(destPtr, srcPtr, bpp); } @@ -799,10 +799,10 @@ void scaleSurfaceInternal(SDL_Surface *surf, SDL_Surface *ret) //assert( w11 + w12 + w21 + w22 > 0.99 && w11 + w12 + w21 + w22 < 1.01);//total weight is ~1.0 // Get pointers to source pixels - Uint8 *p11 = (Uint8*)surf->pixels + int(y1) * surf->pitch + int(x1) * bpp; - Uint8 *p12 = p11 + bpp; - Uint8 *p21 = p11 + surf->pitch; - Uint8 *p22 = p21 + bpp; + uint8_t *p11 = (uint8_t*)surf->pixels + int(y1) * surf->pitch + int(x1) * bpp; + uint8_t *p12 = p11 + bpp; + uint8_t *p21 = p11 + surf->pitch; + uint8_t *p22 = p21 + bpp; // Calculate resulting channels #define PX(X, PTR) Channels::px::X.get(PTR) int resR = static_cast(PX(r, p11) * w11 + PX(r, p12) * w12 + PX(r, p21) * w21 + PX(r, p22) * w22); @@ -811,7 +811,7 @@ void scaleSurfaceInternal(SDL_Surface *surf, SDL_Surface *ret) int resA = static_cast(PX(a, p11) * w11 + PX(a, p12) * w12 + PX(a, p21) * w21 + PX(a, p22) * w22); //assert(resR < 256 && resG < 256 && resB < 256 && resA < 256); #undef PX - Uint8 *dest = (Uint8*)ret->pixels + y * ret->pitch + x * bpp; + uint8_t *dest = (uint8_t*)ret->pixels + y * ret->pitch + x * bpp; Channels::px::r.set(dest, resR); Channels::px::g.set(dest, resG); Channels::px::b.set(dest, resB); diff --git a/client/gui/SDL_Extensions.h b/client/gui/SDL_Extensions.h index b63ab8fef..0be7d1d45 100644 --- a/client/gui/SDL_Extensions.h +++ b/client/gui/SDL_Extensions.h @@ -9,11 +9,11 @@ */ #pragma once -#include #include "../../lib/GameConstants.h" #include "../../lib/Rect.h" #include "../../lib/Color.h" +struct SDL_Rect; struct SDL_Window; struct SDL_Renderer; struct SDL_Texture; @@ -114,8 +114,8 @@ std::string makeNumberShort(IntType number, IntType maxLength = 3) //the output Rect genRect(const int & hh, const int & ww, const int & xx, const int & yy); -typedef void (*TColorPutter)(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B); -typedef void (*TColorPutterAlpha)(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B, const Uint8 & A); +typedef void (*TColorPutter)(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B); +typedef void (*TColorPutterAlpha)(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A); void blitAt(SDL_Surface * src, int x, int y, SDL_Surface * dst=screen); void blitAt(SDL_Surface * src, const Rect & pos, SDL_Surface * dst=screen); @@ -131,23 +131,23 @@ typedef void (*TColorPutterAlpha)(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, void updateRect(SDL_Surface *surface, const Rect & rect); - void putPixelWithoutRefresh(SDL_Surface *ekran, const int & x, const int & y, const Uint8 & R, const Uint8 & G, const Uint8 & B, Uint8 A = 255); - void putPixelWithoutRefreshIfInSurf(SDL_Surface *ekran, const int & x, const int & y, const Uint8 & R, const Uint8 & G, const Uint8 & B, Uint8 A = 255); + void putPixelWithoutRefresh(SDL_Surface *ekran, const int & x, const int & y, const uint8_t & R, const uint8_t & G, const uint8_t & B, uint8_t A = 255); + void putPixelWithoutRefreshIfInSurf(SDL_Surface *ekran, const int & x, const int & y, const uint8_t & R, const uint8_t & G, const uint8_t & B, uint8_t A = 255); SDL_Surface * verticalFlip(SDL_Surface * toRot); //vertical flip SDL_Surface * horizontalFlip(SDL_Surface * toRot); //horizontal flip - Uint32 getPixel(SDL_Surface *surface, const int & x, const int & y, bool colorByte = false); + uint32_t getPixel(SDL_Surface *surface, const int & x, const int & y, bool colorByte = false); bool isTransparent(SDL_Surface * srf, int x, int y); //checks if surface is transparent at given position bool isTransparent(SDL_Surface * srf, const Point & position); //checks if surface is transparent at given position - Uint8 *getPxPtr(const SDL_Surface * const &srf, const int x, const int y); + uint8_t *getPxPtr(const SDL_Surface * const &srf, const int x, const int y); TColorPutter getPutterFor(SDL_Surface * const &dest, int incrementing); //incrementing: -1, 0, 1 TColorPutterAlpha getPutterAlphaFor(SDL_Surface * const &dest, int incrementing); //incrementing: -1, 0, 1 template int blit8bppAlphaTo24bppT(const SDL_Surface * src, const Rect & srcRect, SDL_Surface * dst, const Point & dstPoint); //blits 8 bpp surface with alpha channel to 24 bpp surface int blit8bppAlphaTo24bpp(const SDL_Surface * src, const Rect & srcRect, SDL_Surface * dst, const Point & dstPoint); //blits 8 bpp surface with alpha channel to 24 bpp surface - Uint32 colorToUint32(const SDL_Color * color); //little endian only + uint32_t colorTouint32_t(const SDL_Color * color); //little endian only SDL_Color makeColor(ui8 r, ui8 g, ui8 b, ui8 a); void update(SDL_Surface * what = screen); //updates whole surface (default - main screen) diff --git a/client/gui/SDL_Pixels.h b/client/gui/SDL_Pixels.h index f18f599bc..3ad055819 100644 --- a/client/gui/SDL_Pixels.h +++ b/client/gui/SDL_Pixels.h @@ -12,6 +12,7 @@ #include "SDL_Extensions.h" #include +#include // for accessing channels from pixel in format-independent way //should be as fast as accessing via pointer at least for 3-4 bytes per pixel @@ -20,20 +21,20 @@ namespace Channels // channel not present in this format struct channel_empty { - static STRONG_INLINE void set(Uint8*, Uint8) {} - static STRONG_INLINE Uint8 get(const Uint8 *) { return 255;} + static STRONG_INLINE void set(uint8_t*, uint8_t) {} + static STRONG_INLINE uint8_t get(const uint8_t *) { return 255;} }; // channel which uses whole pixel template struct channel_pixel { - static STRONG_INLINE void set(Uint8 *ptr, Uint8 value) + static STRONG_INLINE void set(uint8_t *ptr, uint8_t value) { ptr[offset] = value; } - static STRONG_INLINE Uint8 get(const Uint8 *ptr) + static STRONG_INLINE uint8_t get(const uint8_t *ptr) { return ptr[offset]; } @@ -44,16 +45,16 @@ namespace Channels struct channel_subpx { - static void STRONG_INLINE set(Uint8 *ptr, Uint8 value) + static void STRONG_INLINE set(uint8_t *ptr, uint8_t value) { - Uint16 * const pixel = (Uint16*)ptr; - Uint8 subpx = value >> (8 - bits); + uint16_t * const pixel = (uint16_t*)ptr; + uint8_t subpx = value >> (8 - bits); *pixel = (*pixel & ~mask) | ((subpx << shift) & mask ); } - static Uint8 STRONG_INLINE get(const Uint8 *ptr) + static uint8_t STRONG_INLINE get(const uint8_t *ptr) { - Uint8 subpx = (*((Uint16 *)ptr) & mask) >> shift; + uint8_t subpx = (*((uint16_t *)ptr) & mask) >> shift; return (subpx << (8 - bits)) | (subpx >> (2*bits - 8)); } }; @@ -122,39 +123,39 @@ namespace Channels template struct ColorPutter { - static STRONG_INLINE void PutColor(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B); - static STRONG_INLINE void PutColor(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B, const Uint8 & A); - static STRONG_INLINE void PutColorAlphaSwitch(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B, const Uint8 & A); - static STRONG_INLINE void PutColor(Uint8 *&ptr, const SDL_Color & Color); - static STRONG_INLINE void PutColorAlpha(Uint8 *&ptr, const SDL_Color & Color); - static STRONG_INLINE void PutColorRow(Uint8 *&ptr, const SDL_Color & Color, size_t count); + static STRONG_INLINE void PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B); + static STRONG_INLINE void PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A); + static STRONG_INLINE void PutColorAlphaSwitch(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A); + static STRONG_INLINE void PutColor(uint8_t *&ptr, const SDL_Color & Color); + static STRONG_INLINE void PutColorAlpha(uint8_t *&ptr, const SDL_Color & Color); + static STRONG_INLINE void PutColorRow(uint8_t *&ptr, const SDL_Color & Color, size_t count); }; template struct ColorPutter<2, incrementPtr> { - static STRONG_INLINE void PutColor(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B); - static STRONG_INLINE void PutColor(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B, const Uint8 & A); - static STRONG_INLINE void PutColorAlphaSwitch(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B, const Uint8 & A); - static STRONG_INLINE void PutColor(Uint8 *&ptr, const SDL_Color & Color); - static STRONG_INLINE void PutColorAlpha(Uint8 *&ptr, const SDL_Color & Color); - static STRONG_INLINE void PutColorRow(Uint8 *&ptr, const SDL_Color & Color, size_t count); + static STRONG_INLINE void PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B); + static STRONG_INLINE void PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A); + static STRONG_INLINE void PutColorAlphaSwitch(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A); + static STRONG_INLINE void PutColor(uint8_t *&ptr, const SDL_Color & Color); + static STRONG_INLINE void PutColorAlpha(uint8_t *&ptr, const SDL_Color & Color); + static STRONG_INLINE void PutColorRow(uint8_t *&ptr, const SDL_Color & Color, size_t count); }; template -STRONG_INLINE void ColorPutter::PutColorAlpha(Uint8 *&ptr, const SDL_Color & Color) +STRONG_INLINE void ColorPutter::PutColorAlpha(uint8_t *&ptr, const SDL_Color & Color) { PutColor(ptr, Color.r, Color.g, Color.b, Color.a); } template -STRONG_INLINE void ColorPutter::PutColor(Uint8 *&ptr, const SDL_Color & Color) +STRONG_INLINE void ColorPutter::PutColor(uint8_t *&ptr, const SDL_Color & Color) { PutColor(ptr, Color.r, Color.g, Color.b); } template -STRONG_INLINE void ColorPutter::PutColorAlphaSwitch(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B, const Uint8 & A) +STRONG_INLINE void ColorPutter::PutColorAlphaSwitch(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A) { switch (A) { @@ -166,9 +167,9 @@ STRONG_INLINE void ColorPutter::PutColorAlphaSwitch(Uint8 *&p return; case 128: // optimized PutColor(ptr, - ((Uint16)R + Channels::px::r.get(ptr)) >> 1, - ((Uint16)G + Channels::px::g.get(ptr)) >> 1, - ((Uint16)B + Channels::px::b.get(ptr)) >> 1); + ((uint16_t)R + Channels::px::r.get(ptr)) >> 1, + ((uint16_t)G + Channels::px::g.get(ptr)) >> 1, + ((uint16_t)B + Channels::px::b.get(ptr)) >> 1); return; default: PutColor(ptr, R, G, B, A); @@ -177,16 +178,16 @@ STRONG_INLINE void ColorPutter::PutColorAlphaSwitch(Uint8 *&p } template -STRONG_INLINE void ColorPutter::PutColor(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B, const Uint8 & A) +STRONG_INLINE void ColorPutter::PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A) { - PutColor(ptr, ((((Uint32)R - (Uint32)Channels::px::r.get(ptr))*(Uint32)A) >> 8 ) + (Uint32)Channels::px::r.get(ptr), - ((((Uint32)G - (Uint32)Channels::px::g.get(ptr))*(Uint32)A) >> 8 ) + (Uint32)Channels::px::g.get(ptr), - ((((Uint32)B - (Uint32)Channels::px::b.get(ptr))*(Uint32)A) >> 8 ) + (Uint32)Channels::px::b.get(ptr)); + PutColor(ptr, ((((uint32_t)R - (uint32_t)Channels::px::r.get(ptr))*(uint32_t)A) >> 8 ) + (uint32_t)Channels::px::r.get(ptr), + ((((uint32_t)G - (uint32_t)Channels::px::g.get(ptr))*(uint32_t)A) >> 8 ) + (uint32_t)Channels::px::g.get(ptr), + ((((uint32_t)B - (uint32_t)Channels::px::b.get(ptr))*(uint32_t)A) >> 8 ) + (uint32_t)Channels::px::b.get(ptr)); } template -STRONG_INLINE void ColorPutter::PutColor(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B) +STRONG_INLINE void ColorPutter::PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B) { static_assert(incrementPtr >= -1 && incrementPtr <= +1, "Invalid incrementPtr value!"); @@ -204,11 +205,11 @@ STRONG_INLINE void ColorPutter::PutColor(Uint8 *&ptr, const U } template -STRONG_INLINE void ColorPutter::PutColorRow(Uint8 *&ptr, const SDL_Color & Color, size_t count) +STRONG_INLINE void ColorPutter::PutColorRow(uint8_t *&ptr, const SDL_Color & Color, size_t count) { if (count) { - Uint8 *pixel = ptr; + uint8_t *pixel = ptr; PutColor(ptr, Color.r, Color.g, Color.b); for (size_t i=0; i::PutColorRow(Uint8 *&ptr, cons } template -STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColor(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B) +STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B) { if(incrementPtr == -1) ptr -= 2; - Uint16 * const px = (Uint16*)ptr; + uint16_t * const px = (uint16_t*)ptr; *px = (B>>3) + ((G>>2) << 5) + ((R>>3) << 11); //drop least significant bits of 24 bpp encoded color if(incrementPtr == 1) @@ -233,7 +234,7 @@ STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColor(Uint8 *&ptr, const Uin } template -STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColorAlphaSwitch(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B, const Uint8 & A) +STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColorAlphaSwitch(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A) { switch (A) { @@ -250,17 +251,17 @@ STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColorAlphaSwitch(Uint8 *&ptr } template -STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColor(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B, const Uint8 & A) +STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A) { const int rbit = 5, gbit = 6, bbit = 5; //bits per color const int rmask = 0xF800, gmask = 0x7E0, bmask = 0x1F; const int rshift = 11, gshift = 5, bshift = 0; - const Uint8 r5 = (*((Uint16 *)ptr) & rmask) >> rshift, - b5 = (*((Uint16 *)ptr) & bmask) >> bshift, - g5 = (*((Uint16 *)ptr) & gmask) >> gshift; + const uint8_t r5 = (*((uint16_t *)ptr) & rmask) >> rshift, + b5 = (*((uint16_t *)ptr) & bmask) >> bshift, + g5 = (*((uint16_t *)ptr) & gmask) >> gshift; - const Uint32 r8 = (r5 << (8 - rbit)) | (r5 >> (2*rbit - 8)), + const uint32_t r8 = (r5 << (8 - rbit)) | (r5 >> (2*rbit - 8)), g8 = (g5 << (8 - gbit)) | (g5 >> (2*gbit - 8)), b8 = (b5 << (8 - bbit)) | (b5 >> (2*bbit - 8)); @@ -271,22 +272,22 @@ STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColor(Uint8 *&ptr, const Uin } template -STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColorAlpha(Uint8 *&ptr, const SDL_Color & Color) +STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColorAlpha(uint8_t *&ptr, const SDL_Color & Color) { PutColor(ptr, Color.r, Color.g, Color.b, Color.a); } template -STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColor(Uint8 *&ptr, const SDL_Color & Color) +STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColor(uint8_t *&ptr, const SDL_Color & Color) { PutColor(ptr, Color.r, Color.g, Color.b); } template -STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColorRow(Uint8 *&ptr, const SDL_Color & Color, size_t count) +STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColorRow(uint8_t *&ptr, const SDL_Color & Color, size_t count) { //drop least significant bits of 24 bpp encoded color - Uint16 pixel = (Color.b>>3) + ((Color.g>>2) << 5) + ((Color.r>>3) << 11); + uint16_t pixel = (Color.b>>3) + ((Color.g>>2) << 5) + ((Color.r>>3) << 11); for (size_t i=0; i + ISelectionScreenInfo::ISelectionScreenInfo(ESelectionScreen ScreenType) : screenType(ScreenType) { diff --git a/client/lobby/SelectionTab.cpp b/client/lobby/SelectionTab.cpp index 9eaa83386..f33d7413e 100644 --- a/client/lobby/SelectionTab.cpp +++ b/client/lobby/SelectionTab.cpp @@ -36,6 +36,7 @@ #include "../../lib/mapping/CMapInfo.h" #include "../../lib/serializer/Connection.h" +#include bool mapSorter::operator()(const std::shared_ptr aaa, const std::shared_ptr bbb) { diff --git a/client/mainmenu/CMainMenu.cpp b/client/mainmenu/CMainMenu.cpp index f1a271067..88ec3e949 100644 --- a/client/mainmenu/CMainMenu.cpp +++ b/client/mainmenu/CMainMenu.cpp @@ -56,6 +56,7 @@ #include "../../lib/CondSh.h" #include "../../lib/mapping/CCampaignHandler.h" +#include namespace fs = boost::filesystem; diff --git a/client/widgets/AdventureMapClasses.cpp b/client/widgets/AdventureMapClasses.cpp index 6a6fd19bd..47685b341 100644 --- a/client/widgets/AdventureMapClasses.cpp +++ b/client/widgets/AdventureMapClasses.cpp @@ -43,6 +43,10 @@ #include "../../lib/mapping/CMap.h" #include "ClientCommandManager.h" +#include +#include +#include + CList::CListItem::CListItem(CList * Parent) : CIntObject(LCLICK | RCLICK | HOVER), parent(Parent), @@ -187,7 +191,7 @@ CHeroList::CEmptyHeroItem::CEmptyHeroItem() mana = std::make_shared("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1 ); pos.w = mana->pos.w + mana->pos.x - pos.x; - pos.h = std::max(std::max(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h); + pos.h = std::max(std::max(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h); } CHeroList::CHeroItem::CHeroItem(CHeroList *parent, const CGHeroInstance * Hero) @@ -200,7 +204,7 @@ CHeroList::CHeroItem::CHeroItem(CHeroList *parent, const CGHeroInstance * Hero) mana = std::make_shared("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1); pos.w = mana->pos.w + mana->pos.x - pos.x; - pos.h = std::max(std::max(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h); + pos.h = std::max(std::max(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h); update(); } @@ -409,7 +413,7 @@ void CMinimapInstance::blitTileWithColor(const SDL_Color &color, const int3 &til for (int y=yBegin; ypixels + y * to->pitch + xBegin * minimap->format->BytesPerPixel; + uint8_t *ptr = (uint8_t*)to->pixels + y * to->pitch + xBegin * minimap->format->BytesPerPixel; for (int x=xBegin; x::PutColor(ptr, color); @@ -446,7 +450,7 @@ void CMinimapInstance::drawScaled(int level) for (int y=yBegin; ypixels + y * minimap->pitch + xBegin * minimap->format->BytesPerPixel; + uint8_t *ptr = (uint8_t*)minimap->pixels + y * minimap->pitch + xBegin * minimap->format->BytesPerPixel; for (int x=xBegin; x::PutColor(ptr, color); @@ -948,7 +952,7 @@ void CInGameConsole::show(SDL_Surface * to) { int number = 0; - std::vector >::iterator> toDel; + std::vector >::iterator> toDel; boost::unique_lock lock(texts_mx); for(auto it = texts.begin(); it != texts.end(); ++it, ++number) diff --git a/client/widgets/AdventureMapClasses.h b/client/widgets/AdventureMapClasses.h index 81bc9727f..3b4874d9e 100644 --- a/client/widgets/AdventureMapClasses.h +++ b/client/widgets/AdventureMapClasses.h @@ -405,7 +405,7 @@ public: class CInGameConsole : public CIntObject { private: - std::list< std::pair< std::string, Uint32 > > texts; //list + std::list< std::pair< std::string, uint32_t > > texts; //list boost::mutex texts_mx; // protects texts std::vector< std::string > previouslyEntered; //previously entered texts, for up/down arrows to work int prevEntDisp; //displayed entry from previouslyEntered - if none it's -1 diff --git a/client/widgets/Buttons.cpp b/client/widgets/Buttons.cpp index aa53ca7c1..30965e53d 100644 --- a/client/widgets/Buttons.cpp +++ b/client/widgets/Buttons.cpp @@ -24,6 +24,8 @@ #include "../../lib/CConfigHandler.h" #include "../../lib/CGeneralTextHandler.h" +#include + void CButton::update() { if (overlay) diff --git a/client/widgets/Buttons.h b/client/widgets/Buttons.h index 6835f1cd3..74e6ad690 100644 --- a/client/widgets/Buttons.h +++ b/client/widgets/Buttons.h @@ -13,6 +13,8 @@ #include "../gui/SDL_Extensions.h" #include "../../lib/FunctionList.h" +#include + VCMI_LIB_NAMESPACE_BEGIN namespace config diff --git a/client/widgets/CGarrisonInt.cpp b/client/widgets/CGarrisonInt.cpp index 3bd4e9b1a..4e052c5e0 100644 --- a/client/widgets/CGarrisonInt.cpp +++ b/client/widgets/CGarrisonInt.cpp @@ -32,6 +32,8 @@ #define SDL_SCANCODE_LCTRL SDL_SCANCODE_LGUI #endif +#include + void CGarrisonSlot::setHighlight(bool on) { if (on) @@ -437,7 +439,7 @@ void CGarrisonSlot::splitIntoParts(CGarrisonSlot::EGarrisonType type, int amount bool CGarrisonSlot::handleSplittingShortcuts() { - const Uint8 * state = SDL_GetKeyboardState(NULL); + const uint8_t * state = SDL_GetKeyboardState(NULL); const bool isAlt = !!state[SDL_SCANCODE_LALT]; const bool isLShift = !!state[SDL_SCANCODE_LSHIFT]; const bool isLCtrl = !!state[SDL_SCANCODE_LCTRL]; diff --git a/client/widgets/TextControls.cpp b/client/widgets/TextControls.cpp index 55bd3bcf0..bb3ad318e 100644 --- a/client/widgets/TextControls.cpp +++ b/client/widgets/TextControls.cpp @@ -24,6 +24,8 @@ #include "lib/CAndroidVMHelper.h" #endif +#include + std::string CLabel::visibleText() { return text; diff --git a/client/widgets/TextControls.h b/client/widgets/TextControls.h index cda84bb78..d1a5b3e67 100644 --- a/client/widgets/TextControls.h +++ b/client/widgets/TextControls.h @@ -14,6 +14,8 @@ #include "../gui/SDL_Extensions.h" #include "../../lib/FunctionList.h" +#include + class IImage; class CSlider; diff --git a/client/windows/CAdvmapInterface.cpp b/client/windows/CAdvmapInterface.cpp index 0b76b654a..d0529f744 100644 --- a/client/windows/CAdvmapInterface.cpp +++ b/client/windows/CAdvmapInterface.cpp @@ -55,6 +55,9 @@ #include "../../lib/mapping/CMapInfo.h" #include "../../lib/TerrainHandler.h" +#include +#include + #define ADVOPT (conf.go()->ac) using namespace CSDL_Ext; diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index f3d397bcf..6fcbf4c67 100644 --- a/client/windows/CCastleInterface.cpp +++ b/client/windows/CCastleInterface.cpp @@ -44,6 +44,8 @@ #include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGTownInstance.h" +#include + CBuildingRect::CBuildingRect(CCastleBuildings * Par, const CGTownInstance * Town, const CStructure * Str) : CShowableAnim(0, 0, Str->defName, CShowableAnim::BASE), parent(Par), @@ -153,10 +155,10 @@ void CBuildingRect::clickRight(tribool down, bool previousState) SDL_Color multiplyColors(const SDL_Color & b, const SDL_Color & a, double f) { SDL_Color ret; - ret.r = static_cast(a.r * f + b.r * (1 - f)); - ret.g = static_cast(a.g * f + b.g * (1 - f)); - ret.b = static_cast(a.b * f + b.b * (1 - f)); - ret.a = static_cast(a.a * f + b.b * (1 - f)); + ret.r = static_cast(a.r * f + b.r * (1 - f)); + ret.g = static_cast(a.g * f + b.g * (1 - f)); + ret.b = static_cast(a.b * f + b.b * (1 - f)); + ret.a = static_cast(a.a * f + b.b * (1 - f)); return ret; } diff --git a/client/windows/CSpellWindow.cpp b/client/windows/CSpellWindow.cpp index 4dc525baf..2cc5b6c78 100644 --- a/client/windows/CSpellWindow.cpp +++ b/client/windows/CSpellWindow.cpp @@ -42,6 +42,8 @@ #include "../../lib/mapObjects/CGHeroInstance.h" +#include + CSpellWindow::InteractiveArea::InteractiveArea(const Rect & myRect, std::function funcL, int helpTextId, CSpellWindow * _owner) { addUsedEvents(LCLICK | RCLICK | HOVER); diff --git a/client/windows/CSpellWindow.h b/client/windows/CSpellWindow.h index b5b0f2774..b0364dae0 100644 --- a/client/windows/CSpellWindow.h +++ b/client/windows/CSpellWindow.h @@ -84,7 +84,7 @@ class CSpellWindow : public CWindowObject int sitesPerTabBattle[5]; bool battleSpellsOnly; //if true, only battle spells are displayed; if false, only adventure map spells are displayed - Uint8 selectedTab; // 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic, 4 - all schools + uint8_t selectedTab; // 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic, 4 - all schools int currentPage; //changes when corners are clicked std::vector mySpells; //all spels in this spellbook diff --git a/client/windows/CWindowObject.cpp b/client/windows/CWindowObject.cpp index c818400c6..4d38677fb 100644 --- a/client/windows/CWindowObject.cpp +++ b/client/windows/CWindowObject.cpp @@ -35,6 +35,8 @@ #include "../../lib/CConfigHandler.h" #include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff +#include + CWindowObject::CWindowObject(int options_, std::string imageName, Point centerAt): WindowBase(getUsedEvents(options_), Point()), options(options_), @@ -138,7 +140,7 @@ void CWindowObject::setShadow(bool on) //helper to set last row auto blitAlphaRow = [](SDL_Surface *surf, size_t row) { - Uint8 * ptr = (Uint8*)surf->pixels + surf->pitch * (row); + uint8_t * ptr = (uint8_t*)surf->pixels + surf->pitch * (row); for (size_t i=0; i< surf->w; i++) { @@ -150,7 +152,7 @@ void CWindowObject::setShadow(bool on) // helper to set last column auto blitAlphaCol = [](SDL_Surface *surf, size_t col) { - Uint8 * ptr = (Uint8*)surf->pixels + 4 * (col); + uint8_t * ptr = (uint8_t*)surf->pixels + 4 * (col); for (size_t i=0; i< surf->h; i++) { diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 0954ac825..50fefaa2a 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -61,6 +61,8 @@ #include "../lib/NetPacksBase.h" #include "../lib/StartInfo.h" +#include + using namespace CSDL_Ext; std::list CFocusable::focusables; diff --git a/client/windows/InfoWindows.cpp b/client/windows/InfoWindows.cpp index 0d2a52532..98ab48b86 100644 --- a/client/windows/InfoWindows.cpp +++ b/client/windows/InfoWindows.cpp @@ -39,6 +39,8 @@ #include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/mapObjects/MiscObjects.h" +#include + void CSimpleWindow::show(SDL_Surface * to) { if(bitmap) From 5cc23cc2869d0b0eff7a94c5572055e061f859db Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Mon, 30 Jan 2023 20:06:08 +0200 Subject: [PATCH 34/79] Renamed SDL_Pixels -> SDL_PixelAccess due to similar SDL header --- client/CMakeLists.txt | 2 +- client/gui/CAnimation.cpp | 1 - client/gui/Fonts.cpp | 2 +- client/gui/SDL_Extensions.cpp | 2 +- client/gui/{SDL_Pixels.h => SDL_PixelAccess.h} | 2 +- client/widgets/AdventureMapClasses.cpp | 2 +- client/widgets/Images.cpp | 1 - client/windows/CWindowObject.cpp | 2 +- client/windows/InfoWindows.cpp | 1 - 9 files changed, 6 insertions(+), 9 deletions(-) rename client/gui/{SDL_Pixels.h => SDL_PixelAccess.h} (99%) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index f9404f59d..a9cb657fe 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -111,7 +111,7 @@ set(client_HEADERS gui/Fonts.h gui/TextAlignment.h gui/SDL_Extensions.h - gui/SDL_Pixels.h + gui/SDL_PixelAccess.h gui/NotificationHandler.h gui/InterfaceObjectConfigurable.h diff --git a/client/gui/CAnimation.cpp b/client/gui/CAnimation.cpp index 589e300e8..31a18f5e5 100644 --- a/client/gui/CAnimation.cpp +++ b/client/gui/CAnimation.cpp @@ -11,7 +11,6 @@ #include "CAnimation.h" #include "SDL_Extensions.h" -#include "SDL_Pixels.h" #include "ColorFilter.h" #include "../CBitmapHandler.h" diff --git a/client/gui/Fonts.cpp b/client/gui/Fonts.cpp index adc843b79..9eb024aaf 100644 --- a/client/gui/Fonts.cpp +++ b/client/gui/Fonts.cpp @@ -12,7 +12,7 @@ #include -#include "SDL_Pixels.h" +#include "SDL_Extensions.h" #include "../../lib/JsonNode.h" #include "../../lib/vcmi_endian.h" #include "../../lib/filesystem/Filesystem.h" diff --git a/client/gui/SDL_Extensions.cpp b/client/gui/SDL_Extensions.cpp index c5aea27fb..b4403a477 100644 --- a/client/gui/SDL_Extensions.cpp +++ b/client/gui/SDL_Extensions.cpp @@ -9,7 +9,7 @@ */ #include "StdInc.h" #include "SDL_Extensions.h" -#include "SDL_Pixels.h" +#include "SDL_PixelAccess.h" #include "../CGameInfo.h" #include "../CMessage.h" diff --git a/client/gui/SDL_Pixels.h b/client/gui/SDL_PixelAccess.h similarity index 99% rename from client/gui/SDL_Pixels.h rename to client/gui/SDL_PixelAccess.h index 3ad055819..6ddfc2e83 100644 --- a/client/gui/SDL_Pixels.h +++ b/client/gui/SDL_PixelAccess.h @@ -1,5 +1,5 @@ /* - * SDL_Pixels.h, part of VCMI engine + * SDL_PixelAccess.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/widgets/AdventureMapClasses.cpp b/client/widgets/AdventureMapClasses.cpp index 47685b341..4edf48fbd 100644 --- a/client/widgets/AdventureMapClasses.cpp +++ b/client/widgets/AdventureMapClasses.cpp @@ -22,7 +22,7 @@ #include "../mainmenu/CMainMenu.h" #include "../gui/CGuiHandler.h" -#include "../gui/SDL_Pixels.h" +#include "../gui/SDL_PixelAccess.h" #include "../gui/CAnimation.h" #include "../windows/InfoWindows.h" diff --git a/client/widgets/Images.cpp b/client/widgets/Images.cpp index 4e2f32652..1b27dae0a 100644 --- a/client/widgets/Images.cpp +++ b/client/widgets/Images.cpp @@ -13,7 +13,6 @@ #include "MiscWidgets.h" #include "../gui/CAnimation.h" -#include "../gui/SDL_Pixels.h" #include "../gui/CGuiHandler.h" #include "../gui/CursorHandler.h" #include "../gui/ColorFilter.h" diff --git a/client/windows/CWindowObject.cpp b/client/windows/CWindowObject.cpp index 4d38677fb..dca6b6e5b 100644 --- a/client/windows/CWindowObject.cpp +++ b/client/windows/CWindowObject.cpp @@ -15,7 +15,7 @@ #include "../widgets/MiscWidgets.h" #include "../widgets/Images.h" -#include "../gui/SDL_Pixels.h" +#include "../gui/SDL_PixelAccess.h" #include "../gui/SDL_Extensions.h" #include "../gui/CGuiHandler.h" #include "../gui/CursorHandler.h" diff --git a/client/windows/InfoWindows.cpp b/client/windows/InfoWindows.cpp index 98ab48b86..6f1bc6d46 100644 --- a/client/windows/InfoWindows.cpp +++ b/client/windows/InfoWindows.cpp @@ -21,7 +21,6 @@ #include "../widgets/CComponent.h" #include "../widgets/MiscWidgets.h" -#include "../gui/SDL_Pixels.h" #include "../gui/SDL_Extensions.h" #include "../gui/CGuiHandler.h" #include "../gui/CursorHandler.h" From bf343126c4bdd59f6db509dec4c89171c3495380 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 31 Jan 2023 00:42:50 +0200 Subject: [PATCH 35/79] Fix Hero animation speed in battles --- client/battle/BattleInterfaceClasses.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/client/battle/BattleInterfaceClasses.cpp b/client/battle/BattleInterfaceClasses.cpp index 280385372..e5a818111 100644 --- a/client/battle/BattleInterfaceClasses.cpp +++ b/client/battle/BattleInterfaceClasses.cpp @@ -218,8 +218,10 @@ void BattleHero::render(Canvas & canvas) canvas.draw(flagFrame, flagPosition); canvas.draw(heroFrame, heroPosition); - flagCurrentFrame += currentSpeed; - currentFrame += currentSpeed; + float timePassed = float(GH.mainFPSmng->getElapsedMilliseconds()) / 1000.f; + + flagCurrentFrame += currentSpeed * timePassed; + currentFrame += currentSpeed * timePassed; if(flagCurrentFrame >= flagAnimation->size(0)) flagCurrentFrame -= flagAnimation->size(0); @@ -238,8 +240,8 @@ void BattleHero::pause() void BattleHero::play() { - //FIXME: un-hardcode speed - currentSpeed = 0.25f; + //H3 speed: 10 fps ( 100 ms per frame) + currentSpeed = 10.f; } float BattleHero::getFrame() const From fc60a7aff0bb83a203c4bc02efeea46596358e02 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 31 Jan 2023 01:28:11 +0200 Subject: [PATCH 36/79] Removed redundant include --- client/Graphics.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/Graphics.cpp b/client/Graphics.cpp index de9ac1916..54c9baf2a 100644 --- a/client/Graphics.cpp +++ b/client/Graphics.cpp @@ -22,7 +22,6 @@ #include "../lib/filesystem/CBinaryReader.h" #include "gui/SDL_Extensions.h" #include "gui/CAnimation.h" -#include #include "../lib/CThreadHelper.h" #include "../lib/CModHandler.h" #include "CGameInfo.h" @@ -37,6 +36,8 @@ #include "../lib/mapObjects/CObjectHandler.h" #include "../lib/CHeroHandler.h" +#include + using namespace CSDL_Ext; Graphics * graphics = nullptr; From c3a2dee45a64532e4e08442b5762531cab0479da Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 31 Jan 2023 15:00:46 +0200 Subject: [PATCH 37/79] Code cleanup --- client/gui/CursorHandler.cpp | 2 +- client/widgets/Images.h | 4 +++- lib/CCreatureHandler.h | 7 +++++++ lib/serializer/CSerializer.h | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/client/gui/CursorHandler.cpp b/client/gui/CursorHandler.cpp index bb57fa80a..43cdeb15d 100644 --- a/client/gui/CursorHandler.cpp +++ b/client/gui/CursorHandler.cpp @@ -260,7 +260,7 @@ void CursorHandler::centerCursor() void CursorHandler::updateSpellcastCursor() { - static const float frameDisplayDuration = 5.f / 60.f; // H3 uses ~83 ms per image = 5 / 60 second + static const float frameDisplayDuration = 0.1f; // H3 uses 100 ms per frame frameTime += GH.mainFPSmng->getElapsedMilliseconds() / 1000.f; size_t newFrame = frame; diff --git a/client/widgets/Images.h b/client/widgets/Images.h index 166ba45d9..b35ee1da9 100644 --- a/client/widgets/Images.h +++ b/client/widgets/Images.h @@ -125,8 +125,10 @@ protected: size_t first, last; //animation range - /// how long (in milliseconds) should + /// total time on scren for each frame in animation ui32 frameTimeTotal; + + /// how long was current frame visible on screen ui32 frameTimePassed; ui8 flags;//Flags from EFlags enum diff --git a/lib/CCreatureHandler.h b/lib/CCreatureHandler.h index 8b2089481..c85caac98 100644 --- a/lib/CCreatureHandler.h +++ b/lib/CCreatureHandler.h @@ -90,6 +90,13 @@ public: h & idleAnimationTime; h & walkAnimationTime; h & attackAnimationTime; + + if (version < 814) + { + float unused = 0.f; + h & unused; + } + h & upperRightMissleOffsetX; h & rightMissleOffsetX; h & lowerRightMissleOffsetX; diff --git a/lib/serializer/CSerializer.h b/lib/serializer/CSerializer.h index a99a4775d..4cd2b9587 100644 --- a/lib/serializer/CSerializer.h +++ b/lib/serializer/CSerializer.h @@ -14,7 +14,7 @@ VCMI_LIB_NAMESPACE_BEGIN -const ui32 SERIALIZATION_VERSION = 813; +const ui32 SERIALIZATION_VERSION = 814; const ui32 MINIMAL_SERIALIZATION_VERSION = 813; const std::string SAVEGAME_MAGIC = "VCMISVG"; From a9669578fc31beabc8885b436643b4182247fd6d Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 31 Jan 2023 18:13:51 +0200 Subject: [PATCH 38/79] Remove MXE action from CI --- .github/workflows/github.yml | 8 ------ CI/mxe/before_install.sh | 53 ------------------------------------ 2 files changed, 61 deletions(-) delete mode 100644 CI/mxe/before_install.sh diff --git a/.github/workflows/github.yml b/.github/workflows/github.yml index e2b285e6f..b2b967f09 100644 --- a/.github/workflows/github.yml +++ b/.github/workflows/github.yml @@ -99,14 +99,6 @@ jobs: extension: ipa preset: ios-release-conan conan_profile: ios-arm64 - - platform: mxe - os: ubuntu-20.04 - mxe: i686-w64-mingw32.shared - test: 0 - pack: 1 - cpack_args: -D CPACK_NSIS_EXECUTABLE=`which makensis` - extension: exe - cmake_args: -G Ninja - platform: msvc os: windows-latest test: 0 diff --git a/CI/mxe/before_install.sh b/CI/mxe/before_install.sh deleted file mode 100644 index 0a4855f2d..000000000 --- a/CI/mxe/before_install.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -# steps to upgrade MXE dependencies: -# 1) Use Debian/Ubuntu system or install one (virtual machines will work too) -# 2) update following script to include any new dependencies -# You can also run it to upgrade existing ones, but don't expect much -# MXE repository only provides ancient versions for the sake of "stability" -# https://github.com/vcmi/vcmi-deps-mxe/blob/master/mirror-mxe.sh -# 3) make release in vcmi-deps-mxe repository using resulting tar archive -# 4) update paths to tar archive in this script - -# Install nsis for installer creation -sudo add-apt-repository 'deb http://security.ubuntu.com/ubuntu bionic-security main' -sudo apt-get install -qq nsis ninja-build libssl1.0.0 - -# MXE repository was too slow for Travis far too often -wget -nv https://github.com/vcmi/vcmi-deps-mxe/releases/download/2021-02-20/mxe-i686-w64-mingw32.shared-2021-01-22.tar -tar -xvf mxe-i686-w64-mingw32.shared-2021-01-22.tar -sudo dpkg -i mxe-*.deb -sudo apt-get install -f --yes - -if false; then - # Add MXE repository and key - echo "deb http://pkg.mxe.cc/repos/apt/debian wheezy main" \ - | sudo tee /etc/apt/sources.list.d/mxeapt.list - - sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys D43A795B73B16ABE9643FE1AFD8FFF16DB45C6AB - - # Install needed packages - sudo apt-get update -qq - - sudo apt-get install -q --yes \ - mxe-$MXE_TARGET-gcc \ - mxe-$MXE_TARGET-boost \ - mxe-$MXE_TARGET-zlib \ - mxe-$MXE_TARGET-sdl2 \ - mxe-$MXE_TARGET-sdl2-gfx \ - mxe-$MXE_TARGET-sdl2-image \ - mxe-$MXE_TARGET-sdl2-mixer \ - mxe-$MXE_TARGET-sdl2-ttf \ - mxe-$MXE_TARGET-ffmpeg \ - mxe-$MXE_TARGET-qt \ - mxe-$MXE_TARGET-qtbase \ - mxe-$MXE_TARGET-intel-tbb \ - mxe-i686-w64-mingw32.static-luajit - -fi # Disable - -# alias for CMake - -CMAKE_LOCATION=$(which cmake) -sudo mv $CMAKE_LOCATION $CMAKE_LOCATION.orig -sudo ln -s /usr/lib/mxe/usr/bin/$MXE_TARGET-cmake $CMAKE_LOCATION From e938a9bb6c4e5050d4f0555411d93d2503cf1bfd Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 31 Jan 2023 18:14:17 +0200 Subject: [PATCH 39/79] Removed non-preset build from CI config --- .github/workflows/github.yml | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/.github/workflows/github.yml b/.github/workflows/github.yml index b2b967f09..7dc53d43b 100644 --- a/.github/workflows/github.yml +++ b/.github/workflows/github.yml @@ -127,7 +127,6 @@ jobs: - name: Dependencies run: source '${{github.workspace}}/CI/${{matrix.platform}}/before_install.sh' env: - MXE_TARGET: ${{ matrix.mxe }} VCMI_BUILD_PLATFORM: x64 - uses: actions/setup-python@v4 @@ -165,40 +164,16 @@ jobs: env: PULL_REQUEST: ${{ github.event.pull_request.number }} - - name: Configure CMake - if: "${{ matrix.preset == '' }}" - run: | - mkdir -p '${{github.workspace}}/out/build/${{matrix.preset}}' - cd '${{github.workspace}}/out/build/${{matrix.preset}}' - cmake \ - ../.. -GNinja \ - ${{matrix.cmake_args}} -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \ - -DENABLE_TEST=${{matrix.test}} \ - -DENABLE_STRICT_COMPILATION=ON \ - -DPACKAGE_NAME_SUFFIX:STRING="$VCMI_PACKAGE_NAME_SUFFIX" \ - -DPACKAGE_FILE_NAME:STRING="$VCMI_PACKAGE_FILE_NAME" \ - -DENABLE_GITVERSION="$VCMI_PACKAGE_GITVERSION" - env: - CC: ${{ matrix.cc }} - CXX: ${{ matrix.cxx }} - - name: CMake Preset - if: "${{ matrix.preset != '' }}" run: | cmake --preset ${{ matrix.preset }} - - name: Build - if: "${{ matrix.preset == '' }}" - run: | - cmake --build '${{github.workspace}}/out/build/${{matrix.preset}}' - - name: Build Preset - if: "${{ matrix.preset != '' }}" run: | cmake --build --preset ${{matrix.preset}} - name: Test - if: ${{ matrix.test == 1 && matrix.preset != ''}} + if: ${{ matrix.test == 1 }} run: | ctest --preset ${{matrix.preset}} @@ -214,7 +189,7 @@ jobs: rm -rf _CPack_Packages - name: Additional logs - if: ${{ failure() && steps.cpack.outcome == 'failure' && matrix.platform == 'mxe' }} + if: ${{ failure() && steps.cpack.outcome == 'failure' && matrix.platform == 'msvc' }} run: | cat '${{github.workspace}}/out/build/${{matrix.preset}}/_CPack_Packages/win32/NSIS/project.nsi' cat '${{github.workspace}}/out/build/${{matrix.preset}}/_CPack_Packages/win32/NSIS/NSISOutput.log' @@ -228,7 +203,7 @@ jobs: ${{github.workspace}}/**/${{ env.VCMI_PACKAGE_FILE_NAME }}.${{ matrix.extension }} - name: Upload build - if: ${{ matrix.pack == 1 && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/beta' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/features/')) && matrix.platform != 'msvc' }} + if: ${{ matrix.pack == 1 && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/beta' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/features/')) && matrix.platform == 'msvc' }} run: | cd '${{github.workspace}}/out/build/${{matrix.preset}}' source '${{github.workspace}}/CI/upload_package.sh' @@ -246,7 +221,7 @@ jobs: - name: Trigger Android uses: peter-evans/repository-dispatch@v1 - if: ${{ (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/beta' || github.ref == 'refs/heads/master') && matrix.platform == 'mxe' }} + if: ${{ (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/beta' || github.ref == 'refs/heads/master') && matrix.platform == 'msvc' }} with: token: ${{ secrets.VCMI_ANDROID_ACCESS_TOKEN }} repository: vcmi/vcmi-android From 8e13ed74d7644ea8b1cffae5018561e0fbd0641b Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 31 Jan 2023 18:21:49 +0200 Subject: [PATCH 40/79] CMake version bump to 3.16, removed MXE workarounds --- CMakeLists.txt | 43 +++++++------------------------------------ 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 480f97f41..aec633ff8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Minimum required version greatly affect CMake behavior # So cmake_minimum_required must be called before the project() -# 3.10.0 is used since it's minimal in MXE dependencies for now -cmake_minimum_required(VERSION 3.10.0) +# 3.16.0 is used since it's used by our currently oldest suppored system: Ubuntu-20.04 +cmake_minimum_required(VERSION 3.16.0) project(VCMI) # TODO @@ -10,9 +10,6 @@ project(VCMI) # Cmake put them after all install code of main CMakelists in cmake_install.cmake # Currently I just added extra add_subdirectory and CMakeLists.txt in osx directory to bypass that. # -# MXE: -# - Try to implement MXE support into BundleUtilities so we can deploy deps automatically -# # Vckpg: # - Improve install code once there is better way to deploy DLLs and Qt plugins # @@ -57,9 +54,8 @@ if(APPLE_IOS) else() option(ENABLE_TEST "Enable compilation of unit tests" OFF) endif() -if(NOT ${CMAKE_VERSION} VERSION_LESS "3.16.0") - option(ENABLE_PCH "Enable compilation using precompiled headers" ON) -endif(NOT ${CMAKE_VERSION} VERSION_LESS "3.16.0") + +option(ENABLE_PCH "Enable compilation using precompiled headers" ON) option(ENABLE_GITVERSION "Enable Version.cpp with Git commit hash" ON) option(ENABLE_DEBUG_CONSOLE "Enable debug console for Windows builds" ON) option(ENABLE_STRICT_COMPILATION "Treat all compiler warnings as errors" OFF) @@ -90,11 +86,6 @@ if(APPLE_IOS AND COPY_CONFIG_ON_BUILD) set(COPY_CONFIG_ON_BUILD OFF) endif() -# No QT Linguist on MXE -if((MINGW) AND (${CMAKE_CROSSCOMPILING}) AND (NOT USING_CONAN)) - set(ENABLE_TRANSLATIONS OFF) -endif() - ############################################ # Miscellaneous options # ############################################ @@ -138,10 +129,6 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_ set(ENABLE_PCH OFF) # broken endif() -if( ${CMAKE_VERSION} VERSION_LESS "3.16.0") - set(ENABLE_PCH OFF) #not supported -endif() - if(ENABLE_PCH) macro(enable_pch name) target_precompile_headers(${name} PRIVATE $<$:>) @@ -296,13 +283,6 @@ if(CMAKE_COMPILER_IS_GNUCXX OR NOT WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-sign-compare") # low chance of any significant issues set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-varargs") # emitted in fuzzylite headers, disabled - if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-pragmas") # emitted only by ancient gcc 5.5 in MXE build, remove after upgrade - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas") # emitted only by ancient gcc 5.5 in MXE build, remove after upgrade - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-variable") # emitted only by ancient gcc 5.5 in MXE build, remove after upgrade - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-maybe-uninitialized") # emitted only by ancient gcc 5.5 in MXE build, remove after upgrade - endif() - if(ENABLE_STRICT_COMPILATION) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=array-bounds") # false positives in boost::multiarray during release build, keep as warning-only @@ -407,14 +387,7 @@ endif() if(ENABLE_LUA) find_package(luajit) - # MXE paths hardcoded for current dependencies pack - tried and could not make it work another way - if((MINGW) AND (${CMAKE_CROSSCOMPILING}) AND (DEFINED MSYS) AND (NOT TARGET luajit::luajit)) - add_library(luajit::luajit STATIC IMPORTED) - set_target_properties(luajit::luajit PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "/usr/lib/mxe/usr/i686-w64-mingw32.static/include/luajit-2.0") - set_target_properties(luajit::luajit PROPERTIES - IMPORTED_LOCATION "/usr/lib/mxe/usr/i686-w64-mingw32.static/lib/libluajit-5.1.a") - endif() + if(TARGET luajit::luajit) message(STATUS "Using LuaJIT provided by system") else() @@ -580,9 +553,7 @@ if(WIN32) "${CMAKE_FIND_ROOT_PATH}/bin/*.dll") endif() - if((${CMAKE_CROSSCOMPILING}) AND (DEFINED MSYS)) - message(STATUS "Detected MXE build") - elseif(CMAKE_BUILD_TYPE MATCHES Debug) + if(CMAKE_BUILD_TYPE MATCHES Debug) # Copy debug versions of libraries if build type is debug set(debug_postfix d) endif() @@ -685,7 +656,7 @@ if(WIN32) set(CPACK_NSIS_URL_INFO_ABOUT "http://vcmi.eu/") set(CPACK_NSIS_CONTACT @CPACK_PACKAGE_CONTACT@) set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") - # Use BundleUtilities to fix build when Vcpkg is used and disable it for MXE + # Use BundleUtilities to fix build when Vcpkg is used and disable it for mingw if(NOT (${CMAKE_CROSSCOMPILING})) add_subdirectory(win) endif() From 13dde2c4f3907170bafc408b770587704f08fdfc Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 31 Jan 2023 18:50:22 +0200 Subject: [PATCH 41/79] Removed old info from readme --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 535a192fd..4c6995ddf 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,6 @@ Platform support is constantly tested by continuous integration and CMake config * (optional) All platforms: [using Conan package manager to obtain prebuilt dependencies](docs/conan.md) * [On Linux](https://wiki.vcmi.eu/How_to_build_VCMI_(Linux)) - * [On Linux for Windows with MXE](https://wiki.vcmi.eu/How_to_build_VCMI_(Linux/Cmake/MXE)) * [On macOS](https://wiki.vcmi.eu/How_to_build_VCMI_(macOS)) * [On Windows using MSVC and Vcpkg](https://wiki.vcmi.eu/How_to_build_VCMI_(Windows/Vcpkg)) * [iOS on macOS](https://wiki.vcmi.eu/How_to_build_VCMI_(iOS)) From c72fb1bcfe75a3818309f791b3fbb08af65a96f0 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 31 Jan 2023 19:38:01 +0200 Subject: [PATCH 42/79] Added conan+mingw info to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4c6995ddf..e56020618 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Platform support is constantly tested by continuous integration and CMake config * (optional) All platforms: [using Conan package manager to obtain prebuilt dependencies](docs/conan.md) * [On Linux](https://wiki.vcmi.eu/How_to_build_VCMI_(Linux)) + * [On Linux for Windows with Conan and mingw]( https://wiki.vcmi.eu/How_to_build_VCMI_(Linux/Cmake/Conan) * [On macOS](https://wiki.vcmi.eu/How_to_build_VCMI_(macOS)) * [On Windows using MSVC and Vcpkg](https://wiki.vcmi.eu/How_to_build_VCMI_(Windows/Vcpkg)) * [iOS on macOS](https://wiki.vcmi.eu/How_to_build_VCMI_(iOS)) From 2f31033dbaeed1aa4b23a51a3f60f882538eeae3 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 31 Jan 2023 19:48:24 +0200 Subject: [PATCH 43/79] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e56020618..1af484ad5 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Platform support is constantly tested by continuous integration and CMake config * (optional) All platforms: [using Conan package manager to obtain prebuilt dependencies](docs/conan.md) * [On Linux](https://wiki.vcmi.eu/How_to_build_VCMI_(Linux)) - * [On Linux for Windows with Conan and mingw]( https://wiki.vcmi.eu/How_to_build_VCMI_(Linux/Cmake/Conan) + * [On Linux for Windows with Conan and mingw](https://wiki.vcmi.eu/How_to_build_VCMI_(Linux/Cmake/Conan)) * [On macOS](https://wiki.vcmi.eu/How_to_build_VCMI_(macOS)) * [On Windows using MSVC and Vcpkg](https://wiki.vcmi.eu/How_to_build_VCMI_(Windows/Vcpkg)) * [iOS on macOS](https://wiki.vcmi.eu/How_to_build_VCMI_(iOS)) From 8a9492d129c751833455502c8c8721164d7d375c Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 13:09:19 +0200 Subject: [PATCH 44/79] Moved client files to more suitable locations --- client/{widgets => adventureMap}/AdventureMapClasses.cpp | 0 client/{widgets => adventureMap}/AdventureMapClasses.h | 0 client/{windows => adventureMap}/CAdvmapInterface.cpp | 0 client/{windows => adventureMap}/CAdvmapInterface.h | 0 client/{ => adventureMap}/mapHandler.cpp | 0 client/{ => adventureMap}/mapHandler.h | 0 client/{gui => render}/CAnimation.cpp | 0 client/{gui => render}/CAnimation.h | 0 client/{ => render}/CBitmapHandler.cpp | 0 client/{ => render}/CBitmapHandler.h | 0 client/{gui => render}/Canvas.cpp | 0 client/{gui => render}/Canvas.h | 0 client/{gui => render}/ColorFilter.cpp | 0 client/{gui => render}/ColorFilter.h | 0 client/{gui => render}/Fonts.cpp | 0 client/{gui => render}/Fonts.h | 0 client/{ => render}/Graphics.cpp | 0 client/{ => render}/Graphics.h | 0 client/{ => render}/SDLRWwrapper.cpp | 0 client/{ => render}/SDLRWwrapper.h | 0 client/{gui => render}/SDL_Extensions.cpp | 0 client/{gui => render}/SDL_Extensions.h | 0 client/{gui => render}/SDL_PixelAccess.h | 0 client/{ => widgets}/CreatureCostBox.cpp | 0 client/{ => widgets}/CreatureCostBox.h | 0 client/{ => windows}/CMessage.cpp | 0 client/{ => windows}/CMessage.h | 0 27 files changed, 0 insertions(+), 0 deletions(-) rename client/{widgets => adventureMap}/AdventureMapClasses.cpp (100%) rename client/{widgets => adventureMap}/AdventureMapClasses.h (100%) rename client/{windows => adventureMap}/CAdvmapInterface.cpp (100%) rename client/{windows => adventureMap}/CAdvmapInterface.h (100%) rename client/{ => adventureMap}/mapHandler.cpp (100%) rename client/{ => adventureMap}/mapHandler.h (100%) rename client/{gui => render}/CAnimation.cpp (100%) rename client/{gui => render}/CAnimation.h (100%) rename client/{ => render}/CBitmapHandler.cpp (100%) rename client/{ => render}/CBitmapHandler.h (100%) rename client/{gui => render}/Canvas.cpp (100%) rename client/{gui => render}/Canvas.h (100%) rename client/{gui => render}/ColorFilter.cpp (100%) rename client/{gui => render}/ColorFilter.h (100%) rename client/{gui => render}/Fonts.cpp (100%) rename client/{gui => render}/Fonts.h (100%) rename client/{ => render}/Graphics.cpp (100%) rename client/{ => render}/Graphics.h (100%) rename client/{ => render}/SDLRWwrapper.cpp (100%) rename client/{ => render}/SDLRWwrapper.h (100%) rename client/{gui => render}/SDL_Extensions.cpp (100%) rename client/{gui => render}/SDL_Extensions.h (100%) rename client/{gui => render}/SDL_PixelAccess.h (100%) rename client/{ => widgets}/CreatureCostBox.cpp (100%) rename client/{ => widgets}/CreatureCostBox.h (100%) rename client/{ => windows}/CMessage.cpp (100%) rename client/{ => windows}/CMessage.h (100%) diff --git a/client/widgets/AdventureMapClasses.cpp b/client/adventureMap/AdventureMapClasses.cpp similarity index 100% rename from client/widgets/AdventureMapClasses.cpp rename to client/adventureMap/AdventureMapClasses.cpp diff --git a/client/widgets/AdventureMapClasses.h b/client/adventureMap/AdventureMapClasses.h similarity index 100% rename from client/widgets/AdventureMapClasses.h rename to client/adventureMap/AdventureMapClasses.h diff --git a/client/windows/CAdvmapInterface.cpp b/client/adventureMap/CAdvmapInterface.cpp similarity index 100% rename from client/windows/CAdvmapInterface.cpp rename to client/adventureMap/CAdvmapInterface.cpp diff --git a/client/windows/CAdvmapInterface.h b/client/adventureMap/CAdvmapInterface.h similarity index 100% rename from client/windows/CAdvmapInterface.h rename to client/adventureMap/CAdvmapInterface.h diff --git a/client/mapHandler.cpp b/client/adventureMap/mapHandler.cpp similarity index 100% rename from client/mapHandler.cpp rename to client/adventureMap/mapHandler.cpp diff --git a/client/mapHandler.h b/client/adventureMap/mapHandler.h similarity index 100% rename from client/mapHandler.h rename to client/adventureMap/mapHandler.h diff --git a/client/gui/CAnimation.cpp b/client/render/CAnimation.cpp similarity index 100% rename from client/gui/CAnimation.cpp rename to client/render/CAnimation.cpp diff --git a/client/gui/CAnimation.h b/client/render/CAnimation.h similarity index 100% rename from client/gui/CAnimation.h rename to client/render/CAnimation.h diff --git a/client/CBitmapHandler.cpp b/client/render/CBitmapHandler.cpp similarity index 100% rename from client/CBitmapHandler.cpp rename to client/render/CBitmapHandler.cpp diff --git a/client/CBitmapHandler.h b/client/render/CBitmapHandler.h similarity index 100% rename from client/CBitmapHandler.h rename to client/render/CBitmapHandler.h diff --git a/client/gui/Canvas.cpp b/client/render/Canvas.cpp similarity index 100% rename from client/gui/Canvas.cpp rename to client/render/Canvas.cpp diff --git a/client/gui/Canvas.h b/client/render/Canvas.h similarity index 100% rename from client/gui/Canvas.h rename to client/render/Canvas.h diff --git a/client/gui/ColorFilter.cpp b/client/render/ColorFilter.cpp similarity index 100% rename from client/gui/ColorFilter.cpp rename to client/render/ColorFilter.cpp diff --git a/client/gui/ColorFilter.h b/client/render/ColorFilter.h similarity index 100% rename from client/gui/ColorFilter.h rename to client/render/ColorFilter.h diff --git a/client/gui/Fonts.cpp b/client/render/Fonts.cpp similarity index 100% rename from client/gui/Fonts.cpp rename to client/render/Fonts.cpp diff --git a/client/gui/Fonts.h b/client/render/Fonts.h similarity index 100% rename from client/gui/Fonts.h rename to client/render/Fonts.h diff --git a/client/Graphics.cpp b/client/render/Graphics.cpp similarity index 100% rename from client/Graphics.cpp rename to client/render/Graphics.cpp diff --git a/client/Graphics.h b/client/render/Graphics.h similarity index 100% rename from client/Graphics.h rename to client/render/Graphics.h diff --git a/client/SDLRWwrapper.cpp b/client/render/SDLRWwrapper.cpp similarity index 100% rename from client/SDLRWwrapper.cpp rename to client/render/SDLRWwrapper.cpp diff --git a/client/SDLRWwrapper.h b/client/render/SDLRWwrapper.h similarity index 100% rename from client/SDLRWwrapper.h rename to client/render/SDLRWwrapper.h diff --git a/client/gui/SDL_Extensions.cpp b/client/render/SDL_Extensions.cpp similarity index 100% rename from client/gui/SDL_Extensions.cpp rename to client/render/SDL_Extensions.cpp diff --git a/client/gui/SDL_Extensions.h b/client/render/SDL_Extensions.h similarity index 100% rename from client/gui/SDL_Extensions.h rename to client/render/SDL_Extensions.h diff --git a/client/gui/SDL_PixelAccess.h b/client/render/SDL_PixelAccess.h similarity index 100% rename from client/gui/SDL_PixelAccess.h rename to client/render/SDL_PixelAccess.h diff --git a/client/CreatureCostBox.cpp b/client/widgets/CreatureCostBox.cpp similarity index 100% rename from client/CreatureCostBox.cpp rename to client/widgets/CreatureCostBox.cpp diff --git a/client/CreatureCostBox.h b/client/widgets/CreatureCostBox.h similarity index 100% rename from client/CreatureCostBox.h rename to client/widgets/CreatureCostBox.h diff --git a/client/CMessage.cpp b/client/windows/CMessage.cpp similarity index 100% rename from client/CMessage.cpp rename to client/windows/CMessage.cpp diff --git a/client/CMessage.h b/client/windows/CMessage.h similarity index 100% rename from client/CMessage.h rename to client/windows/CMessage.h From 134b40363fe8f8a3e943fdceece0d4bcc56433ed Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 13:47:05 +0200 Subject: [PATCH 45/79] Created separate file for CInGameConsole --- .../adventureMap/{AdventureMapClasses.cpp => CInGameConsole.cpp} | 0 client/adventureMap/{AdventureMapClasses.h => CInGameConsole.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/adventureMap/{AdventureMapClasses.cpp => CInGameConsole.cpp} (100%) rename client/adventureMap/{AdventureMapClasses.h => CInGameConsole.h} (100%) diff --git a/client/adventureMap/AdventureMapClasses.cpp b/client/adventureMap/CInGameConsole.cpp similarity index 100% rename from client/adventureMap/AdventureMapClasses.cpp rename to client/adventureMap/CInGameConsole.cpp diff --git a/client/adventureMap/AdventureMapClasses.h b/client/adventureMap/CInGameConsole.h similarity index 100% rename from client/adventureMap/AdventureMapClasses.h rename to client/adventureMap/CInGameConsole.h From 87498287f581f4053e299bbc660350ea032501e1 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 13:48:26 +0200 Subject: [PATCH 46/79] Created separate file for CAdvMapPanel --- client/adventureMap/{AdventureMapClasses.cpp => CAdvMapPanel.cpp} | 0 client/adventureMap/{AdventureMapClasses.h => CAdvMapPanel.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/adventureMap/{AdventureMapClasses.cpp => CAdvMapPanel.cpp} (100%) rename client/adventureMap/{AdventureMapClasses.h => CAdvMapPanel.h} (100%) diff --git a/client/adventureMap/AdventureMapClasses.cpp b/client/adventureMap/CAdvMapPanel.cpp similarity index 100% rename from client/adventureMap/AdventureMapClasses.cpp rename to client/adventureMap/CAdvMapPanel.cpp diff --git a/client/adventureMap/AdventureMapClasses.h b/client/adventureMap/CAdvMapPanel.h similarity index 100% rename from client/adventureMap/AdventureMapClasses.h rename to client/adventureMap/CAdvMapPanel.h From 27f2e4fd33e9e1f7944408c192214183b58b70d7 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 13:49:31 +0200 Subject: [PATCH 47/79] Created separate file for CMinimap --- client/adventureMap/{AdventureMapClasses.cpp => CMinimap.cpp} | 0 client/adventureMap/{AdventureMapClasses.h => CMinimap.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/adventureMap/{AdventureMapClasses.cpp => CMinimap.cpp} (100%) rename client/adventureMap/{AdventureMapClasses.h => CMinimap.h} (100%) diff --git a/client/adventureMap/AdventureMapClasses.cpp b/client/adventureMap/CMinimap.cpp similarity index 100% rename from client/adventureMap/AdventureMapClasses.cpp rename to client/adventureMap/CMinimap.cpp diff --git a/client/adventureMap/AdventureMapClasses.h b/client/adventureMap/CMinimap.h similarity index 100% rename from client/adventureMap/AdventureMapClasses.h rename to client/adventureMap/CMinimap.h From d0c6627cdb91da4a3b9a7b8a68a5bf5d1a58551a Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 13:50:13 +0200 Subject: [PATCH 48/79] Created separate file for CList --- client/adventureMap/{AdventureMapClasses.cpp => CList.cpp} | 0 client/adventureMap/{AdventureMapClasses.h => CList.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/adventureMap/{AdventureMapClasses.cpp => CList.cpp} (100%) rename client/adventureMap/{AdventureMapClasses.h => CList.h} (100%) diff --git a/client/adventureMap/AdventureMapClasses.cpp b/client/adventureMap/CList.cpp similarity index 100% rename from client/adventureMap/AdventureMapClasses.cpp rename to client/adventureMap/CList.cpp diff --git a/client/adventureMap/AdventureMapClasses.h b/client/adventureMap/CList.h similarity index 100% rename from client/adventureMap/AdventureMapClasses.h rename to client/adventureMap/CList.h From ef236be2dad9e0241f3b5fbacd4a939f35012142 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 13:55:56 +0200 Subject: [PATCH 49/79] Created separate file for CInfoBar --- client/adventureMap/{AdventureMapClasses.cpp => CInfoBar.cpp} | 0 client/adventureMap/{AdventureMapClasses.h => CInfoBar.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/adventureMap/{AdventureMapClasses.cpp => CInfoBar.cpp} (100%) rename client/adventureMap/{AdventureMapClasses.h => CInfoBar.h} (100%) diff --git a/client/adventureMap/AdventureMapClasses.cpp b/client/adventureMap/CInfoBar.cpp similarity index 100% rename from client/adventureMap/AdventureMapClasses.cpp rename to client/adventureMap/CInfoBar.cpp diff --git a/client/adventureMap/AdventureMapClasses.h b/client/adventureMap/CInfoBar.h similarity index 100% rename from client/adventureMap/AdventureMapClasses.h rename to client/adventureMap/CInfoBar.h From 9366506e2ca37ae6ef17d06a92dd1c52b3d75626 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 14:01:48 +0200 Subject: [PATCH 50/79] Finalized split of AdventureMapClasses --- client/adventureMap/CAdvMapPanel.cpp | 1127 +----------------------- client/adventureMap/CAdvMapPanel.h | 354 -------- client/adventureMap/CInGameConsole.cpp | 969 -------------------- client/adventureMap/CInGameConsole.h | 365 -------- client/adventureMap/CInfoBar.cpp | 908 ------------------- client/adventureMap/CInfoBar.h | 275 ------ client/adventureMap/CList.cpp | 891 ------------------- client/adventureMap/CList.h | 240 ----- client/adventureMap/CMinimap.cpp | 914 ------------------- client/adventureMap/CMinimap.h | 330 ------- 10 files changed, 1 insertion(+), 6372 deletions(-) diff --git a/client/adventureMap/CAdvMapPanel.cpp b/client/adventureMap/CAdvMapPanel.cpp index b2d83416c..3820966ce 100644 --- a/client/adventureMap/CAdvMapPanel.cpp +++ b/client/adventureMap/CAdvMapPanel.cpp @@ -47,1132 +47,6 @@ #include #include -CList::CListItem::CListItem(CList * Parent) - : CIntObject(LCLICK | RCLICK | HOVER), - parent(Parent), - selection() -{ - defActions = 255-DISPOSE; -} - -CList::CListItem::~CListItem() -{ -} - -void CList::CListItem::clickRight(tribool down, bool previousState) -{ - if (down == true) - showTooltip(); -} - -void CList::CListItem::clickLeft(tribool down, bool previousState) -{ - if(down == true) - { - //second click on already selected item - if(parent->selected == this->shared_from_this()) - { - open(); - } - else - { - //first click - switch selection - parent->select(this->shared_from_this()); - } - } -} - -void CList::CListItem::hover(bool on) -{ - if (on) - GH.statusbar->write(getHoverText()); - else - GH.statusbar->clear(); -} - -void CList::CListItem::onSelect(bool on) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - selection.reset(); - if(on) - selection = genSelection(); - select(on); - GH.totalRedraw(); -} - -CList::CList(int Size, Point position, std::string btnUp, std::string btnDown, size_t listAmount, int helpUp, int helpDown, CListBox::CreateFunc create) - : CIntObject(0, position), - size(Size), - selected(nullptr) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - scrollUp = std::make_shared(Point(0, 0), btnUp, CGI->generaltexth->zelp[helpUp]); - scrollDown = std::make_shared(Point(0, scrollUp->pos.h + 32*(int)size), btnDown, CGI->generaltexth->zelp[helpDown]); - - listBox = std::make_shared(create, Point(1,scrollUp->pos.h), Point(0, 32), size, listAmount); - - //assign callback only after list was created - scrollUp->addCallback(std::bind(&CListBox::moveToPrev, listBox)); - scrollDown->addCallback(std::bind(&CListBox::moveToNext, listBox)); - - scrollUp->addCallback(std::bind(&CList::update, this)); - scrollDown->addCallback(std::bind(&CList::update, this)); - - update(); -} - -void CList::update() -{ - bool onTop = listBox->getPos() == 0; - bool onBottom = listBox->getPos() + size >= listBox->size(); - - scrollUp->block(onTop); - scrollDown->block(onBottom); -} - -void CList::select(std::shared_ptr which) -{ - if(selected == which) - return; - - if(selected) - selected->onSelect(false); - - selected = which; - if(which) - { - which->onSelect(true); - onSelect(); - } -} - -int CList::getSelectedIndex() -{ - return static_cast(listBox->getIndexOf(selected)); -} - -void CList::selectIndex(int which) -{ - if(which < 0) - { - if(selected) - select(nullptr); - } - else - { - listBox->scrollTo(which); - update(); - select(std::dynamic_pointer_cast(listBox->getItem(which))); - } -} - -void CList::selectNext() -{ - int index = getSelectedIndex() + 1; - if(index >= listBox->size()) - index = 0; - selectIndex(index); -} - -void CList::selectPrev() -{ - int index = getSelectedIndex(); - if(index <= 0) - selectIndex(0); - else - selectIndex(index-1); -} - -CHeroList::CEmptyHeroItem::CEmptyHeroItem() -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - movement = std::make_shared("IMOBIL", 0, 0, 0, 1); - portrait = std::make_shared("HPSXXX", movement->pos.w + 1, 0); - mana = std::make_shared("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1 ); - - pos.w = mana->pos.w + mana->pos.x - pos.x; - pos.h = std::max(std::max(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h); -} - -CHeroList::CHeroItem::CHeroItem(CHeroList *parent, const CGHeroInstance * Hero) - : CListItem(parent), - hero(Hero) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - movement = std::make_shared("IMOBIL", 0, 0, 0, 1); - portrait = std::make_shared("PortraitsSmall", hero->portrait, 0, movement->pos.w + 1); - mana = std::make_shared("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1); - - pos.w = mana->pos.w + mana->pos.x - pos.x; - pos.h = std::max(std::max(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h); - - update(); -} - -void CHeroList::CHeroItem::update() -{ - movement->setFrame(std::min(movement->size()-1, hero->movement / 100)); - mana->setFrame(std::min(mana->size()-1, hero->mana / 5)); - redraw(); -} - -std::shared_ptr CHeroList::CHeroItem::genSelection() -{ - return std::make_shared("HPSYYY", movement->pos.w + 1, 0); -} - -void CHeroList::CHeroItem::select(bool on) -{ - if(on && adventureInt->selection != hero) - adventureInt->select(hero); -} - -void CHeroList::CHeroItem::open() -{ - LOCPLINT->openHeroWindow(hero); -} - -void CHeroList::CHeroItem::showTooltip() -{ - CRClickPopup::createAndPush(hero, GH.getCursorPosition()); -} - -std::string CHeroList::CHeroItem::getHoverText() -{ - return boost::str(boost::format(CGI->generaltexth->allTexts[15]) % hero->getNameTranslated() % hero->type->heroClass->getNameTranslated()); -} - -std::shared_ptr CHeroList::createHeroItem(size_t index) -{ - if (LOCPLINT->wanderingHeroes.size() > index) - return std::make_shared(this, LOCPLINT->wanderingHeroes[index]); - return std::make_shared(); -} - -CHeroList::CHeroList(int size, Point position, std::string btnUp, std::string btnDown): - CList(size, position, btnUp, btnDown, LOCPLINT->wanderingHeroes.size(), 303, 304, std::bind(&CHeroList::createHeroItem, this, _1)) -{ -} - -void CHeroList::select(const CGHeroInstance * hero) -{ - selectIndex(vstd::find_pos(LOCPLINT->wanderingHeroes, hero)); -} - -void CHeroList::update(const CGHeroInstance * hero) -{ - //this hero is already present, update its status - for(auto & elem : listBox->getItems()) - { - auto item = std::dynamic_pointer_cast(elem); - if(item && item->hero == hero && vstd::contains(LOCPLINT->wanderingHeroes, hero)) - { - item->update(); - return; - } - } - //simplest solution for now: reset list and restore selection - - listBox->resize(LOCPLINT->wanderingHeroes.size()); - if (adventureInt->selection) - { - auto selectedHero = dynamic_cast(adventureInt->selection); - if (selectedHero) - select(selectedHero); - } - CList::update(); -} - -std::shared_ptr CTownList::createTownItem(size_t index) -{ - if (LOCPLINT->towns.size() > index) - return std::make_shared(this, LOCPLINT->towns[index]); - return std::make_shared("ITPA", 0); -} - -CTownList::CTownItem::CTownItem(CTownList *parent, const CGTownInstance *Town): - CListItem(parent), - town(Town) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - picture = std::make_shared("ITPA", 0); - pos = picture->pos; - update(); -} - -std::shared_ptr CTownList::CTownItem::genSelection() -{ - return std::make_shared("ITPA", 1); -} - -void CTownList::CTownItem::update() -{ - size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN]; - - picture->setFrame(iconIndex + 2); - redraw(); -} - -void CTownList::CTownItem::select(bool on) -{ - if (on && adventureInt->selection != town) - adventureInt->select(town); -} - -void CTownList::CTownItem::open() -{ - LOCPLINT->openTownWindow(town); -} - -void CTownList::CTownItem::showTooltip() -{ - CRClickPopup::createAndPush(town, GH.getCursorPosition()); -} - -std::string CTownList::CTownItem::getHoverText() -{ - return town->getObjectName(); -} - -CTownList::CTownList(int size, Point position, std::string btnUp, std::string btnDown): - CList(size, position, btnUp, btnDown, LOCPLINT->towns.size(), 306, 307, std::bind(&CTownList::createTownItem, this, _1)) -{ -} - -void CTownList::select(const CGTownInstance * town) -{ - selectIndex(vstd::find_pos(LOCPLINT->towns, town)); -} - -void CTownList::update(const CGTownInstance *) -{ - //simplest solution for now: reset list and restore selection - - listBox->resize(LOCPLINT->towns.size()); - if (adventureInt->selection) - { - auto town = dynamic_cast(adventureInt->selection); - if (town) - select(town); - } - CList::update(); -} - -const SDL_Color & CMinimapInstance::getTileColor(const int3 & pos) -{ - const TerrainTile * tile = LOCPLINT->cb->getTile(pos, false); - - // if tile is not visible it will be black on minimap - if(!tile) - return Colors::BLACK; - - // if object at tile is owned - it will be colored as its owner - for (const CGObjectInstance *obj : tile->blockingObjects) - { - //heroes will be blitted later - switch (obj->ID) - { - case Obj::HERO: - case Obj::PRISON: - continue; - } - - PlayerColor player = obj->getOwner(); - if(player == PlayerColor::NEUTRAL) - return *graphics->neutralColor; - else - if (player < PlayerColor::PLAYER_LIMIT) - return graphics->playerColors[player.getNum()]; - } - - // else - use terrain color (blocked version or normal) - const auto & colorPair = parent->colors.find(tile->terType->getId())->second; - if (tile->blocked && (!tile->visitable)) - return colorPair.second; - else - return colorPair.first; -} -void CMinimapInstance::tileToPixels (const int3 &tile, int &x, int &y, int toX, int toY) -{ - int3 mapSizes = LOCPLINT->cb->getMapSize(); - - double stepX = double(pos.w) / mapSizes.x; - double stepY = double(pos.h) / mapSizes.y; - - x = static_cast(toX + stepX * tile.x); - y = static_cast(toY + stepY * tile.y); -} - -void CMinimapInstance::blitTileWithColor(const SDL_Color &color, const int3 &tile, SDL_Surface *to, int toX, int toY) -{ - //coordinates of rectangle on minimap representing this tile - // begin - first to blit, end - first NOT to blit - int xBegin, yBegin, xEnd, yEnd; - tileToPixels (tile, xBegin, yBegin, toX, toY); - tileToPixels (int3 (tile.x + 1, tile.y + 1, tile.z), xEnd, yEnd, toX, toY); - - for (int y=yBegin; ypixels + y * to->pitch + xBegin * minimap->format->BytesPerPixel; - - for (int x=xBegin; x::PutColor(ptr, color); - } -} - -void CMinimapInstance::refreshTile(const int3 &tile) -{ - blitTileWithColor(getTileColor(int3(tile.x, tile.y, level)), tile, minimap, 0, 0); -} - -void CMinimapInstance::drawScaled(int level) -{ - int3 mapSizes = LOCPLINT->cb->getMapSize(); - - //size of one map tile on our minimap - double stepX = double(pos.w) / mapSizes.x; - double stepY = double(pos.h) / mapSizes.y; - - double currY = 0; - for (int y=0; y(currX); - int yBegin = static_cast(currY); - int xEnd = static_cast(currX + stepX); - int yEnd = static_cast(currY + stepY); - - for (int y=yBegin; ypixels + y * minimap->pitch + xBegin * minimap->format->BytesPerPixel; - - for (int x=xBegin; x::PutColor(ptr, color); - } - } - } -} - -CMinimapInstance::CMinimapInstance(CMinimap *Parent, int Level): - parent(Parent), - minimap(CSDL_Ext::createSurfaceWithBpp<4>(parent->pos.w, parent->pos.h)), - level(Level) -{ - pos.w = parent->pos.w; - pos.h = parent->pos.h; - drawScaled(level); -} - -CMinimapInstance::~CMinimapInstance() -{ - SDL_FreeSurface(minimap); -} - -void CMinimapInstance::showAll(SDL_Surface * to) -{ - blitAtLoc(minimap, 0, 0, to); - - //draw heroes - std::vector heroes = LOCPLINT->cb->getHeroesInfo(false); //TODO: do we really need separate function for drawing heroes? - for(auto & hero : heroes) - { - int3 position = hero->visitablePos(); - if(position.z == level) - { - const SDL_Color & color = graphics->playerColors[hero->getOwner().getNum()]; - blitTileWithColor(color, position, to, pos.x, pos.y); - } - } -} - -std::map > CMinimap::loadColors() -{ - std::map > ret; - - for(const auto & terrain : CGI->terrainTypeHandler->objects) - { - SDL_Color normal = CSDL_Ext::toSDL(terrain->minimapUnblocked); - SDL_Color blocked = CSDL_Ext::toSDL(terrain->minimapBlocked); - - ret[terrain->getId()] = std::make_pair(normal, blocked); - } - return ret; -} - -CMinimap::CMinimap(const Rect & position) - : CIntObject(LCLICK | RCLICK | HOVER | MOVE, position.topLeft()), - level(0), - colors(loadColors()) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - pos.w = position.w; - pos.h = position.h; - - aiShield = std::make_shared("AIShield"); - aiShield->disable(); -} - -int3 CMinimap::translateMousePosition() -{ - // 0 = top-left corner, 1 = bottom-right corner - double dx = double(GH.getCursorPosition().x - pos.x) / pos.w; - double dy = double(GH.getCursorPosition().y - pos.y) / pos.h; - - int3 mapSizes = LOCPLINT->cb->getMapSize(); - - int3 tile ((si32)(mapSizes.x * dx), (si32)(mapSizes.y * dy), level); - return tile; -} - -void CMinimap::moveAdvMapSelection() -{ - int3 newLocation = translateMousePosition(); - adventureInt->centerOn(newLocation); - - if (!(adventureInt->active & GENERAL)) - GH.totalRedraw(); //redraw this as well as inactive adventure map - else - redraw();//redraw only this -} - -void CMinimap::clickLeft(tribool down, bool previousState) -{ - if(down) - moveAdvMapSelection(); -} - -void CMinimap::clickRight(tribool down, bool previousState) -{ - adventureInt->handleRightClick(CGI->generaltexth->zelp[291].second, down); -} - -void CMinimap::hover(bool on) -{ - if(on) - GH.statusbar->write(CGI->generaltexth->zelp[291].first); - else - GH.statusbar->clear(); -} - -void CMinimap::mouseMoved(const SDL_MouseMotionEvent & sEvent) -{ - if(mouseState(EIntObjMouseBtnType::LEFT)) - moveAdvMapSelection(); -} - -void CMinimap::showAll(SDL_Surface * to) -{ - CIntObject::showAll(to); - if(minimap) - { - int3 mapSizes = LOCPLINT->cb->getMapSize(); - int3 tileCountOnScreen = adventureInt->terrain.tileCountOnScreen(); - - //draw radar - Rect oldClip; - Rect radar = - { - si16(adventureInt->position.x * pos.w / mapSizes.x + pos.x), - si16(adventureInt->position.y * pos.h / mapSizes.y + pos.y), - ui16(tileCountOnScreen.x * pos.w / mapSizes.x), - ui16(tileCountOnScreen.y * pos.h / mapSizes.y) - }; - - if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) - { - // adjusts radar so that it doesn't go out of map in world view mode (since there's no frame) - radar.x = std::min(std::max(pos.x, radar.x), pos.x + pos.w - radar.w); - radar.y = std::min(std::max(pos.y, radar.y), pos.y + pos.h - radar.h); - - if(radar.x < pos.x && radar.y < pos.y) - return; // whole map is visible at once, no point in redrawing border - } - - CSDL_Ext::getClipRect(to, oldClip); - CSDL_Ext::setClipRect(to, pos); - CSDL_Ext::drawDashedBorder(to, radar, Colors::PURPLE); - CSDL_Ext::setClipRect(to, oldClip); - } -} - -void CMinimap::update() -{ - if(aiShield->recActions & UPDATE) //AI turn is going on. There is no need to update minimap - return; - - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - minimap = std::make_shared(this, level); - redraw(); -} - -void CMinimap::setLevel(int newLevel) -{ - level = newLevel; - update(); -} - -void CMinimap::setAIRadar(bool on) -{ - if(on) - { - aiShield->enable(); - minimap.reset(); - } - else - { - aiShield->disable(); - update(); - } - // this my happen during AI turn when this interface is inactive - // force redraw in order to properly update interface - GH.totalRedraw(); -} - -void CMinimap::hideTile(const int3 &pos) -{ - if(minimap) - minimap->refreshTile(pos); -} - -void CMinimap::showTile(const int3 &pos) -{ - if(minimap) - minimap->refreshTile(pos); -} - -CInfoBar::CVisibleInfo::CVisibleInfo() - : CIntObject(0, Point(8, 12)) -{ -} - -void CInfoBar::CVisibleInfo::show(SDL_Surface * to) -{ - CIntObject::show(to); - for(auto object : forceRefresh) - object->showAll(to); -} - -CInfoBar::EmptyVisibleInfo::EmptyVisibleInfo() -{ -} - -CInfoBar::VisibleHeroInfo::VisibleHeroInfo(const CGHeroInstance * hero) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared("ADSTATHR"); - heroTooltip = std::make_shared(Point(0,0), hero); -} - -CInfoBar::VisibleTownInfo::VisibleTownInfo(const CGTownInstance * town) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared("ADSTATCS"); - townTooltip = std::make_shared(Point(0,0), town); -} - -CInfoBar::VisibleDateInfo::VisibleDateInfo() -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - - animation = std::make_shared(1, 0, getNewDayName(), CShowableAnim::PLAY_ONCE, 180);// H3 uses around 175-180 ms per frame - - std::string labelText; - if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) == 1 && LOCPLINT->cb->getDate(Date::DAY) != 1) // monday of any week but first - show new week info - labelText = CGI->generaltexth->allTexts[63] + " " + boost::lexical_cast(LOCPLINT->cb->getDate(Date::WEEK)); - else - labelText = CGI->generaltexth->allTexts[64] + " " + boost::lexical_cast(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK)); - - label = std::make_shared(95, 31, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, labelText); - - forceRefresh.push_back(label); -} - -std::string CInfoBar::VisibleDateInfo::getNewDayName() -{ - if(LOCPLINT->cb->getDate(Date::DAY) == 1) - return "NEWDAY"; - - if(LOCPLINT->cb->getDate(Date::DAY) != 1) - return "NEWDAY"; - - switch(LOCPLINT->cb->getDate(Date::WEEK)) - { - case 1: - return "NEWWEEK1"; - case 2: - return "NEWWEEK2"; - case 3: - return "NEWWEEK3"; - case 4: - return "NEWWEEK4"; - default: - return ""; - } -} - -CInfoBar::VisibleEnemyTurnInfo::VisibleEnemyTurnInfo(PlayerColor player) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared("ADSTATNX"); - banner = std::make_shared("CREST58", player.getNum(), 0, 20, 51); - sand = std::make_shared(99, 51, "HOURSAND", 0, 100); // H3 uses around 100 ms per frame - glass = std::make_shared(99, 51, "HOURGLAS", CShowableAnim::PLAY_ONCE, 1000); // H3 scales this nicely for AI turn duration, don't have anything like that in vcmi -} - -CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo() -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - //get amount of halls of each level - std::vector halls(4, 0); - for(auto town : LOCPLINT->towns) - { - int hallLevel = town->hallLevel(); - //negative value means no village hall, unlikely but possible - if(hallLevel >= 0) - halls.at(hallLevel)++; - } - - std::vector allies, enemies; - - //generate list of allies and enemies - for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++) - { - if(LOCPLINT->cb->getPlayerStatus(PlayerColor(i), false) == EPlayerStatus::INGAME) - { - if(LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, PlayerColor(i)) != PlayerRelations::ENEMIES) - allies.push_back(PlayerColor(i)); - else - enemies.push_back(PlayerColor(i)); - } - } - - //generate widgets - background = std::make_shared("ADSTATIN"); - allyLabel = std::make_shared(10, 106, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[390] + ":"); - enemyLabel = std::make_shared(10, 136, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[391] + ":"); - - int posx = allyLabel->pos.w + allyLabel->pos.x - pos.x + 4; - for(PlayerColor & player : allies) - { - auto image = std::make_shared("ITGFLAGS", player.getNum(), 0, posx, 102); - posx += image->pos.w; - flags.push_back(image); - } - - posx = enemyLabel->pos.w + enemyLabel->pos.x - pos.x + 4; - for(PlayerColor & player : enemies) - { - auto image = std::make_shared("ITGFLAGS", player.getNum(), 0, posx, 132); - posx += image->pos.w; - flags.push_back(image); - } - - for(size_t i=0; i("itmtl", i, 0, 6 + 42 * (int)i , 11)); - if(halls[i]) - hallLabels.push_back(std::make_shared( 26 + 42 * (int)i, 64, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, boost::lexical_cast(halls[i]))); - } -} - -CInfoBar::VisibleComponentInfo::VisibleComponentInfo(const Component & compToDisplay, std::string message) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - - background = std::make_shared("ADSTATOT", 1, 0); - - comp = std::make_shared(compToDisplay); - comp->moveTo(Point(pos.x+47, pos.y+50)); - - text = std::make_shared(message, Rect(10, 4, 160, 50), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); -} - -void CInfoBar::playNewDaySound() -{ - if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) != 1) // not first day of the week - CCS->soundh->playSound(soundBase::newDay); - else if(LOCPLINT->cb->getDate(Date::WEEK) != 1) // not first week in month - CCS->soundh->playSound(soundBase::newWeek); - else if(LOCPLINT->cb->getDate(Date::MONTH) != 1) // not first month - CCS->soundh->playSound(soundBase::newMonth); - else - CCS->soundh->playSound(soundBase::newDay); -} - -void CInfoBar::reset() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = EMPTY; - visibleInfo = std::make_shared(); -} - -void CInfoBar::showSelection() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - if(adventureInt->selection) - { - if(auto hero = dynamic_cast(adventureInt->selection)) - { - showHeroSelection(hero); - return; - } - else if(auto town = dynamic_cast(adventureInt->selection)) - { - showTownSelection(town); - return; - } - } - showGameStatus();//FIXME: may be incorrect but shouldn't happen in general -} - -void CInfoBar::tick() -{ - removeUsedEvents(TIME); - if(GH.topInt() == adventureInt) - showSelection(); -} - -void CInfoBar::clickLeft(tribool down, bool previousState) -{ - if(down) - { - if(state == HERO || state == TOWN) - showGameStatus(); - else if(state == GAME) - showDate(); - else - showSelection(); - } -} - -void CInfoBar::clickRight(tribool down, bool previousState) -{ - adventureInt->handleRightClick(CGI->generaltexth->allTexts[109], down); -} - -void CInfoBar::hover(bool on) -{ - if(on) - GH.statusbar->write(CGI->generaltexth->zelp[292].first); - else - GH.statusbar->clear(); -} - -CInfoBar::CInfoBar(const Rect & position) - : CIntObject(LCLICK | RCLICK | HOVER, position.topLeft()), - state(EMPTY) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - pos.w = position.w; - pos.h = position.h; - reset(); -} - -void CInfoBar::showDate() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - playNewDaySound(); - state = DATE; - visibleInfo = std::make_shared(); - setTimer(3000); // confirmed to match H3 - redraw(); -} - -void CInfoBar::showComponent(const Component & comp, std::string message) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = COMPONENT; - visibleInfo = std::make_shared(comp, message); - setTimer(3000); - redraw(); -} - -void CInfoBar::startEnemyTurn(PlayerColor color) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = AITURN; - visibleInfo = std::make_shared(color); - redraw(); -} - -void CInfoBar::showHeroSelection(const CGHeroInstance * hero) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - if(!hero) - { - reset(); - } - else - { - state = HERO; - visibleInfo = std::make_shared(hero); - } - redraw(); -} - -void CInfoBar::showTownSelection(const CGTownInstance * town) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - if(!town) - { - reset(); - } - else - { - state = TOWN; - visibleInfo = std::make_shared(town); - } - redraw(); -} - -void CInfoBar::showGameStatus() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = GAME; - visibleInfo = std::make_shared(); - setTimer(3000); - redraw(); -} - -CInGameConsole::CInGameConsole() - : CIntObject(KEYBOARD | TEXTINPUT), - prevEntDisp(-1), - defaultTimeout(10000), - maxDisplayedTexts(10) -{ -} - -void CInGameConsole::show(SDL_Surface * to) -{ - int number = 0; - - std::vector >::iterator> toDel; - - boost::unique_lock lock(texts_mx); - for(auto it = texts.begin(); it != texts.end(); ++it, ++number) - { - Point leftBottomCorner(0, pos.h); - - graphics->fonts[FONT_MEDIUM]->renderTextLeft(to, it->first, Colors::GREEN, - Point(leftBottomCorner.x + 50, leftBottomCorner.y - (int)texts.size() * 20 - 80 + number*20)); - - if((int)(SDL_GetTicks() - it->second) > defaultTimeout) - { - toDel.push_back(it); - } - } - - for(auto & elem : toDel) - { - texts.erase(elem); - } -} - -void CInGameConsole::print(const std::string &txt) -{ - boost::unique_lock lock(texts_mx); - int lineLen = conf.go()->ac.outputLineLength; - - if(txt.size() < lineLen) - { - texts.push_back(std::make_pair(txt, SDL_GetTicks())); - if(texts.size() > maxDisplayedTexts) - { - texts.pop_front(); - } - } - else - { - assert(lineLen); - for(int g=0; g maxDisplayedTexts) - { - texts.pop_front(); - } - } - } -} - -void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key) -{ - if(key.type != SDL_KEYDOWN) return; - - if(!captureAllKeys && key.keysym.sym != SDLK_TAB) return; //because user is not entering any text - - switch(key.keysym.sym) - { - case SDLK_TAB: - case SDLK_ESCAPE: - { - if(captureAllKeys) - { - endEnteringText(false); - } - else if(SDLK_TAB == key.keysym.sym) - { - startEnteringText(); - } - break; - } - case SDLK_RETURN: //enter key - { - if(!enteredText.empty() && captureAllKeys) - { - bool anyTextExceptCaret = enteredText.size() > 1; - endEnteringText(anyTextExceptCaret); - - if(anyTextExceptCaret) - { - CCS->soundh->playSound("CHAT"); - } - } - break; - } - case SDLK_BACKSPACE: - { - if(enteredText.size() > 1) - { - Unicode::trimRight(enteredText,2); - enteredText += '_'; - refreshEnteredText(); - } - break; - } - case SDLK_UP: //up arrow - { - if(previouslyEntered.size() == 0) - break; - - if(prevEntDisp == -1) - { - prevEntDisp = static_cast(previouslyEntered.size() - 1); - enteredText = previouslyEntered[prevEntDisp] + "_"; - refreshEnteredText(); - } - else if( prevEntDisp > 0) - { - --prevEntDisp; - enteredText = previouslyEntered[prevEntDisp] + "_"; - refreshEnteredText(); - } - break; - } - case SDLK_DOWN: //down arrow - { - if(prevEntDisp != -1 && prevEntDisp+1 < previouslyEntered.size()) - { - ++prevEntDisp; - enteredText = previouslyEntered[prevEntDisp] + "_"; - refreshEnteredText(); - } - else if(prevEntDisp+1 == previouslyEntered.size()) //useful feature - { - prevEntDisp = -1; - enteredText = "_"; - refreshEnteredText(); - } - break; - } - default: - { - break; - } - } -} - -void CInGameConsole::textInputed(const SDL_TextInputEvent & event) -{ - if(!captureAllKeys || enteredText.size() == 0) - return; - enteredText.resize(enteredText.size()-1); - - enteredText += event.text; - enteredText += "_"; - - refreshEnteredText(); -} - -void CInGameConsole::textEdited(const SDL_TextEditingEvent & event) -{ - //do nothing here -} - -void CInGameConsole::startEnteringText() -{ - if (!active) - return; - - if (captureAllKeys) - return; - - assert(GH.statusbar); - assert(currentStatusBar.expired());//effectively, nullptr check - - currentStatusBar = GH.statusbar; - - captureAllKeys = true; - enteredText = "_"; - - GH.statusbar->setEnteringMode(true); - GH.statusbar->setEnteredText(enteredText); -} - -void CInGameConsole::endEnteringText(bool processEnteredText) -{ - captureAllKeys = false; - prevEntDisp = -1; - if(processEnteredText) - { - std::string txt = enteredText.substr(0, enteredText.size()-1); - previouslyEntered.push_back(txt); - - if(txt.at(0) == '/') - { - //some commands like gosolo don't work when executed from GUI thread - auto threadFunction = [=]() - { - ClientCommandManager commandController; - commandController.processCommand(txt.substr(1), true); - }; - - boost::thread clientCommandThread(threadFunction); - clientCommandThread.detach(); - } - else - LOCPLINT->cb->sendMessage(txt, LOCPLINT->getSelection()); - } - enteredText.clear(); - - auto statusbar = currentStatusBar.lock(); - assert(statusbar); - - if (statusbar) - statusbar->setEnteringMode(false); - - currentStatusBar.reset(); -} - -void CInGameConsole::refreshEnteredText() -{ - auto statusbar = currentStatusBar.lock(); - assert(statusbar); - - if (statusbar) - statusbar->setEnteredText(enteredText); -} - CAdvMapPanel::CAdvMapPanel(std::shared_ptr bg, Point position) : CIntObject() , background(bg) @@ -1249,3 +123,4 @@ void CAdvMapWorldViewPanel::addChildIcon(std::pair data, int indexOf iconsData.push_back(data); currentIcons.push_back(std::make_shared(icons, data.first + indexOffset, 0, data.second.x, data.second.y)); } + diff --git a/client/adventureMap/CAdvMapPanel.h b/client/adventureMap/CAdvMapPanel.h index 3b4874d9e..b5a1d663d 100644 --- a/client/adventureMap/CAdvMapPanel.h +++ b/client/adventureMap/CAdvMapPanel.h @@ -37,334 +37,6 @@ class CTownTooltip; class CTextBox; class IImage; -/// Base UI Element for hero\town lists -class CList : public CIntObject -{ -protected: - class CListItem : public CIntObject, public std::enable_shared_from_this - { - CList * parent; - std::shared_ptr selection; - public: - CListItem(CList * parent); - ~CListItem(); - - void clickRight(tribool down, bool previousState) override; - void clickLeft(tribool down, bool previousState) override; - void hover(bool on) override; - void onSelect(bool on); - - /// create object with selection rectangle - virtual std::shared_ptr genSelection()=0; - /// reaction on item selection (e.g. enable selection border) - /// NOTE: item may be deleted in selected state - virtual void select(bool on)=0; - /// open item (town or hero screen) - virtual void open()=0; - /// show right-click tooltip - virtual void showTooltip()=0; - /// get hover text for status bar - virtual std::string getHoverText()=0; - }; - - std::shared_ptr listBox; - const size_t size; - - /** - * @brief CList - protected constructor - * @param size - maximal amount of visible at once items - * @param position - cordinates - * @param btnUp - path to image to use as top button - * @param btnDown - path to image to use as bottom button - * @param listAmount - amount of items in the list - * @param helpUp - index in zelp.txt for button help tooltip - * @param helpDown - index in zelp.txt for button help tooltip - * @param create - function for creating items in listbox - * @param destroy - function for deleting items in listbox - */ - CList(int size, Point position, std::string btnUp, std::string btnDown, size_t listAmount, int helpUp, int helpDown, CListBox::CreateFunc create); - - //for selection\deselection - std::shared_ptr selected; - void select(std::shared_ptr which); - friend class CListItem; - - std::shared_ptr scrollUp; - std::shared_ptr scrollDown; - - /// should be called when list is invalidated - void update(); - -public: - /// functions that will be called when selection changes - CFunctionList onSelect; - - /// return index of currently selected element - int getSelectedIndex(); - - /// set of methods to switch selection - void selectIndex(int which); - void selectNext(); - void selectPrev(); -}; - -/// List of heroes which is shown at the right of the adventure map screen -class CHeroList : public CList -{ - /// Empty hero item used as placeholder for unused entries in list - class CEmptyHeroItem : public CIntObject - { - std::shared_ptr movement; - std::shared_ptr mana; - std::shared_ptr portrait; - public: - CEmptyHeroItem(); - }; - - class CHeroItem : public CListItem - { - std::shared_ptr movement; - std::shared_ptr mana; - std::shared_ptr portrait; - public: - const CGHeroInstance * const hero; - - CHeroItem(CHeroList * parent, const CGHeroInstance * hero); - - std::shared_ptr genSelection() override; - void update(); - void select(bool on) override; - void open() override; - void showTooltip() override; - std::string getHoverText() override; - }; - - std::shared_ptr createHeroItem(size_t index); -public: - /** - * @brief CHeroList - * @param size, position, btnUp, btnDown @see CList::CList - */ - CHeroList(int size, Point position, std::string btnUp, std::string btnDown); - - /// Select specific hero and scroll if needed - void select(const CGHeroInstance * hero = nullptr); - - /// Update hero. Will add or remove it from the list if needed - void update(const CGHeroInstance * hero = nullptr); -}; - -/// List of towns which is shown at the right of the adventure map screen or in the town screen -class CTownList : public CList -{ - class CTownItem : public CListItem - { - std::shared_ptr picture; - public: - const CGTownInstance * const town; - - CTownItem(CTownList *parent, const CGTownInstance * town); - - std::shared_ptr genSelection() override; - void update(); - void select(bool on) override; - void open() override; - void showTooltip() override; - std::string getHoverText() override; - }; - - std::shared_ptr createTownItem(size_t index); -public: - /** - * @brief CTownList - * @param size, position, btnUp, btnDown @see CList::CList - */ - CTownList(int size, Point position, std::string btnUp, std::string btnDown); - - /// Select specific town and scroll if needed - void select(const CGTownInstance * town = nullptr); - - /// Update town. Will add or remove it from the list if needed - void update(const CGTownInstance * town = nullptr); -}; - -class CMinimap; - -class CMinimapInstance : public CIntObject -{ - CMinimap * parent; - SDL_Surface * minimap; - int level; - - //get color of selected tile on minimap - const SDL_Color & getTileColor(const int3 & pos); - - void blitTileWithColor(const SDL_Color & color, const int3 & pos, SDL_Surface * to, int x, int y); - - //draw minimap already scaled. - //result is not antialiased. Will result in "missing" pixels on huge maps (>144) - void drawScaled(int level); -public: - CMinimapInstance(CMinimap * parent, int level); - ~CMinimapInstance(); - - void showAll(SDL_Surface * to) override; - void tileToPixels (const int3 & tile, int & x, int & y, int toX = 0, int toY = 0); - void refreshTile(const int3 & pos); -}; - -/// Minimap which is displayed at the right upper corner of adventure map -class CMinimap : public CIntObject -{ -protected: - std::shared_ptr aiShield; //the graphic displayed during AI turn - std::shared_ptr minimap; - int level; - - //to initialize colors - std::map > loadColors(); - - void clickLeft(tribool down, bool previousState) override; - void clickRight(tribool down, bool previousState) override; - void hover (bool on) override; - void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; - - void moveAdvMapSelection(); - -public: - // terrainID -> (normal color, blocked color) - const std::map > colors; - - CMinimap(const Rect & position); - - //should be called to invalidate whole map - different player or level - int3 translateMousePosition(); - void update(); - void setLevel(int level); - void setAIRadar(bool on); - - void showAll(SDL_Surface * to) override; - - void hideTile(const int3 &pos); //puts FoW - void showTile(const int3 &pos); //removes FoW -}; - -/// Info box which shows next week/day information, hold the current date -class CInfoBar : public CIntObject -{ - //all visible information located in one object - for ease of replacing - class CVisibleInfo : public CIntObject - { - public: - void show(SDL_Surface * to) override; - - protected: - std::shared_ptr background; - std::list> forceRefresh; - - CVisibleInfo(); - }; - - class EmptyVisibleInfo : public CVisibleInfo - { - public: - EmptyVisibleInfo(); - }; - - class VisibleHeroInfo : public CVisibleInfo - { - std::shared_ptr heroTooltip; - public: - VisibleHeroInfo(const CGHeroInstance * hero); - }; - - class VisibleTownInfo : public CVisibleInfo - { - std::shared_ptr townTooltip; - public: - VisibleTownInfo(const CGTownInstance * town); - }; - - class VisibleDateInfo : public CVisibleInfo - { - std::shared_ptr animation; - std::shared_ptr label; - - std::string getNewDayName(); - public: - VisibleDateInfo(); - }; - - class VisibleEnemyTurnInfo : public CVisibleInfo - { - std::shared_ptr banner; - std::shared_ptr glass; - std::shared_ptr sand; - public: - VisibleEnemyTurnInfo(PlayerColor player); - }; - - class VisibleGameStatusInfo : public CVisibleInfo - { - std::shared_ptr allyLabel; - std::shared_ptr enemyLabel; - - std::vector> flags; - std::vector> hallIcons; - std::vector> hallLabels; - public: - VisibleGameStatusInfo(); - }; - - class VisibleComponentInfo : public CVisibleInfo - { - std::shared_ptr comp; - std::shared_ptr text; - public: - VisibleComponentInfo(const Component & compToDisplay, std::string message); - }; - - enum EState - { - EMPTY, HERO, TOWN, DATE, GAME, AITURN, COMPONENT - }; - - std::shared_ptr visibleInfo; - EState state; - - //removes all information about current state, deactivates timer (if any) - void reset(); - - void tick() override; - - void clickLeft(tribool down, bool previousState) override; - void clickRight(tribool down, bool previousState) override; - void hover(bool on) override; - - void playNewDaySound(); -public: - CInfoBar(const Rect & pos); - - /// show new day/week animation - void showDate(); - - /// show component for 3 seconds. Used to display picked up resources - void showComponent(const Component & comp, std::string message); - - /// print enemy turn progress - void startEnemyTurn(PlayerColor color); - - /// reset to default view - selected object - void showSelection(); - - /// show hero\town information - void showHeroSelection(const CGHeroInstance * hero); - void showTownSelection(const CGTownInstance * town); - - /// for 3 seconds shows amount of town halls and players status - void showGameStatus(); -}; - /// simple panel that contains other displayable elements; used to separate groups of controls class CAdvMapPanel : public CIntObject { @@ -402,29 +74,3 @@ public: void recolorIcons(const PlayerColor & color, int indexOffset); }; -class CInGameConsole : public CIntObject -{ -private: - std::list< std::pair< std::string, uint32_t > > texts; //list - boost::mutex texts_mx; // protects texts - std::vector< std::string > previouslyEntered; //previously entered texts, for up/down arrows to work - int prevEntDisp; //displayed entry from previouslyEntered - if none it's -1 - int defaultTimeout; //timeout for new texts (in ms) - int maxDisplayedTexts; //hiw many texts can be displayed simultaneously - - std::weak_ptr currentStatusBar; -public: - std::string enteredText; - void show(SDL_Surface * to) override; - void print(const std::string &txt); - void keyPressed (const SDL_KeyboardEvent & key) override; //call-in - - void textInputed(const SDL_TextInputEvent & event) override; - void textEdited(const SDL_TextEditingEvent & event) override; - - void startEnteringText(); - void endEnteringText(bool processEnteredText); - void refreshEnteredText(); - - CInGameConsole(); -}; diff --git a/client/adventureMap/CInGameConsole.cpp b/client/adventureMap/CInGameConsole.cpp index b2d83416c..7d6b6af1a 100644 --- a/client/adventureMap/CInGameConsole.cpp +++ b/client/adventureMap/CInGameConsole.cpp @@ -47,899 +47,6 @@ #include #include -CList::CListItem::CListItem(CList * Parent) - : CIntObject(LCLICK | RCLICK | HOVER), - parent(Parent), - selection() -{ - defActions = 255-DISPOSE; -} - -CList::CListItem::~CListItem() -{ -} - -void CList::CListItem::clickRight(tribool down, bool previousState) -{ - if (down == true) - showTooltip(); -} - -void CList::CListItem::clickLeft(tribool down, bool previousState) -{ - if(down == true) - { - //second click on already selected item - if(parent->selected == this->shared_from_this()) - { - open(); - } - else - { - //first click - switch selection - parent->select(this->shared_from_this()); - } - } -} - -void CList::CListItem::hover(bool on) -{ - if (on) - GH.statusbar->write(getHoverText()); - else - GH.statusbar->clear(); -} - -void CList::CListItem::onSelect(bool on) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - selection.reset(); - if(on) - selection = genSelection(); - select(on); - GH.totalRedraw(); -} - -CList::CList(int Size, Point position, std::string btnUp, std::string btnDown, size_t listAmount, int helpUp, int helpDown, CListBox::CreateFunc create) - : CIntObject(0, position), - size(Size), - selected(nullptr) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - scrollUp = std::make_shared(Point(0, 0), btnUp, CGI->generaltexth->zelp[helpUp]); - scrollDown = std::make_shared(Point(0, scrollUp->pos.h + 32*(int)size), btnDown, CGI->generaltexth->zelp[helpDown]); - - listBox = std::make_shared(create, Point(1,scrollUp->pos.h), Point(0, 32), size, listAmount); - - //assign callback only after list was created - scrollUp->addCallback(std::bind(&CListBox::moveToPrev, listBox)); - scrollDown->addCallback(std::bind(&CListBox::moveToNext, listBox)); - - scrollUp->addCallback(std::bind(&CList::update, this)); - scrollDown->addCallback(std::bind(&CList::update, this)); - - update(); -} - -void CList::update() -{ - bool onTop = listBox->getPos() == 0; - bool onBottom = listBox->getPos() + size >= listBox->size(); - - scrollUp->block(onTop); - scrollDown->block(onBottom); -} - -void CList::select(std::shared_ptr which) -{ - if(selected == which) - return; - - if(selected) - selected->onSelect(false); - - selected = which; - if(which) - { - which->onSelect(true); - onSelect(); - } -} - -int CList::getSelectedIndex() -{ - return static_cast(listBox->getIndexOf(selected)); -} - -void CList::selectIndex(int which) -{ - if(which < 0) - { - if(selected) - select(nullptr); - } - else - { - listBox->scrollTo(which); - update(); - select(std::dynamic_pointer_cast(listBox->getItem(which))); - } -} - -void CList::selectNext() -{ - int index = getSelectedIndex() + 1; - if(index >= listBox->size()) - index = 0; - selectIndex(index); -} - -void CList::selectPrev() -{ - int index = getSelectedIndex(); - if(index <= 0) - selectIndex(0); - else - selectIndex(index-1); -} - -CHeroList::CEmptyHeroItem::CEmptyHeroItem() -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - movement = std::make_shared("IMOBIL", 0, 0, 0, 1); - portrait = std::make_shared("HPSXXX", movement->pos.w + 1, 0); - mana = std::make_shared("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1 ); - - pos.w = mana->pos.w + mana->pos.x - pos.x; - pos.h = std::max(std::max(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h); -} - -CHeroList::CHeroItem::CHeroItem(CHeroList *parent, const CGHeroInstance * Hero) - : CListItem(parent), - hero(Hero) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - movement = std::make_shared("IMOBIL", 0, 0, 0, 1); - portrait = std::make_shared("PortraitsSmall", hero->portrait, 0, movement->pos.w + 1); - mana = std::make_shared("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1); - - pos.w = mana->pos.w + mana->pos.x - pos.x; - pos.h = std::max(std::max(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h); - - update(); -} - -void CHeroList::CHeroItem::update() -{ - movement->setFrame(std::min(movement->size()-1, hero->movement / 100)); - mana->setFrame(std::min(mana->size()-1, hero->mana / 5)); - redraw(); -} - -std::shared_ptr CHeroList::CHeroItem::genSelection() -{ - return std::make_shared("HPSYYY", movement->pos.w + 1, 0); -} - -void CHeroList::CHeroItem::select(bool on) -{ - if(on && adventureInt->selection != hero) - adventureInt->select(hero); -} - -void CHeroList::CHeroItem::open() -{ - LOCPLINT->openHeroWindow(hero); -} - -void CHeroList::CHeroItem::showTooltip() -{ - CRClickPopup::createAndPush(hero, GH.getCursorPosition()); -} - -std::string CHeroList::CHeroItem::getHoverText() -{ - return boost::str(boost::format(CGI->generaltexth->allTexts[15]) % hero->getNameTranslated() % hero->type->heroClass->getNameTranslated()); -} - -std::shared_ptr CHeroList::createHeroItem(size_t index) -{ - if (LOCPLINT->wanderingHeroes.size() > index) - return std::make_shared(this, LOCPLINT->wanderingHeroes[index]); - return std::make_shared(); -} - -CHeroList::CHeroList(int size, Point position, std::string btnUp, std::string btnDown): - CList(size, position, btnUp, btnDown, LOCPLINT->wanderingHeroes.size(), 303, 304, std::bind(&CHeroList::createHeroItem, this, _1)) -{ -} - -void CHeroList::select(const CGHeroInstance * hero) -{ - selectIndex(vstd::find_pos(LOCPLINT->wanderingHeroes, hero)); -} - -void CHeroList::update(const CGHeroInstance * hero) -{ - //this hero is already present, update its status - for(auto & elem : listBox->getItems()) - { - auto item = std::dynamic_pointer_cast(elem); - if(item && item->hero == hero && vstd::contains(LOCPLINT->wanderingHeroes, hero)) - { - item->update(); - return; - } - } - //simplest solution for now: reset list and restore selection - - listBox->resize(LOCPLINT->wanderingHeroes.size()); - if (adventureInt->selection) - { - auto selectedHero = dynamic_cast(adventureInt->selection); - if (selectedHero) - select(selectedHero); - } - CList::update(); -} - -std::shared_ptr CTownList::createTownItem(size_t index) -{ - if (LOCPLINT->towns.size() > index) - return std::make_shared(this, LOCPLINT->towns[index]); - return std::make_shared("ITPA", 0); -} - -CTownList::CTownItem::CTownItem(CTownList *parent, const CGTownInstance *Town): - CListItem(parent), - town(Town) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - picture = std::make_shared("ITPA", 0); - pos = picture->pos; - update(); -} - -std::shared_ptr CTownList::CTownItem::genSelection() -{ - return std::make_shared("ITPA", 1); -} - -void CTownList::CTownItem::update() -{ - size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN]; - - picture->setFrame(iconIndex + 2); - redraw(); -} - -void CTownList::CTownItem::select(bool on) -{ - if (on && adventureInt->selection != town) - adventureInt->select(town); -} - -void CTownList::CTownItem::open() -{ - LOCPLINT->openTownWindow(town); -} - -void CTownList::CTownItem::showTooltip() -{ - CRClickPopup::createAndPush(town, GH.getCursorPosition()); -} - -std::string CTownList::CTownItem::getHoverText() -{ - return town->getObjectName(); -} - -CTownList::CTownList(int size, Point position, std::string btnUp, std::string btnDown): - CList(size, position, btnUp, btnDown, LOCPLINT->towns.size(), 306, 307, std::bind(&CTownList::createTownItem, this, _1)) -{ -} - -void CTownList::select(const CGTownInstance * town) -{ - selectIndex(vstd::find_pos(LOCPLINT->towns, town)); -} - -void CTownList::update(const CGTownInstance *) -{ - //simplest solution for now: reset list and restore selection - - listBox->resize(LOCPLINT->towns.size()); - if (adventureInt->selection) - { - auto town = dynamic_cast(adventureInt->selection); - if (town) - select(town); - } - CList::update(); -} - -const SDL_Color & CMinimapInstance::getTileColor(const int3 & pos) -{ - const TerrainTile * tile = LOCPLINT->cb->getTile(pos, false); - - // if tile is not visible it will be black on minimap - if(!tile) - return Colors::BLACK; - - // if object at tile is owned - it will be colored as its owner - for (const CGObjectInstance *obj : tile->blockingObjects) - { - //heroes will be blitted later - switch (obj->ID) - { - case Obj::HERO: - case Obj::PRISON: - continue; - } - - PlayerColor player = obj->getOwner(); - if(player == PlayerColor::NEUTRAL) - return *graphics->neutralColor; - else - if (player < PlayerColor::PLAYER_LIMIT) - return graphics->playerColors[player.getNum()]; - } - - // else - use terrain color (blocked version or normal) - const auto & colorPair = parent->colors.find(tile->terType->getId())->second; - if (tile->blocked && (!tile->visitable)) - return colorPair.second; - else - return colorPair.first; -} -void CMinimapInstance::tileToPixels (const int3 &tile, int &x, int &y, int toX, int toY) -{ - int3 mapSizes = LOCPLINT->cb->getMapSize(); - - double stepX = double(pos.w) / mapSizes.x; - double stepY = double(pos.h) / mapSizes.y; - - x = static_cast(toX + stepX * tile.x); - y = static_cast(toY + stepY * tile.y); -} - -void CMinimapInstance::blitTileWithColor(const SDL_Color &color, const int3 &tile, SDL_Surface *to, int toX, int toY) -{ - //coordinates of rectangle on minimap representing this tile - // begin - first to blit, end - first NOT to blit - int xBegin, yBegin, xEnd, yEnd; - tileToPixels (tile, xBegin, yBegin, toX, toY); - tileToPixels (int3 (tile.x + 1, tile.y + 1, tile.z), xEnd, yEnd, toX, toY); - - for (int y=yBegin; ypixels + y * to->pitch + xBegin * minimap->format->BytesPerPixel; - - for (int x=xBegin; x::PutColor(ptr, color); - } -} - -void CMinimapInstance::refreshTile(const int3 &tile) -{ - blitTileWithColor(getTileColor(int3(tile.x, tile.y, level)), tile, minimap, 0, 0); -} - -void CMinimapInstance::drawScaled(int level) -{ - int3 mapSizes = LOCPLINT->cb->getMapSize(); - - //size of one map tile on our minimap - double stepX = double(pos.w) / mapSizes.x; - double stepY = double(pos.h) / mapSizes.y; - - double currY = 0; - for (int y=0; y(currX); - int yBegin = static_cast(currY); - int xEnd = static_cast(currX + stepX); - int yEnd = static_cast(currY + stepY); - - for (int y=yBegin; ypixels + y * minimap->pitch + xBegin * minimap->format->BytesPerPixel; - - for (int x=xBegin; x::PutColor(ptr, color); - } - } - } -} - -CMinimapInstance::CMinimapInstance(CMinimap *Parent, int Level): - parent(Parent), - minimap(CSDL_Ext::createSurfaceWithBpp<4>(parent->pos.w, parent->pos.h)), - level(Level) -{ - pos.w = parent->pos.w; - pos.h = parent->pos.h; - drawScaled(level); -} - -CMinimapInstance::~CMinimapInstance() -{ - SDL_FreeSurface(minimap); -} - -void CMinimapInstance::showAll(SDL_Surface * to) -{ - blitAtLoc(minimap, 0, 0, to); - - //draw heroes - std::vector heroes = LOCPLINT->cb->getHeroesInfo(false); //TODO: do we really need separate function for drawing heroes? - for(auto & hero : heroes) - { - int3 position = hero->visitablePos(); - if(position.z == level) - { - const SDL_Color & color = graphics->playerColors[hero->getOwner().getNum()]; - blitTileWithColor(color, position, to, pos.x, pos.y); - } - } -} - -std::map > CMinimap::loadColors() -{ - std::map > ret; - - for(const auto & terrain : CGI->terrainTypeHandler->objects) - { - SDL_Color normal = CSDL_Ext::toSDL(terrain->minimapUnblocked); - SDL_Color blocked = CSDL_Ext::toSDL(terrain->minimapBlocked); - - ret[terrain->getId()] = std::make_pair(normal, blocked); - } - return ret; -} - -CMinimap::CMinimap(const Rect & position) - : CIntObject(LCLICK | RCLICK | HOVER | MOVE, position.topLeft()), - level(0), - colors(loadColors()) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - pos.w = position.w; - pos.h = position.h; - - aiShield = std::make_shared("AIShield"); - aiShield->disable(); -} - -int3 CMinimap::translateMousePosition() -{ - // 0 = top-left corner, 1 = bottom-right corner - double dx = double(GH.getCursorPosition().x - pos.x) / pos.w; - double dy = double(GH.getCursorPosition().y - pos.y) / pos.h; - - int3 mapSizes = LOCPLINT->cb->getMapSize(); - - int3 tile ((si32)(mapSizes.x * dx), (si32)(mapSizes.y * dy), level); - return tile; -} - -void CMinimap::moveAdvMapSelection() -{ - int3 newLocation = translateMousePosition(); - adventureInt->centerOn(newLocation); - - if (!(adventureInt->active & GENERAL)) - GH.totalRedraw(); //redraw this as well as inactive adventure map - else - redraw();//redraw only this -} - -void CMinimap::clickLeft(tribool down, bool previousState) -{ - if(down) - moveAdvMapSelection(); -} - -void CMinimap::clickRight(tribool down, bool previousState) -{ - adventureInt->handleRightClick(CGI->generaltexth->zelp[291].second, down); -} - -void CMinimap::hover(bool on) -{ - if(on) - GH.statusbar->write(CGI->generaltexth->zelp[291].first); - else - GH.statusbar->clear(); -} - -void CMinimap::mouseMoved(const SDL_MouseMotionEvent & sEvent) -{ - if(mouseState(EIntObjMouseBtnType::LEFT)) - moveAdvMapSelection(); -} - -void CMinimap::showAll(SDL_Surface * to) -{ - CIntObject::showAll(to); - if(minimap) - { - int3 mapSizes = LOCPLINT->cb->getMapSize(); - int3 tileCountOnScreen = adventureInt->terrain.tileCountOnScreen(); - - //draw radar - Rect oldClip; - Rect radar = - { - si16(adventureInt->position.x * pos.w / mapSizes.x + pos.x), - si16(adventureInt->position.y * pos.h / mapSizes.y + pos.y), - ui16(tileCountOnScreen.x * pos.w / mapSizes.x), - ui16(tileCountOnScreen.y * pos.h / mapSizes.y) - }; - - if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) - { - // adjusts radar so that it doesn't go out of map in world view mode (since there's no frame) - radar.x = std::min(std::max(pos.x, radar.x), pos.x + pos.w - radar.w); - radar.y = std::min(std::max(pos.y, radar.y), pos.y + pos.h - radar.h); - - if(radar.x < pos.x && radar.y < pos.y) - return; // whole map is visible at once, no point in redrawing border - } - - CSDL_Ext::getClipRect(to, oldClip); - CSDL_Ext::setClipRect(to, pos); - CSDL_Ext::drawDashedBorder(to, radar, Colors::PURPLE); - CSDL_Ext::setClipRect(to, oldClip); - } -} - -void CMinimap::update() -{ - if(aiShield->recActions & UPDATE) //AI turn is going on. There is no need to update minimap - return; - - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - minimap = std::make_shared(this, level); - redraw(); -} - -void CMinimap::setLevel(int newLevel) -{ - level = newLevel; - update(); -} - -void CMinimap::setAIRadar(bool on) -{ - if(on) - { - aiShield->enable(); - minimap.reset(); - } - else - { - aiShield->disable(); - update(); - } - // this my happen during AI turn when this interface is inactive - // force redraw in order to properly update interface - GH.totalRedraw(); -} - -void CMinimap::hideTile(const int3 &pos) -{ - if(minimap) - minimap->refreshTile(pos); -} - -void CMinimap::showTile(const int3 &pos) -{ - if(minimap) - minimap->refreshTile(pos); -} - -CInfoBar::CVisibleInfo::CVisibleInfo() - : CIntObject(0, Point(8, 12)) -{ -} - -void CInfoBar::CVisibleInfo::show(SDL_Surface * to) -{ - CIntObject::show(to); - for(auto object : forceRefresh) - object->showAll(to); -} - -CInfoBar::EmptyVisibleInfo::EmptyVisibleInfo() -{ -} - -CInfoBar::VisibleHeroInfo::VisibleHeroInfo(const CGHeroInstance * hero) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared("ADSTATHR"); - heroTooltip = std::make_shared(Point(0,0), hero); -} - -CInfoBar::VisibleTownInfo::VisibleTownInfo(const CGTownInstance * town) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared("ADSTATCS"); - townTooltip = std::make_shared(Point(0,0), town); -} - -CInfoBar::VisibleDateInfo::VisibleDateInfo() -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - - animation = std::make_shared(1, 0, getNewDayName(), CShowableAnim::PLAY_ONCE, 180);// H3 uses around 175-180 ms per frame - - std::string labelText; - if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) == 1 && LOCPLINT->cb->getDate(Date::DAY) != 1) // monday of any week but first - show new week info - labelText = CGI->generaltexth->allTexts[63] + " " + boost::lexical_cast(LOCPLINT->cb->getDate(Date::WEEK)); - else - labelText = CGI->generaltexth->allTexts[64] + " " + boost::lexical_cast(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK)); - - label = std::make_shared(95, 31, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, labelText); - - forceRefresh.push_back(label); -} - -std::string CInfoBar::VisibleDateInfo::getNewDayName() -{ - if(LOCPLINT->cb->getDate(Date::DAY) == 1) - return "NEWDAY"; - - if(LOCPLINT->cb->getDate(Date::DAY) != 1) - return "NEWDAY"; - - switch(LOCPLINT->cb->getDate(Date::WEEK)) - { - case 1: - return "NEWWEEK1"; - case 2: - return "NEWWEEK2"; - case 3: - return "NEWWEEK3"; - case 4: - return "NEWWEEK4"; - default: - return ""; - } -} - -CInfoBar::VisibleEnemyTurnInfo::VisibleEnemyTurnInfo(PlayerColor player) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared("ADSTATNX"); - banner = std::make_shared("CREST58", player.getNum(), 0, 20, 51); - sand = std::make_shared(99, 51, "HOURSAND", 0, 100); // H3 uses around 100 ms per frame - glass = std::make_shared(99, 51, "HOURGLAS", CShowableAnim::PLAY_ONCE, 1000); // H3 scales this nicely for AI turn duration, don't have anything like that in vcmi -} - -CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo() -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - //get amount of halls of each level - std::vector halls(4, 0); - for(auto town : LOCPLINT->towns) - { - int hallLevel = town->hallLevel(); - //negative value means no village hall, unlikely but possible - if(hallLevel >= 0) - halls.at(hallLevel)++; - } - - std::vector allies, enemies; - - //generate list of allies and enemies - for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++) - { - if(LOCPLINT->cb->getPlayerStatus(PlayerColor(i), false) == EPlayerStatus::INGAME) - { - if(LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, PlayerColor(i)) != PlayerRelations::ENEMIES) - allies.push_back(PlayerColor(i)); - else - enemies.push_back(PlayerColor(i)); - } - } - - //generate widgets - background = std::make_shared("ADSTATIN"); - allyLabel = std::make_shared(10, 106, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[390] + ":"); - enemyLabel = std::make_shared(10, 136, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[391] + ":"); - - int posx = allyLabel->pos.w + allyLabel->pos.x - pos.x + 4; - for(PlayerColor & player : allies) - { - auto image = std::make_shared("ITGFLAGS", player.getNum(), 0, posx, 102); - posx += image->pos.w; - flags.push_back(image); - } - - posx = enemyLabel->pos.w + enemyLabel->pos.x - pos.x + 4; - for(PlayerColor & player : enemies) - { - auto image = std::make_shared("ITGFLAGS", player.getNum(), 0, posx, 132); - posx += image->pos.w; - flags.push_back(image); - } - - for(size_t i=0; i("itmtl", i, 0, 6 + 42 * (int)i , 11)); - if(halls[i]) - hallLabels.push_back(std::make_shared( 26 + 42 * (int)i, 64, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, boost::lexical_cast(halls[i]))); - } -} - -CInfoBar::VisibleComponentInfo::VisibleComponentInfo(const Component & compToDisplay, std::string message) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - - background = std::make_shared("ADSTATOT", 1, 0); - - comp = std::make_shared(compToDisplay); - comp->moveTo(Point(pos.x+47, pos.y+50)); - - text = std::make_shared(message, Rect(10, 4, 160, 50), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); -} - -void CInfoBar::playNewDaySound() -{ - if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) != 1) // not first day of the week - CCS->soundh->playSound(soundBase::newDay); - else if(LOCPLINT->cb->getDate(Date::WEEK) != 1) // not first week in month - CCS->soundh->playSound(soundBase::newWeek); - else if(LOCPLINT->cb->getDate(Date::MONTH) != 1) // not first month - CCS->soundh->playSound(soundBase::newMonth); - else - CCS->soundh->playSound(soundBase::newDay); -} - -void CInfoBar::reset() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = EMPTY; - visibleInfo = std::make_shared(); -} - -void CInfoBar::showSelection() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - if(adventureInt->selection) - { - if(auto hero = dynamic_cast(adventureInt->selection)) - { - showHeroSelection(hero); - return; - } - else if(auto town = dynamic_cast(adventureInt->selection)) - { - showTownSelection(town); - return; - } - } - showGameStatus();//FIXME: may be incorrect but shouldn't happen in general -} - -void CInfoBar::tick() -{ - removeUsedEvents(TIME); - if(GH.topInt() == adventureInt) - showSelection(); -} - -void CInfoBar::clickLeft(tribool down, bool previousState) -{ - if(down) - { - if(state == HERO || state == TOWN) - showGameStatus(); - else if(state == GAME) - showDate(); - else - showSelection(); - } -} - -void CInfoBar::clickRight(tribool down, bool previousState) -{ - adventureInt->handleRightClick(CGI->generaltexth->allTexts[109], down); -} - -void CInfoBar::hover(bool on) -{ - if(on) - GH.statusbar->write(CGI->generaltexth->zelp[292].first); - else - GH.statusbar->clear(); -} - -CInfoBar::CInfoBar(const Rect & position) - : CIntObject(LCLICK | RCLICK | HOVER, position.topLeft()), - state(EMPTY) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - pos.w = position.w; - pos.h = position.h; - reset(); -} - -void CInfoBar::showDate() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - playNewDaySound(); - state = DATE; - visibleInfo = std::make_shared(); - setTimer(3000); // confirmed to match H3 - redraw(); -} - -void CInfoBar::showComponent(const Component & comp, std::string message) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = COMPONENT; - visibleInfo = std::make_shared(comp, message); - setTimer(3000); - redraw(); -} - -void CInfoBar::startEnemyTurn(PlayerColor color) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = AITURN; - visibleInfo = std::make_shared(color); - redraw(); -} - -void CInfoBar::showHeroSelection(const CGHeroInstance * hero) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - if(!hero) - { - reset(); - } - else - { - state = HERO; - visibleInfo = std::make_shared(hero); - } - redraw(); -} - -void CInfoBar::showTownSelection(const CGTownInstance * town) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - if(!town) - { - reset(); - } - else - { - state = TOWN; - visibleInfo = std::make_shared(town); - } - redraw(); -} - -void CInfoBar::showGameStatus() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = GAME; - visibleInfo = std::make_shared(); - setTimer(3000); - redraw(); -} - CInGameConsole::CInGameConsole() : CIntObject(KEYBOARD | TEXTINPUT), prevEntDisp(-1), @@ -1173,79 +280,3 @@ void CInGameConsole::refreshEnteredText() statusbar->setEnteredText(enteredText); } -CAdvMapPanel::CAdvMapPanel(std::shared_ptr bg, Point position) - : CIntObject() - , background(bg) -{ - defActions = 255; - recActions = 255; - pos.x += position.x; - pos.y += position.y; - if (bg) - { - pos.w = bg->width(); - pos.h = bg->height(); - } -} - -void CAdvMapPanel::addChildColorableButton(std::shared_ptr button) -{ - colorableButtons.push_back(button); - addChildToPanel(button, ACTIVATE | DEACTIVATE); -} - -void CAdvMapPanel::setPlayerColor(const PlayerColor & clr) -{ - for(auto & button : colorableButtons) - { - button->setPlayerColor(clr); - } -} - -void CAdvMapPanel::showAll(SDL_Surface * to) -{ - if(background) - background->draw(to, pos.x, pos.y); - - CIntObject::showAll(to); -} - -void CAdvMapPanel::addChildToPanel(std::shared_ptr obj, ui8 actions) -{ - otherObjects.push_back(obj); - obj->recActions |= actions | SHOWALL; - obj->recActions &= ~DISPOSE; - addChild(obj.get(), false); -} - -CAdvMapWorldViewPanel::CAdvMapWorldViewPanel(std::shared_ptr _icons, std::shared_ptr bg, Point position, int spaceBottom, const PlayerColor &color) - : CAdvMapPanel(bg, position), icons(_icons) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - int fillerHeight = bg ? spaceBottom - pos.y - pos.h : 0; - - if(fillerHeight > 0) - { - backgroundFiller = std::make_shared("DIBOXBCK", Rect(0, pos.h, pos.w, fillerHeight)); - } -} - -CAdvMapWorldViewPanel::~CAdvMapWorldViewPanel() = default; - -void CAdvMapWorldViewPanel::recolorIcons(const PlayerColor & color, int indexOffset) -{ - assert(iconsData.size() == currentIcons.size()); - - for(size_t idx = 0; idx < iconsData.size(); idx++) - { - const auto & data = iconsData.at(idx); - currentIcons[idx]->setFrame(data.first + indexOffset); - } -} - -void CAdvMapWorldViewPanel::addChildIcon(std::pair data, int indexOffset) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - iconsData.push_back(data); - currentIcons.push_back(std::make_shared(icons, data.first + indexOffset, 0, data.second.x, data.second.y)); -} diff --git a/client/adventureMap/CInGameConsole.h b/client/adventureMap/CInGameConsole.h index 3b4874d9e..43c625b70 100644 --- a/client/adventureMap/CInGameConsole.h +++ b/client/adventureMap/CInGameConsole.h @@ -37,371 +37,6 @@ class CTownTooltip; class CTextBox; class IImage; -/// Base UI Element for hero\town lists -class CList : public CIntObject -{ -protected: - class CListItem : public CIntObject, public std::enable_shared_from_this - { - CList * parent; - std::shared_ptr selection; - public: - CListItem(CList * parent); - ~CListItem(); - - void clickRight(tribool down, bool previousState) override; - void clickLeft(tribool down, bool previousState) override; - void hover(bool on) override; - void onSelect(bool on); - - /// create object with selection rectangle - virtual std::shared_ptr genSelection()=0; - /// reaction on item selection (e.g. enable selection border) - /// NOTE: item may be deleted in selected state - virtual void select(bool on)=0; - /// open item (town or hero screen) - virtual void open()=0; - /// show right-click tooltip - virtual void showTooltip()=0; - /// get hover text for status bar - virtual std::string getHoverText()=0; - }; - - std::shared_ptr listBox; - const size_t size; - - /** - * @brief CList - protected constructor - * @param size - maximal amount of visible at once items - * @param position - cordinates - * @param btnUp - path to image to use as top button - * @param btnDown - path to image to use as bottom button - * @param listAmount - amount of items in the list - * @param helpUp - index in zelp.txt for button help tooltip - * @param helpDown - index in zelp.txt for button help tooltip - * @param create - function for creating items in listbox - * @param destroy - function for deleting items in listbox - */ - CList(int size, Point position, std::string btnUp, std::string btnDown, size_t listAmount, int helpUp, int helpDown, CListBox::CreateFunc create); - - //for selection\deselection - std::shared_ptr selected; - void select(std::shared_ptr which); - friend class CListItem; - - std::shared_ptr scrollUp; - std::shared_ptr scrollDown; - - /// should be called when list is invalidated - void update(); - -public: - /// functions that will be called when selection changes - CFunctionList onSelect; - - /// return index of currently selected element - int getSelectedIndex(); - - /// set of methods to switch selection - void selectIndex(int which); - void selectNext(); - void selectPrev(); -}; - -/// List of heroes which is shown at the right of the adventure map screen -class CHeroList : public CList -{ - /// Empty hero item used as placeholder for unused entries in list - class CEmptyHeroItem : public CIntObject - { - std::shared_ptr movement; - std::shared_ptr mana; - std::shared_ptr portrait; - public: - CEmptyHeroItem(); - }; - - class CHeroItem : public CListItem - { - std::shared_ptr movement; - std::shared_ptr mana; - std::shared_ptr portrait; - public: - const CGHeroInstance * const hero; - - CHeroItem(CHeroList * parent, const CGHeroInstance * hero); - - std::shared_ptr genSelection() override; - void update(); - void select(bool on) override; - void open() override; - void showTooltip() override; - std::string getHoverText() override; - }; - - std::shared_ptr createHeroItem(size_t index); -public: - /** - * @brief CHeroList - * @param size, position, btnUp, btnDown @see CList::CList - */ - CHeroList(int size, Point position, std::string btnUp, std::string btnDown); - - /// Select specific hero and scroll if needed - void select(const CGHeroInstance * hero = nullptr); - - /// Update hero. Will add or remove it from the list if needed - void update(const CGHeroInstance * hero = nullptr); -}; - -/// List of towns which is shown at the right of the adventure map screen or in the town screen -class CTownList : public CList -{ - class CTownItem : public CListItem - { - std::shared_ptr picture; - public: - const CGTownInstance * const town; - - CTownItem(CTownList *parent, const CGTownInstance * town); - - std::shared_ptr genSelection() override; - void update(); - void select(bool on) override; - void open() override; - void showTooltip() override; - std::string getHoverText() override; - }; - - std::shared_ptr createTownItem(size_t index); -public: - /** - * @brief CTownList - * @param size, position, btnUp, btnDown @see CList::CList - */ - CTownList(int size, Point position, std::string btnUp, std::string btnDown); - - /// Select specific town and scroll if needed - void select(const CGTownInstance * town = nullptr); - - /// Update town. Will add or remove it from the list if needed - void update(const CGTownInstance * town = nullptr); -}; - -class CMinimap; - -class CMinimapInstance : public CIntObject -{ - CMinimap * parent; - SDL_Surface * minimap; - int level; - - //get color of selected tile on minimap - const SDL_Color & getTileColor(const int3 & pos); - - void blitTileWithColor(const SDL_Color & color, const int3 & pos, SDL_Surface * to, int x, int y); - - //draw minimap already scaled. - //result is not antialiased. Will result in "missing" pixels on huge maps (>144) - void drawScaled(int level); -public: - CMinimapInstance(CMinimap * parent, int level); - ~CMinimapInstance(); - - void showAll(SDL_Surface * to) override; - void tileToPixels (const int3 & tile, int & x, int & y, int toX = 0, int toY = 0); - void refreshTile(const int3 & pos); -}; - -/// Minimap which is displayed at the right upper corner of adventure map -class CMinimap : public CIntObject -{ -protected: - std::shared_ptr aiShield; //the graphic displayed during AI turn - std::shared_ptr minimap; - int level; - - //to initialize colors - std::map > loadColors(); - - void clickLeft(tribool down, bool previousState) override; - void clickRight(tribool down, bool previousState) override; - void hover (bool on) override; - void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; - - void moveAdvMapSelection(); - -public: - // terrainID -> (normal color, blocked color) - const std::map > colors; - - CMinimap(const Rect & position); - - //should be called to invalidate whole map - different player or level - int3 translateMousePosition(); - void update(); - void setLevel(int level); - void setAIRadar(bool on); - - void showAll(SDL_Surface * to) override; - - void hideTile(const int3 &pos); //puts FoW - void showTile(const int3 &pos); //removes FoW -}; - -/// Info box which shows next week/day information, hold the current date -class CInfoBar : public CIntObject -{ - //all visible information located in one object - for ease of replacing - class CVisibleInfo : public CIntObject - { - public: - void show(SDL_Surface * to) override; - - protected: - std::shared_ptr background; - std::list> forceRefresh; - - CVisibleInfo(); - }; - - class EmptyVisibleInfo : public CVisibleInfo - { - public: - EmptyVisibleInfo(); - }; - - class VisibleHeroInfo : public CVisibleInfo - { - std::shared_ptr heroTooltip; - public: - VisibleHeroInfo(const CGHeroInstance * hero); - }; - - class VisibleTownInfo : public CVisibleInfo - { - std::shared_ptr townTooltip; - public: - VisibleTownInfo(const CGTownInstance * town); - }; - - class VisibleDateInfo : public CVisibleInfo - { - std::shared_ptr animation; - std::shared_ptr label; - - std::string getNewDayName(); - public: - VisibleDateInfo(); - }; - - class VisibleEnemyTurnInfo : public CVisibleInfo - { - std::shared_ptr banner; - std::shared_ptr glass; - std::shared_ptr sand; - public: - VisibleEnemyTurnInfo(PlayerColor player); - }; - - class VisibleGameStatusInfo : public CVisibleInfo - { - std::shared_ptr allyLabel; - std::shared_ptr enemyLabel; - - std::vector> flags; - std::vector> hallIcons; - std::vector> hallLabels; - public: - VisibleGameStatusInfo(); - }; - - class VisibleComponentInfo : public CVisibleInfo - { - std::shared_ptr comp; - std::shared_ptr text; - public: - VisibleComponentInfo(const Component & compToDisplay, std::string message); - }; - - enum EState - { - EMPTY, HERO, TOWN, DATE, GAME, AITURN, COMPONENT - }; - - std::shared_ptr visibleInfo; - EState state; - - //removes all information about current state, deactivates timer (if any) - void reset(); - - void tick() override; - - void clickLeft(tribool down, bool previousState) override; - void clickRight(tribool down, bool previousState) override; - void hover(bool on) override; - - void playNewDaySound(); -public: - CInfoBar(const Rect & pos); - - /// show new day/week animation - void showDate(); - - /// show component for 3 seconds. Used to display picked up resources - void showComponent(const Component & comp, std::string message); - - /// print enemy turn progress - void startEnemyTurn(PlayerColor color); - - /// reset to default view - selected object - void showSelection(); - - /// show hero\town information - void showHeroSelection(const CGHeroInstance * hero); - void showTownSelection(const CGTownInstance * town); - - /// for 3 seconds shows amount of town halls and players status - void showGameStatus(); -}; - -/// simple panel that contains other displayable elements; used to separate groups of controls -class CAdvMapPanel : public CIntObject -{ - std::vector> colorableButtons; - std::vector> otherObjects; - /// the surface passed to this obj will be freed in dtor - std::shared_ptr background; -public: - CAdvMapPanel(std::shared_ptr bg, Point position); - - void addChildToPanel(std::shared_ptr obj, ui8 actions = 0); - void addChildColorableButton(std::shared_ptr button); - /// recolors all buttons to given player color - void setPlayerColor(const PlayerColor & clr); - - void showAll(SDL_Surface * to) override; -}; - -/// specialized version of CAdvMapPanel that handles recolorable def-based pictures for world view info panel -class CAdvMapWorldViewPanel : public CAdvMapPanel -{ - /// data that allows reconstruction of panel info icons - std::vector> iconsData; - /// ptrs to child-pictures constructed from iconsData - std::vector> currentIcons; - /// surface drawn below world view panel on higher resolutions (won't be needed when world view panel is configured for extraResolutions mod) - std::shared_ptr backgroundFiller; - std::shared_ptr icons; -public: - CAdvMapWorldViewPanel(std::shared_ptr _icons, std::shared_ptr bg, Point position, int spaceBottom, const PlayerColor &color); - virtual ~CAdvMapWorldViewPanel(); - - void addChildIcon(std::pair data, int indexOffset); - /// recreates all pictures from given def to recolor them according to current player color - void recolorIcons(const PlayerColor & color, int indexOffset); -}; - class CInGameConsole : public CIntObject { private: diff --git a/client/adventureMap/CInfoBar.cpp b/client/adventureMap/CInfoBar.cpp index b2d83416c..98c6a8249 100644 --- a/client/adventureMap/CInfoBar.cpp +++ b/client/adventureMap/CInfoBar.cpp @@ -47,605 +47,6 @@ #include #include -CList::CListItem::CListItem(CList * Parent) - : CIntObject(LCLICK | RCLICK | HOVER), - parent(Parent), - selection() -{ - defActions = 255-DISPOSE; -} - -CList::CListItem::~CListItem() -{ -} - -void CList::CListItem::clickRight(tribool down, bool previousState) -{ - if (down == true) - showTooltip(); -} - -void CList::CListItem::clickLeft(tribool down, bool previousState) -{ - if(down == true) - { - //second click on already selected item - if(parent->selected == this->shared_from_this()) - { - open(); - } - else - { - //first click - switch selection - parent->select(this->shared_from_this()); - } - } -} - -void CList::CListItem::hover(bool on) -{ - if (on) - GH.statusbar->write(getHoverText()); - else - GH.statusbar->clear(); -} - -void CList::CListItem::onSelect(bool on) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - selection.reset(); - if(on) - selection = genSelection(); - select(on); - GH.totalRedraw(); -} - -CList::CList(int Size, Point position, std::string btnUp, std::string btnDown, size_t listAmount, int helpUp, int helpDown, CListBox::CreateFunc create) - : CIntObject(0, position), - size(Size), - selected(nullptr) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - scrollUp = std::make_shared(Point(0, 0), btnUp, CGI->generaltexth->zelp[helpUp]); - scrollDown = std::make_shared(Point(0, scrollUp->pos.h + 32*(int)size), btnDown, CGI->generaltexth->zelp[helpDown]); - - listBox = std::make_shared(create, Point(1,scrollUp->pos.h), Point(0, 32), size, listAmount); - - //assign callback only after list was created - scrollUp->addCallback(std::bind(&CListBox::moveToPrev, listBox)); - scrollDown->addCallback(std::bind(&CListBox::moveToNext, listBox)); - - scrollUp->addCallback(std::bind(&CList::update, this)); - scrollDown->addCallback(std::bind(&CList::update, this)); - - update(); -} - -void CList::update() -{ - bool onTop = listBox->getPos() == 0; - bool onBottom = listBox->getPos() + size >= listBox->size(); - - scrollUp->block(onTop); - scrollDown->block(onBottom); -} - -void CList::select(std::shared_ptr which) -{ - if(selected == which) - return; - - if(selected) - selected->onSelect(false); - - selected = which; - if(which) - { - which->onSelect(true); - onSelect(); - } -} - -int CList::getSelectedIndex() -{ - return static_cast(listBox->getIndexOf(selected)); -} - -void CList::selectIndex(int which) -{ - if(which < 0) - { - if(selected) - select(nullptr); - } - else - { - listBox->scrollTo(which); - update(); - select(std::dynamic_pointer_cast(listBox->getItem(which))); - } -} - -void CList::selectNext() -{ - int index = getSelectedIndex() + 1; - if(index >= listBox->size()) - index = 0; - selectIndex(index); -} - -void CList::selectPrev() -{ - int index = getSelectedIndex(); - if(index <= 0) - selectIndex(0); - else - selectIndex(index-1); -} - -CHeroList::CEmptyHeroItem::CEmptyHeroItem() -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - movement = std::make_shared("IMOBIL", 0, 0, 0, 1); - portrait = std::make_shared("HPSXXX", movement->pos.w + 1, 0); - mana = std::make_shared("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1 ); - - pos.w = mana->pos.w + mana->pos.x - pos.x; - pos.h = std::max(std::max(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h); -} - -CHeroList::CHeroItem::CHeroItem(CHeroList *parent, const CGHeroInstance * Hero) - : CListItem(parent), - hero(Hero) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - movement = std::make_shared("IMOBIL", 0, 0, 0, 1); - portrait = std::make_shared("PortraitsSmall", hero->portrait, 0, movement->pos.w + 1); - mana = std::make_shared("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1); - - pos.w = mana->pos.w + mana->pos.x - pos.x; - pos.h = std::max(std::max(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h); - - update(); -} - -void CHeroList::CHeroItem::update() -{ - movement->setFrame(std::min(movement->size()-1, hero->movement / 100)); - mana->setFrame(std::min(mana->size()-1, hero->mana / 5)); - redraw(); -} - -std::shared_ptr CHeroList::CHeroItem::genSelection() -{ - return std::make_shared("HPSYYY", movement->pos.w + 1, 0); -} - -void CHeroList::CHeroItem::select(bool on) -{ - if(on && adventureInt->selection != hero) - adventureInt->select(hero); -} - -void CHeroList::CHeroItem::open() -{ - LOCPLINT->openHeroWindow(hero); -} - -void CHeroList::CHeroItem::showTooltip() -{ - CRClickPopup::createAndPush(hero, GH.getCursorPosition()); -} - -std::string CHeroList::CHeroItem::getHoverText() -{ - return boost::str(boost::format(CGI->generaltexth->allTexts[15]) % hero->getNameTranslated() % hero->type->heroClass->getNameTranslated()); -} - -std::shared_ptr CHeroList::createHeroItem(size_t index) -{ - if (LOCPLINT->wanderingHeroes.size() > index) - return std::make_shared(this, LOCPLINT->wanderingHeroes[index]); - return std::make_shared(); -} - -CHeroList::CHeroList(int size, Point position, std::string btnUp, std::string btnDown): - CList(size, position, btnUp, btnDown, LOCPLINT->wanderingHeroes.size(), 303, 304, std::bind(&CHeroList::createHeroItem, this, _1)) -{ -} - -void CHeroList::select(const CGHeroInstance * hero) -{ - selectIndex(vstd::find_pos(LOCPLINT->wanderingHeroes, hero)); -} - -void CHeroList::update(const CGHeroInstance * hero) -{ - //this hero is already present, update its status - for(auto & elem : listBox->getItems()) - { - auto item = std::dynamic_pointer_cast(elem); - if(item && item->hero == hero && vstd::contains(LOCPLINT->wanderingHeroes, hero)) - { - item->update(); - return; - } - } - //simplest solution for now: reset list and restore selection - - listBox->resize(LOCPLINT->wanderingHeroes.size()); - if (adventureInt->selection) - { - auto selectedHero = dynamic_cast(adventureInt->selection); - if (selectedHero) - select(selectedHero); - } - CList::update(); -} - -std::shared_ptr CTownList::createTownItem(size_t index) -{ - if (LOCPLINT->towns.size() > index) - return std::make_shared(this, LOCPLINT->towns[index]); - return std::make_shared("ITPA", 0); -} - -CTownList::CTownItem::CTownItem(CTownList *parent, const CGTownInstance *Town): - CListItem(parent), - town(Town) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - picture = std::make_shared("ITPA", 0); - pos = picture->pos; - update(); -} - -std::shared_ptr CTownList::CTownItem::genSelection() -{ - return std::make_shared("ITPA", 1); -} - -void CTownList::CTownItem::update() -{ - size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN]; - - picture->setFrame(iconIndex + 2); - redraw(); -} - -void CTownList::CTownItem::select(bool on) -{ - if (on && adventureInt->selection != town) - adventureInt->select(town); -} - -void CTownList::CTownItem::open() -{ - LOCPLINT->openTownWindow(town); -} - -void CTownList::CTownItem::showTooltip() -{ - CRClickPopup::createAndPush(town, GH.getCursorPosition()); -} - -std::string CTownList::CTownItem::getHoverText() -{ - return town->getObjectName(); -} - -CTownList::CTownList(int size, Point position, std::string btnUp, std::string btnDown): - CList(size, position, btnUp, btnDown, LOCPLINT->towns.size(), 306, 307, std::bind(&CTownList::createTownItem, this, _1)) -{ -} - -void CTownList::select(const CGTownInstance * town) -{ - selectIndex(vstd::find_pos(LOCPLINT->towns, town)); -} - -void CTownList::update(const CGTownInstance *) -{ - //simplest solution for now: reset list and restore selection - - listBox->resize(LOCPLINT->towns.size()); - if (adventureInt->selection) - { - auto town = dynamic_cast(adventureInt->selection); - if (town) - select(town); - } - CList::update(); -} - -const SDL_Color & CMinimapInstance::getTileColor(const int3 & pos) -{ - const TerrainTile * tile = LOCPLINT->cb->getTile(pos, false); - - // if tile is not visible it will be black on minimap - if(!tile) - return Colors::BLACK; - - // if object at tile is owned - it will be colored as its owner - for (const CGObjectInstance *obj : tile->blockingObjects) - { - //heroes will be blitted later - switch (obj->ID) - { - case Obj::HERO: - case Obj::PRISON: - continue; - } - - PlayerColor player = obj->getOwner(); - if(player == PlayerColor::NEUTRAL) - return *graphics->neutralColor; - else - if (player < PlayerColor::PLAYER_LIMIT) - return graphics->playerColors[player.getNum()]; - } - - // else - use terrain color (blocked version or normal) - const auto & colorPair = parent->colors.find(tile->terType->getId())->second; - if (tile->blocked && (!tile->visitable)) - return colorPair.second; - else - return colorPair.first; -} -void CMinimapInstance::tileToPixels (const int3 &tile, int &x, int &y, int toX, int toY) -{ - int3 mapSizes = LOCPLINT->cb->getMapSize(); - - double stepX = double(pos.w) / mapSizes.x; - double stepY = double(pos.h) / mapSizes.y; - - x = static_cast(toX + stepX * tile.x); - y = static_cast(toY + stepY * tile.y); -} - -void CMinimapInstance::blitTileWithColor(const SDL_Color &color, const int3 &tile, SDL_Surface *to, int toX, int toY) -{ - //coordinates of rectangle on minimap representing this tile - // begin - first to blit, end - first NOT to blit - int xBegin, yBegin, xEnd, yEnd; - tileToPixels (tile, xBegin, yBegin, toX, toY); - tileToPixels (int3 (tile.x + 1, tile.y + 1, tile.z), xEnd, yEnd, toX, toY); - - for (int y=yBegin; ypixels + y * to->pitch + xBegin * minimap->format->BytesPerPixel; - - for (int x=xBegin; x::PutColor(ptr, color); - } -} - -void CMinimapInstance::refreshTile(const int3 &tile) -{ - blitTileWithColor(getTileColor(int3(tile.x, tile.y, level)), tile, minimap, 0, 0); -} - -void CMinimapInstance::drawScaled(int level) -{ - int3 mapSizes = LOCPLINT->cb->getMapSize(); - - //size of one map tile on our minimap - double stepX = double(pos.w) / mapSizes.x; - double stepY = double(pos.h) / mapSizes.y; - - double currY = 0; - for (int y=0; y(currX); - int yBegin = static_cast(currY); - int xEnd = static_cast(currX + stepX); - int yEnd = static_cast(currY + stepY); - - for (int y=yBegin; ypixels + y * minimap->pitch + xBegin * minimap->format->BytesPerPixel; - - for (int x=xBegin; x::PutColor(ptr, color); - } - } - } -} - -CMinimapInstance::CMinimapInstance(CMinimap *Parent, int Level): - parent(Parent), - minimap(CSDL_Ext::createSurfaceWithBpp<4>(parent->pos.w, parent->pos.h)), - level(Level) -{ - pos.w = parent->pos.w; - pos.h = parent->pos.h; - drawScaled(level); -} - -CMinimapInstance::~CMinimapInstance() -{ - SDL_FreeSurface(minimap); -} - -void CMinimapInstance::showAll(SDL_Surface * to) -{ - blitAtLoc(minimap, 0, 0, to); - - //draw heroes - std::vector heroes = LOCPLINT->cb->getHeroesInfo(false); //TODO: do we really need separate function for drawing heroes? - for(auto & hero : heroes) - { - int3 position = hero->visitablePos(); - if(position.z == level) - { - const SDL_Color & color = graphics->playerColors[hero->getOwner().getNum()]; - blitTileWithColor(color, position, to, pos.x, pos.y); - } - } -} - -std::map > CMinimap::loadColors() -{ - std::map > ret; - - for(const auto & terrain : CGI->terrainTypeHandler->objects) - { - SDL_Color normal = CSDL_Ext::toSDL(terrain->minimapUnblocked); - SDL_Color blocked = CSDL_Ext::toSDL(terrain->minimapBlocked); - - ret[terrain->getId()] = std::make_pair(normal, blocked); - } - return ret; -} - -CMinimap::CMinimap(const Rect & position) - : CIntObject(LCLICK | RCLICK | HOVER | MOVE, position.topLeft()), - level(0), - colors(loadColors()) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - pos.w = position.w; - pos.h = position.h; - - aiShield = std::make_shared("AIShield"); - aiShield->disable(); -} - -int3 CMinimap::translateMousePosition() -{ - // 0 = top-left corner, 1 = bottom-right corner - double dx = double(GH.getCursorPosition().x - pos.x) / pos.w; - double dy = double(GH.getCursorPosition().y - pos.y) / pos.h; - - int3 mapSizes = LOCPLINT->cb->getMapSize(); - - int3 tile ((si32)(mapSizes.x * dx), (si32)(mapSizes.y * dy), level); - return tile; -} - -void CMinimap::moveAdvMapSelection() -{ - int3 newLocation = translateMousePosition(); - adventureInt->centerOn(newLocation); - - if (!(adventureInt->active & GENERAL)) - GH.totalRedraw(); //redraw this as well as inactive adventure map - else - redraw();//redraw only this -} - -void CMinimap::clickLeft(tribool down, bool previousState) -{ - if(down) - moveAdvMapSelection(); -} - -void CMinimap::clickRight(tribool down, bool previousState) -{ - adventureInt->handleRightClick(CGI->generaltexth->zelp[291].second, down); -} - -void CMinimap::hover(bool on) -{ - if(on) - GH.statusbar->write(CGI->generaltexth->zelp[291].first); - else - GH.statusbar->clear(); -} - -void CMinimap::mouseMoved(const SDL_MouseMotionEvent & sEvent) -{ - if(mouseState(EIntObjMouseBtnType::LEFT)) - moveAdvMapSelection(); -} - -void CMinimap::showAll(SDL_Surface * to) -{ - CIntObject::showAll(to); - if(minimap) - { - int3 mapSizes = LOCPLINT->cb->getMapSize(); - int3 tileCountOnScreen = adventureInt->terrain.tileCountOnScreen(); - - //draw radar - Rect oldClip; - Rect radar = - { - si16(adventureInt->position.x * pos.w / mapSizes.x + pos.x), - si16(adventureInt->position.y * pos.h / mapSizes.y + pos.y), - ui16(tileCountOnScreen.x * pos.w / mapSizes.x), - ui16(tileCountOnScreen.y * pos.h / mapSizes.y) - }; - - if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) - { - // adjusts radar so that it doesn't go out of map in world view mode (since there's no frame) - radar.x = std::min(std::max(pos.x, radar.x), pos.x + pos.w - radar.w); - radar.y = std::min(std::max(pos.y, radar.y), pos.y + pos.h - radar.h); - - if(radar.x < pos.x && radar.y < pos.y) - return; // whole map is visible at once, no point in redrawing border - } - - CSDL_Ext::getClipRect(to, oldClip); - CSDL_Ext::setClipRect(to, pos); - CSDL_Ext::drawDashedBorder(to, radar, Colors::PURPLE); - CSDL_Ext::setClipRect(to, oldClip); - } -} - -void CMinimap::update() -{ - if(aiShield->recActions & UPDATE) //AI turn is going on. There is no need to update minimap - return; - - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - minimap = std::make_shared(this, level); - redraw(); -} - -void CMinimap::setLevel(int newLevel) -{ - level = newLevel; - update(); -} - -void CMinimap::setAIRadar(bool on) -{ - if(on) - { - aiShield->enable(); - minimap.reset(); - } - else - { - aiShield->disable(); - update(); - } - // this my happen during AI turn when this interface is inactive - // force redraw in order to properly update interface - GH.totalRedraw(); -} - -void CMinimap::hideTile(const int3 &pos) -{ - if(minimap) - minimap->refreshTile(pos); -} - -void CMinimap::showTile(const int3 &pos) -{ - if(minimap) - minimap->refreshTile(pos); -} - CInfoBar::CVisibleInfo::CVisibleInfo() : CIntObject(0, Point(8, 12)) { @@ -940,312 +341,3 @@ void CInfoBar::showGameStatus() redraw(); } -CInGameConsole::CInGameConsole() - : CIntObject(KEYBOARD | TEXTINPUT), - prevEntDisp(-1), - defaultTimeout(10000), - maxDisplayedTexts(10) -{ -} - -void CInGameConsole::show(SDL_Surface * to) -{ - int number = 0; - - std::vector >::iterator> toDel; - - boost::unique_lock lock(texts_mx); - for(auto it = texts.begin(); it != texts.end(); ++it, ++number) - { - Point leftBottomCorner(0, pos.h); - - graphics->fonts[FONT_MEDIUM]->renderTextLeft(to, it->first, Colors::GREEN, - Point(leftBottomCorner.x + 50, leftBottomCorner.y - (int)texts.size() * 20 - 80 + number*20)); - - if((int)(SDL_GetTicks() - it->second) > defaultTimeout) - { - toDel.push_back(it); - } - } - - for(auto & elem : toDel) - { - texts.erase(elem); - } -} - -void CInGameConsole::print(const std::string &txt) -{ - boost::unique_lock lock(texts_mx); - int lineLen = conf.go()->ac.outputLineLength; - - if(txt.size() < lineLen) - { - texts.push_back(std::make_pair(txt, SDL_GetTicks())); - if(texts.size() > maxDisplayedTexts) - { - texts.pop_front(); - } - } - else - { - assert(lineLen); - for(int g=0; g maxDisplayedTexts) - { - texts.pop_front(); - } - } - } -} - -void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key) -{ - if(key.type != SDL_KEYDOWN) return; - - if(!captureAllKeys && key.keysym.sym != SDLK_TAB) return; //because user is not entering any text - - switch(key.keysym.sym) - { - case SDLK_TAB: - case SDLK_ESCAPE: - { - if(captureAllKeys) - { - endEnteringText(false); - } - else if(SDLK_TAB == key.keysym.sym) - { - startEnteringText(); - } - break; - } - case SDLK_RETURN: //enter key - { - if(!enteredText.empty() && captureAllKeys) - { - bool anyTextExceptCaret = enteredText.size() > 1; - endEnteringText(anyTextExceptCaret); - - if(anyTextExceptCaret) - { - CCS->soundh->playSound("CHAT"); - } - } - break; - } - case SDLK_BACKSPACE: - { - if(enteredText.size() > 1) - { - Unicode::trimRight(enteredText,2); - enteredText += '_'; - refreshEnteredText(); - } - break; - } - case SDLK_UP: //up arrow - { - if(previouslyEntered.size() == 0) - break; - - if(prevEntDisp == -1) - { - prevEntDisp = static_cast(previouslyEntered.size() - 1); - enteredText = previouslyEntered[prevEntDisp] + "_"; - refreshEnteredText(); - } - else if( prevEntDisp > 0) - { - --prevEntDisp; - enteredText = previouslyEntered[prevEntDisp] + "_"; - refreshEnteredText(); - } - break; - } - case SDLK_DOWN: //down arrow - { - if(prevEntDisp != -1 && prevEntDisp+1 < previouslyEntered.size()) - { - ++prevEntDisp; - enteredText = previouslyEntered[prevEntDisp] + "_"; - refreshEnteredText(); - } - else if(prevEntDisp+1 == previouslyEntered.size()) //useful feature - { - prevEntDisp = -1; - enteredText = "_"; - refreshEnteredText(); - } - break; - } - default: - { - break; - } - } -} - -void CInGameConsole::textInputed(const SDL_TextInputEvent & event) -{ - if(!captureAllKeys || enteredText.size() == 0) - return; - enteredText.resize(enteredText.size()-1); - - enteredText += event.text; - enteredText += "_"; - - refreshEnteredText(); -} - -void CInGameConsole::textEdited(const SDL_TextEditingEvent & event) -{ - //do nothing here -} - -void CInGameConsole::startEnteringText() -{ - if (!active) - return; - - if (captureAllKeys) - return; - - assert(GH.statusbar); - assert(currentStatusBar.expired());//effectively, nullptr check - - currentStatusBar = GH.statusbar; - - captureAllKeys = true; - enteredText = "_"; - - GH.statusbar->setEnteringMode(true); - GH.statusbar->setEnteredText(enteredText); -} - -void CInGameConsole::endEnteringText(bool processEnteredText) -{ - captureAllKeys = false; - prevEntDisp = -1; - if(processEnteredText) - { - std::string txt = enteredText.substr(0, enteredText.size()-1); - previouslyEntered.push_back(txt); - - if(txt.at(0) == '/') - { - //some commands like gosolo don't work when executed from GUI thread - auto threadFunction = [=]() - { - ClientCommandManager commandController; - commandController.processCommand(txt.substr(1), true); - }; - - boost::thread clientCommandThread(threadFunction); - clientCommandThread.detach(); - } - else - LOCPLINT->cb->sendMessage(txt, LOCPLINT->getSelection()); - } - enteredText.clear(); - - auto statusbar = currentStatusBar.lock(); - assert(statusbar); - - if (statusbar) - statusbar->setEnteringMode(false); - - currentStatusBar.reset(); -} - -void CInGameConsole::refreshEnteredText() -{ - auto statusbar = currentStatusBar.lock(); - assert(statusbar); - - if (statusbar) - statusbar->setEnteredText(enteredText); -} - -CAdvMapPanel::CAdvMapPanel(std::shared_ptr bg, Point position) - : CIntObject() - , background(bg) -{ - defActions = 255; - recActions = 255; - pos.x += position.x; - pos.y += position.y; - if (bg) - { - pos.w = bg->width(); - pos.h = bg->height(); - } -} - -void CAdvMapPanel::addChildColorableButton(std::shared_ptr button) -{ - colorableButtons.push_back(button); - addChildToPanel(button, ACTIVATE | DEACTIVATE); -} - -void CAdvMapPanel::setPlayerColor(const PlayerColor & clr) -{ - for(auto & button : colorableButtons) - { - button->setPlayerColor(clr); - } -} - -void CAdvMapPanel::showAll(SDL_Surface * to) -{ - if(background) - background->draw(to, pos.x, pos.y); - - CIntObject::showAll(to); -} - -void CAdvMapPanel::addChildToPanel(std::shared_ptr obj, ui8 actions) -{ - otherObjects.push_back(obj); - obj->recActions |= actions | SHOWALL; - obj->recActions &= ~DISPOSE; - addChild(obj.get(), false); -} - -CAdvMapWorldViewPanel::CAdvMapWorldViewPanel(std::shared_ptr _icons, std::shared_ptr bg, Point position, int spaceBottom, const PlayerColor &color) - : CAdvMapPanel(bg, position), icons(_icons) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - int fillerHeight = bg ? spaceBottom - pos.y - pos.h : 0; - - if(fillerHeight > 0) - { - backgroundFiller = std::make_shared("DIBOXBCK", Rect(0, pos.h, pos.w, fillerHeight)); - } -} - -CAdvMapWorldViewPanel::~CAdvMapWorldViewPanel() = default; - -void CAdvMapWorldViewPanel::recolorIcons(const PlayerColor & color, int indexOffset) -{ - assert(iconsData.size() == currentIcons.size()); - - for(size_t idx = 0; idx < iconsData.size(); idx++) - { - const auto & data = iconsData.at(idx); - currentIcons[idx]->setFrame(data.first + indexOffset); - } -} - -void CAdvMapWorldViewPanel::addChildIcon(std::pair data, int indexOffset) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - iconsData.push_back(data); - currentIcons.push_back(std::make_shared(icons, data.first + indexOffset, 0, data.second.x, data.second.y)); -} diff --git a/client/adventureMap/CInfoBar.h b/client/adventureMap/CInfoBar.h index 3b4874d9e..7ec4d3949 100644 --- a/client/adventureMap/CInfoBar.h +++ b/client/adventureMap/CInfoBar.h @@ -37,218 +37,6 @@ class CTownTooltip; class CTextBox; class IImage; -/// Base UI Element for hero\town lists -class CList : public CIntObject -{ -protected: - class CListItem : public CIntObject, public std::enable_shared_from_this - { - CList * parent; - std::shared_ptr selection; - public: - CListItem(CList * parent); - ~CListItem(); - - void clickRight(tribool down, bool previousState) override; - void clickLeft(tribool down, bool previousState) override; - void hover(bool on) override; - void onSelect(bool on); - - /// create object with selection rectangle - virtual std::shared_ptr genSelection()=0; - /// reaction on item selection (e.g. enable selection border) - /// NOTE: item may be deleted in selected state - virtual void select(bool on)=0; - /// open item (town or hero screen) - virtual void open()=0; - /// show right-click tooltip - virtual void showTooltip()=0; - /// get hover text for status bar - virtual std::string getHoverText()=0; - }; - - std::shared_ptr listBox; - const size_t size; - - /** - * @brief CList - protected constructor - * @param size - maximal amount of visible at once items - * @param position - cordinates - * @param btnUp - path to image to use as top button - * @param btnDown - path to image to use as bottom button - * @param listAmount - amount of items in the list - * @param helpUp - index in zelp.txt for button help tooltip - * @param helpDown - index in zelp.txt for button help tooltip - * @param create - function for creating items in listbox - * @param destroy - function for deleting items in listbox - */ - CList(int size, Point position, std::string btnUp, std::string btnDown, size_t listAmount, int helpUp, int helpDown, CListBox::CreateFunc create); - - //for selection\deselection - std::shared_ptr selected; - void select(std::shared_ptr which); - friend class CListItem; - - std::shared_ptr scrollUp; - std::shared_ptr scrollDown; - - /// should be called when list is invalidated - void update(); - -public: - /// functions that will be called when selection changes - CFunctionList onSelect; - - /// return index of currently selected element - int getSelectedIndex(); - - /// set of methods to switch selection - void selectIndex(int which); - void selectNext(); - void selectPrev(); -}; - -/// List of heroes which is shown at the right of the adventure map screen -class CHeroList : public CList -{ - /// Empty hero item used as placeholder for unused entries in list - class CEmptyHeroItem : public CIntObject - { - std::shared_ptr movement; - std::shared_ptr mana; - std::shared_ptr portrait; - public: - CEmptyHeroItem(); - }; - - class CHeroItem : public CListItem - { - std::shared_ptr movement; - std::shared_ptr mana; - std::shared_ptr portrait; - public: - const CGHeroInstance * const hero; - - CHeroItem(CHeroList * parent, const CGHeroInstance * hero); - - std::shared_ptr genSelection() override; - void update(); - void select(bool on) override; - void open() override; - void showTooltip() override; - std::string getHoverText() override; - }; - - std::shared_ptr createHeroItem(size_t index); -public: - /** - * @brief CHeroList - * @param size, position, btnUp, btnDown @see CList::CList - */ - CHeroList(int size, Point position, std::string btnUp, std::string btnDown); - - /// Select specific hero and scroll if needed - void select(const CGHeroInstance * hero = nullptr); - - /// Update hero. Will add or remove it from the list if needed - void update(const CGHeroInstance * hero = nullptr); -}; - -/// List of towns which is shown at the right of the adventure map screen or in the town screen -class CTownList : public CList -{ - class CTownItem : public CListItem - { - std::shared_ptr picture; - public: - const CGTownInstance * const town; - - CTownItem(CTownList *parent, const CGTownInstance * town); - - std::shared_ptr genSelection() override; - void update(); - void select(bool on) override; - void open() override; - void showTooltip() override; - std::string getHoverText() override; - }; - - std::shared_ptr createTownItem(size_t index); -public: - /** - * @brief CTownList - * @param size, position, btnUp, btnDown @see CList::CList - */ - CTownList(int size, Point position, std::string btnUp, std::string btnDown); - - /// Select specific town and scroll if needed - void select(const CGTownInstance * town = nullptr); - - /// Update town. Will add or remove it from the list if needed - void update(const CGTownInstance * town = nullptr); -}; - -class CMinimap; - -class CMinimapInstance : public CIntObject -{ - CMinimap * parent; - SDL_Surface * minimap; - int level; - - //get color of selected tile on minimap - const SDL_Color & getTileColor(const int3 & pos); - - void blitTileWithColor(const SDL_Color & color, const int3 & pos, SDL_Surface * to, int x, int y); - - //draw minimap already scaled. - //result is not antialiased. Will result in "missing" pixels on huge maps (>144) - void drawScaled(int level); -public: - CMinimapInstance(CMinimap * parent, int level); - ~CMinimapInstance(); - - void showAll(SDL_Surface * to) override; - void tileToPixels (const int3 & tile, int & x, int & y, int toX = 0, int toY = 0); - void refreshTile(const int3 & pos); -}; - -/// Minimap which is displayed at the right upper corner of adventure map -class CMinimap : public CIntObject -{ -protected: - std::shared_ptr aiShield; //the graphic displayed during AI turn - std::shared_ptr minimap; - int level; - - //to initialize colors - std::map > loadColors(); - - void clickLeft(tribool down, bool previousState) override; - void clickRight(tribool down, bool previousState) override; - void hover (bool on) override; - void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; - - void moveAdvMapSelection(); - -public: - // terrainID -> (normal color, blocked color) - const std::map > colors; - - CMinimap(const Rect & position); - - //should be called to invalidate whole map - different player or level - int3 translateMousePosition(); - void update(); - void setLevel(int level); - void setAIRadar(bool on); - - void showAll(SDL_Surface * to) override; - - void hideTile(const int3 &pos); //puts FoW - void showTile(const int3 &pos); //removes FoW -}; - /// Info box which shows next week/day information, hold the current date class CInfoBar : public CIntObject { @@ -365,66 +153,3 @@ public: void showGameStatus(); }; -/// simple panel that contains other displayable elements; used to separate groups of controls -class CAdvMapPanel : public CIntObject -{ - std::vector> colorableButtons; - std::vector> otherObjects; - /// the surface passed to this obj will be freed in dtor - std::shared_ptr background; -public: - CAdvMapPanel(std::shared_ptr bg, Point position); - - void addChildToPanel(std::shared_ptr obj, ui8 actions = 0); - void addChildColorableButton(std::shared_ptr button); - /// recolors all buttons to given player color - void setPlayerColor(const PlayerColor & clr); - - void showAll(SDL_Surface * to) override; -}; - -/// specialized version of CAdvMapPanel that handles recolorable def-based pictures for world view info panel -class CAdvMapWorldViewPanel : public CAdvMapPanel -{ - /// data that allows reconstruction of panel info icons - std::vector> iconsData; - /// ptrs to child-pictures constructed from iconsData - std::vector> currentIcons; - /// surface drawn below world view panel on higher resolutions (won't be needed when world view panel is configured for extraResolutions mod) - std::shared_ptr backgroundFiller; - std::shared_ptr icons; -public: - CAdvMapWorldViewPanel(std::shared_ptr _icons, std::shared_ptr bg, Point position, int spaceBottom, const PlayerColor &color); - virtual ~CAdvMapWorldViewPanel(); - - void addChildIcon(std::pair data, int indexOffset); - /// recreates all pictures from given def to recolor them according to current player color - void recolorIcons(const PlayerColor & color, int indexOffset); -}; - -class CInGameConsole : public CIntObject -{ -private: - std::list< std::pair< std::string, uint32_t > > texts; //list - boost::mutex texts_mx; // protects texts - std::vector< std::string > previouslyEntered; //previously entered texts, for up/down arrows to work - int prevEntDisp; //displayed entry from previouslyEntered - if none it's -1 - int defaultTimeout; //timeout for new texts (in ms) - int maxDisplayedTexts; //hiw many texts can be displayed simultaneously - - std::weak_ptr currentStatusBar; -public: - std::string enteredText; - void show(SDL_Surface * to) override; - void print(const std::string &txt); - void keyPressed (const SDL_KeyboardEvent & key) override; //call-in - - void textInputed(const SDL_TextInputEvent & event) override; - void textEdited(const SDL_TextEditingEvent & event) override; - - void startEnteringText(); - void endEnteringText(bool processEnteredText); - void refreshEnteredText(); - - CInGameConsole(); -}; diff --git a/client/adventureMap/CList.cpp b/client/adventureMap/CList.cpp index b2d83416c..0e5a4304f 100644 --- a/client/adventureMap/CList.cpp +++ b/client/adventureMap/CList.cpp @@ -358,894 +358,3 @@ void CTownList::update(const CGTownInstance *) CList::update(); } -const SDL_Color & CMinimapInstance::getTileColor(const int3 & pos) -{ - const TerrainTile * tile = LOCPLINT->cb->getTile(pos, false); - - // if tile is not visible it will be black on minimap - if(!tile) - return Colors::BLACK; - - // if object at tile is owned - it will be colored as its owner - for (const CGObjectInstance *obj : tile->blockingObjects) - { - //heroes will be blitted later - switch (obj->ID) - { - case Obj::HERO: - case Obj::PRISON: - continue; - } - - PlayerColor player = obj->getOwner(); - if(player == PlayerColor::NEUTRAL) - return *graphics->neutralColor; - else - if (player < PlayerColor::PLAYER_LIMIT) - return graphics->playerColors[player.getNum()]; - } - - // else - use terrain color (blocked version or normal) - const auto & colorPair = parent->colors.find(tile->terType->getId())->second; - if (tile->blocked && (!tile->visitable)) - return colorPair.second; - else - return colorPair.first; -} -void CMinimapInstance::tileToPixels (const int3 &tile, int &x, int &y, int toX, int toY) -{ - int3 mapSizes = LOCPLINT->cb->getMapSize(); - - double stepX = double(pos.w) / mapSizes.x; - double stepY = double(pos.h) / mapSizes.y; - - x = static_cast(toX + stepX * tile.x); - y = static_cast(toY + stepY * tile.y); -} - -void CMinimapInstance::blitTileWithColor(const SDL_Color &color, const int3 &tile, SDL_Surface *to, int toX, int toY) -{ - //coordinates of rectangle on minimap representing this tile - // begin - first to blit, end - first NOT to blit - int xBegin, yBegin, xEnd, yEnd; - tileToPixels (tile, xBegin, yBegin, toX, toY); - tileToPixels (int3 (tile.x + 1, tile.y + 1, tile.z), xEnd, yEnd, toX, toY); - - for (int y=yBegin; ypixels + y * to->pitch + xBegin * minimap->format->BytesPerPixel; - - for (int x=xBegin; x::PutColor(ptr, color); - } -} - -void CMinimapInstance::refreshTile(const int3 &tile) -{ - blitTileWithColor(getTileColor(int3(tile.x, tile.y, level)), tile, minimap, 0, 0); -} - -void CMinimapInstance::drawScaled(int level) -{ - int3 mapSizes = LOCPLINT->cb->getMapSize(); - - //size of one map tile on our minimap - double stepX = double(pos.w) / mapSizes.x; - double stepY = double(pos.h) / mapSizes.y; - - double currY = 0; - for (int y=0; y(currX); - int yBegin = static_cast(currY); - int xEnd = static_cast(currX + stepX); - int yEnd = static_cast(currY + stepY); - - for (int y=yBegin; ypixels + y * minimap->pitch + xBegin * minimap->format->BytesPerPixel; - - for (int x=xBegin; x::PutColor(ptr, color); - } - } - } -} - -CMinimapInstance::CMinimapInstance(CMinimap *Parent, int Level): - parent(Parent), - minimap(CSDL_Ext::createSurfaceWithBpp<4>(parent->pos.w, parent->pos.h)), - level(Level) -{ - pos.w = parent->pos.w; - pos.h = parent->pos.h; - drawScaled(level); -} - -CMinimapInstance::~CMinimapInstance() -{ - SDL_FreeSurface(minimap); -} - -void CMinimapInstance::showAll(SDL_Surface * to) -{ - blitAtLoc(minimap, 0, 0, to); - - //draw heroes - std::vector heroes = LOCPLINT->cb->getHeroesInfo(false); //TODO: do we really need separate function for drawing heroes? - for(auto & hero : heroes) - { - int3 position = hero->visitablePos(); - if(position.z == level) - { - const SDL_Color & color = graphics->playerColors[hero->getOwner().getNum()]; - blitTileWithColor(color, position, to, pos.x, pos.y); - } - } -} - -std::map > CMinimap::loadColors() -{ - std::map > ret; - - for(const auto & terrain : CGI->terrainTypeHandler->objects) - { - SDL_Color normal = CSDL_Ext::toSDL(terrain->minimapUnblocked); - SDL_Color blocked = CSDL_Ext::toSDL(terrain->minimapBlocked); - - ret[terrain->getId()] = std::make_pair(normal, blocked); - } - return ret; -} - -CMinimap::CMinimap(const Rect & position) - : CIntObject(LCLICK | RCLICK | HOVER | MOVE, position.topLeft()), - level(0), - colors(loadColors()) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - pos.w = position.w; - pos.h = position.h; - - aiShield = std::make_shared("AIShield"); - aiShield->disable(); -} - -int3 CMinimap::translateMousePosition() -{ - // 0 = top-left corner, 1 = bottom-right corner - double dx = double(GH.getCursorPosition().x - pos.x) / pos.w; - double dy = double(GH.getCursorPosition().y - pos.y) / pos.h; - - int3 mapSizes = LOCPLINT->cb->getMapSize(); - - int3 tile ((si32)(mapSizes.x * dx), (si32)(mapSizes.y * dy), level); - return tile; -} - -void CMinimap::moveAdvMapSelection() -{ - int3 newLocation = translateMousePosition(); - adventureInt->centerOn(newLocation); - - if (!(adventureInt->active & GENERAL)) - GH.totalRedraw(); //redraw this as well as inactive adventure map - else - redraw();//redraw only this -} - -void CMinimap::clickLeft(tribool down, bool previousState) -{ - if(down) - moveAdvMapSelection(); -} - -void CMinimap::clickRight(tribool down, bool previousState) -{ - adventureInt->handleRightClick(CGI->generaltexth->zelp[291].second, down); -} - -void CMinimap::hover(bool on) -{ - if(on) - GH.statusbar->write(CGI->generaltexth->zelp[291].first); - else - GH.statusbar->clear(); -} - -void CMinimap::mouseMoved(const SDL_MouseMotionEvent & sEvent) -{ - if(mouseState(EIntObjMouseBtnType::LEFT)) - moveAdvMapSelection(); -} - -void CMinimap::showAll(SDL_Surface * to) -{ - CIntObject::showAll(to); - if(minimap) - { - int3 mapSizes = LOCPLINT->cb->getMapSize(); - int3 tileCountOnScreen = adventureInt->terrain.tileCountOnScreen(); - - //draw radar - Rect oldClip; - Rect radar = - { - si16(adventureInt->position.x * pos.w / mapSizes.x + pos.x), - si16(adventureInt->position.y * pos.h / mapSizes.y + pos.y), - ui16(tileCountOnScreen.x * pos.w / mapSizes.x), - ui16(tileCountOnScreen.y * pos.h / mapSizes.y) - }; - - if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) - { - // adjusts radar so that it doesn't go out of map in world view mode (since there's no frame) - radar.x = std::min(std::max(pos.x, radar.x), pos.x + pos.w - radar.w); - radar.y = std::min(std::max(pos.y, radar.y), pos.y + pos.h - radar.h); - - if(radar.x < pos.x && radar.y < pos.y) - return; // whole map is visible at once, no point in redrawing border - } - - CSDL_Ext::getClipRect(to, oldClip); - CSDL_Ext::setClipRect(to, pos); - CSDL_Ext::drawDashedBorder(to, radar, Colors::PURPLE); - CSDL_Ext::setClipRect(to, oldClip); - } -} - -void CMinimap::update() -{ - if(aiShield->recActions & UPDATE) //AI turn is going on. There is no need to update minimap - return; - - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - minimap = std::make_shared(this, level); - redraw(); -} - -void CMinimap::setLevel(int newLevel) -{ - level = newLevel; - update(); -} - -void CMinimap::setAIRadar(bool on) -{ - if(on) - { - aiShield->enable(); - minimap.reset(); - } - else - { - aiShield->disable(); - update(); - } - // this my happen during AI turn when this interface is inactive - // force redraw in order to properly update interface - GH.totalRedraw(); -} - -void CMinimap::hideTile(const int3 &pos) -{ - if(minimap) - minimap->refreshTile(pos); -} - -void CMinimap::showTile(const int3 &pos) -{ - if(minimap) - minimap->refreshTile(pos); -} - -CInfoBar::CVisibleInfo::CVisibleInfo() - : CIntObject(0, Point(8, 12)) -{ -} - -void CInfoBar::CVisibleInfo::show(SDL_Surface * to) -{ - CIntObject::show(to); - for(auto object : forceRefresh) - object->showAll(to); -} - -CInfoBar::EmptyVisibleInfo::EmptyVisibleInfo() -{ -} - -CInfoBar::VisibleHeroInfo::VisibleHeroInfo(const CGHeroInstance * hero) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared("ADSTATHR"); - heroTooltip = std::make_shared(Point(0,0), hero); -} - -CInfoBar::VisibleTownInfo::VisibleTownInfo(const CGTownInstance * town) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared("ADSTATCS"); - townTooltip = std::make_shared(Point(0,0), town); -} - -CInfoBar::VisibleDateInfo::VisibleDateInfo() -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - - animation = std::make_shared(1, 0, getNewDayName(), CShowableAnim::PLAY_ONCE, 180);// H3 uses around 175-180 ms per frame - - std::string labelText; - if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) == 1 && LOCPLINT->cb->getDate(Date::DAY) != 1) // monday of any week but first - show new week info - labelText = CGI->generaltexth->allTexts[63] + " " + boost::lexical_cast(LOCPLINT->cb->getDate(Date::WEEK)); - else - labelText = CGI->generaltexth->allTexts[64] + " " + boost::lexical_cast(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK)); - - label = std::make_shared(95, 31, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, labelText); - - forceRefresh.push_back(label); -} - -std::string CInfoBar::VisibleDateInfo::getNewDayName() -{ - if(LOCPLINT->cb->getDate(Date::DAY) == 1) - return "NEWDAY"; - - if(LOCPLINT->cb->getDate(Date::DAY) != 1) - return "NEWDAY"; - - switch(LOCPLINT->cb->getDate(Date::WEEK)) - { - case 1: - return "NEWWEEK1"; - case 2: - return "NEWWEEK2"; - case 3: - return "NEWWEEK3"; - case 4: - return "NEWWEEK4"; - default: - return ""; - } -} - -CInfoBar::VisibleEnemyTurnInfo::VisibleEnemyTurnInfo(PlayerColor player) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared("ADSTATNX"); - banner = std::make_shared("CREST58", player.getNum(), 0, 20, 51); - sand = std::make_shared(99, 51, "HOURSAND", 0, 100); // H3 uses around 100 ms per frame - glass = std::make_shared(99, 51, "HOURGLAS", CShowableAnim::PLAY_ONCE, 1000); // H3 scales this nicely for AI turn duration, don't have anything like that in vcmi -} - -CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo() -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - //get amount of halls of each level - std::vector halls(4, 0); - for(auto town : LOCPLINT->towns) - { - int hallLevel = town->hallLevel(); - //negative value means no village hall, unlikely but possible - if(hallLevel >= 0) - halls.at(hallLevel)++; - } - - std::vector allies, enemies; - - //generate list of allies and enemies - for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++) - { - if(LOCPLINT->cb->getPlayerStatus(PlayerColor(i), false) == EPlayerStatus::INGAME) - { - if(LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, PlayerColor(i)) != PlayerRelations::ENEMIES) - allies.push_back(PlayerColor(i)); - else - enemies.push_back(PlayerColor(i)); - } - } - - //generate widgets - background = std::make_shared("ADSTATIN"); - allyLabel = std::make_shared(10, 106, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[390] + ":"); - enemyLabel = std::make_shared(10, 136, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[391] + ":"); - - int posx = allyLabel->pos.w + allyLabel->pos.x - pos.x + 4; - for(PlayerColor & player : allies) - { - auto image = std::make_shared("ITGFLAGS", player.getNum(), 0, posx, 102); - posx += image->pos.w; - flags.push_back(image); - } - - posx = enemyLabel->pos.w + enemyLabel->pos.x - pos.x + 4; - for(PlayerColor & player : enemies) - { - auto image = std::make_shared("ITGFLAGS", player.getNum(), 0, posx, 132); - posx += image->pos.w; - flags.push_back(image); - } - - for(size_t i=0; i("itmtl", i, 0, 6 + 42 * (int)i , 11)); - if(halls[i]) - hallLabels.push_back(std::make_shared( 26 + 42 * (int)i, 64, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, boost::lexical_cast(halls[i]))); - } -} - -CInfoBar::VisibleComponentInfo::VisibleComponentInfo(const Component & compToDisplay, std::string message) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - - background = std::make_shared("ADSTATOT", 1, 0); - - comp = std::make_shared(compToDisplay); - comp->moveTo(Point(pos.x+47, pos.y+50)); - - text = std::make_shared(message, Rect(10, 4, 160, 50), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); -} - -void CInfoBar::playNewDaySound() -{ - if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) != 1) // not first day of the week - CCS->soundh->playSound(soundBase::newDay); - else if(LOCPLINT->cb->getDate(Date::WEEK) != 1) // not first week in month - CCS->soundh->playSound(soundBase::newWeek); - else if(LOCPLINT->cb->getDate(Date::MONTH) != 1) // not first month - CCS->soundh->playSound(soundBase::newMonth); - else - CCS->soundh->playSound(soundBase::newDay); -} - -void CInfoBar::reset() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = EMPTY; - visibleInfo = std::make_shared(); -} - -void CInfoBar::showSelection() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - if(adventureInt->selection) - { - if(auto hero = dynamic_cast(adventureInt->selection)) - { - showHeroSelection(hero); - return; - } - else if(auto town = dynamic_cast(adventureInt->selection)) - { - showTownSelection(town); - return; - } - } - showGameStatus();//FIXME: may be incorrect but shouldn't happen in general -} - -void CInfoBar::tick() -{ - removeUsedEvents(TIME); - if(GH.topInt() == adventureInt) - showSelection(); -} - -void CInfoBar::clickLeft(tribool down, bool previousState) -{ - if(down) - { - if(state == HERO || state == TOWN) - showGameStatus(); - else if(state == GAME) - showDate(); - else - showSelection(); - } -} - -void CInfoBar::clickRight(tribool down, bool previousState) -{ - adventureInt->handleRightClick(CGI->generaltexth->allTexts[109], down); -} - -void CInfoBar::hover(bool on) -{ - if(on) - GH.statusbar->write(CGI->generaltexth->zelp[292].first); - else - GH.statusbar->clear(); -} - -CInfoBar::CInfoBar(const Rect & position) - : CIntObject(LCLICK | RCLICK | HOVER, position.topLeft()), - state(EMPTY) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - pos.w = position.w; - pos.h = position.h; - reset(); -} - -void CInfoBar::showDate() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - playNewDaySound(); - state = DATE; - visibleInfo = std::make_shared(); - setTimer(3000); // confirmed to match H3 - redraw(); -} - -void CInfoBar::showComponent(const Component & comp, std::string message) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = COMPONENT; - visibleInfo = std::make_shared(comp, message); - setTimer(3000); - redraw(); -} - -void CInfoBar::startEnemyTurn(PlayerColor color) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = AITURN; - visibleInfo = std::make_shared(color); - redraw(); -} - -void CInfoBar::showHeroSelection(const CGHeroInstance * hero) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - if(!hero) - { - reset(); - } - else - { - state = HERO; - visibleInfo = std::make_shared(hero); - } - redraw(); -} - -void CInfoBar::showTownSelection(const CGTownInstance * town) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - if(!town) - { - reset(); - } - else - { - state = TOWN; - visibleInfo = std::make_shared(town); - } - redraw(); -} - -void CInfoBar::showGameStatus() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = GAME; - visibleInfo = std::make_shared(); - setTimer(3000); - redraw(); -} - -CInGameConsole::CInGameConsole() - : CIntObject(KEYBOARD | TEXTINPUT), - prevEntDisp(-1), - defaultTimeout(10000), - maxDisplayedTexts(10) -{ -} - -void CInGameConsole::show(SDL_Surface * to) -{ - int number = 0; - - std::vector >::iterator> toDel; - - boost::unique_lock lock(texts_mx); - for(auto it = texts.begin(); it != texts.end(); ++it, ++number) - { - Point leftBottomCorner(0, pos.h); - - graphics->fonts[FONT_MEDIUM]->renderTextLeft(to, it->first, Colors::GREEN, - Point(leftBottomCorner.x + 50, leftBottomCorner.y - (int)texts.size() * 20 - 80 + number*20)); - - if((int)(SDL_GetTicks() - it->second) > defaultTimeout) - { - toDel.push_back(it); - } - } - - for(auto & elem : toDel) - { - texts.erase(elem); - } -} - -void CInGameConsole::print(const std::string &txt) -{ - boost::unique_lock lock(texts_mx); - int lineLen = conf.go()->ac.outputLineLength; - - if(txt.size() < lineLen) - { - texts.push_back(std::make_pair(txt, SDL_GetTicks())); - if(texts.size() > maxDisplayedTexts) - { - texts.pop_front(); - } - } - else - { - assert(lineLen); - for(int g=0; g maxDisplayedTexts) - { - texts.pop_front(); - } - } - } -} - -void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key) -{ - if(key.type != SDL_KEYDOWN) return; - - if(!captureAllKeys && key.keysym.sym != SDLK_TAB) return; //because user is not entering any text - - switch(key.keysym.sym) - { - case SDLK_TAB: - case SDLK_ESCAPE: - { - if(captureAllKeys) - { - endEnteringText(false); - } - else if(SDLK_TAB == key.keysym.sym) - { - startEnteringText(); - } - break; - } - case SDLK_RETURN: //enter key - { - if(!enteredText.empty() && captureAllKeys) - { - bool anyTextExceptCaret = enteredText.size() > 1; - endEnteringText(anyTextExceptCaret); - - if(anyTextExceptCaret) - { - CCS->soundh->playSound("CHAT"); - } - } - break; - } - case SDLK_BACKSPACE: - { - if(enteredText.size() > 1) - { - Unicode::trimRight(enteredText,2); - enteredText += '_'; - refreshEnteredText(); - } - break; - } - case SDLK_UP: //up arrow - { - if(previouslyEntered.size() == 0) - break; - - if(prevEntDisp == -1) - { - prevEntDisp = static_cast(previouslyEntered.size() - 1); - enteredText = previouslyEntered[prevEntDisp] + "_"; - refreshEnteredText(); - } - else if( prevEntDisp > 0) - { - --prevEntDisp; - enteredText = previouslyEntered[prevEntDisp] + "_"; - refreshEnteredText(); - } - break; - } - case SDLK_DOWN: //down arrow - { - if(prevEntDisp != -1 && prevEntDisp+1 < previouslyEntered.size()) - { - ++prevEntDisp; - enteredText = previouslyEntered[prevEntDisp] + "_"; - refreshEnteredText(); - } - else if(prevEntDisp+1 == previouslyEntered.size()) //useful feature - { - prevEntDisp = -1; - enteredText = "_"; - refreshEnteredText(); - } - break; - } - default: - { - break; - } - } -} - -void CInGameConsole::textInputed(const SDL_TextInputEvent & event) -{ - if(!captureAllKeys || enteredText.size() == 0) - return; - enteredText.resize(enteredText.size()-1); - - enteredText += event.text; - enteredText += "_"; - - refreshEnteredText(); -} - -void CInGameConsole::textEdited(const SDL_TextEditingEvent & event) -{ - //do nothing here -} - -void CInGameConsole::startEnteringText() -{ - if (!active) - return; - - if (captureAllKeys) - return; - - assert(GH.statusbar); - assert(currentStatusBar.expired());//effectively, nullptr check - - currentStatusBar = GH.statusbar; - - captureAllKeys = true; - enteredText = "_"; - - GH.statusbar->setEnteringMode(true); - GH.statusbar->setEnteredText(enteredText); -} - -void CInGameConsole::endEnteringText(bool processEnteredText) -{ - captureAllKeys = false; - prevEntDisp = -1; - if(processEnteredText) - { - std::string txt = enteredText.substr(0, enteredText.size()-1); - previouslyEntered.push_back(txt); - - if(txt.at(0) == '/') - { - //some commands like gosolo don't work when executed from GUI thread - auto threadFunction = [=]() - { - ClientCommandManager commandController; - commandController.processCommand(txt.substr(1), true); - }; - - boost::thread clientCommandThread(threadFunction); - clientCommandThread.detach(); - } - else - LOCPLINT->cb->sendMessage(txt, LOCPLINT->getSelection()); - } - enteredText.clear(); - - auto statusbar = currentStatusBar.lock(); - assert(statusbar); - - if (statusbar) - statusbar->setEnteringMode(false); - - currentStatusBar.reset(); -} - -void CInGameConsole::refreshEnteredText() -{ - auto statusbar = currentStatusBar.lock(); - assert(statusbar); - - if (statusbar) - statusbar->setEnteredText(enteredText); -} - -CAdvMapPanel::CAdvMapPanel(std::shared_ptr bg, Point position) - : CIntObject() - , background(bg) -{ - defActions = 255; - recActions = 255; - pos.x += position.x; - pos.y += position.y; - if (bg) - { - pos.w = bg->width(); - pos.h = bg->height(); - } -} - -void CAdvMapPanel::addChildColorableButton(std::shared_ptr button) -{ - colorableButtons.push_back(button); - addChildToPanel(button, ACTIVATE | DEACTIVATE); -} - -void CAdvMapPanel::setPlayerColor(const PlayerColor & clr) -{ - for(auto & button : colorableButtons) - { - button->setPlayerColor(clr); - } -} - -void CAdvMapPanel::showAll(SDL_Surface * to) -{ - if(background) - background->draw(to, pos.x, pos.y); - - CIntObject::showAll(to); -} - -void CAdvMapPanel::addChildToPanel(std::shared_ptr obj, ui8 actions) -{ - otherObjects.push_back(obj); - obj->recActions |= actions | SHOWALL; - obj->recActions &= ~DISPOSE; - addChild(obj.get(), false); -} - -CAdvMapWorldViewPanel::CAdvMapWorldViewPanel(std::shared_ptr _icons, std::shared_ptr bg, Point position, int spaceBottom, const PlayerColor &color) - : CAdvMapPanel(bg, position), icons(_icons) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - int fillerHeight = bg ? spaceBottom - pos.y - pos.h : 0; - - if(fillerHeight > 0) - { - backgroundFiller = std::make_shared("DIBOXBCK", Rect(0, pos.h, pos.w, fillerHeight)); - } -} - -CAdvMapWorldViewPanel::~CAdvMapWorldViewPanel() = default; - -void CAdvMapWorldViewPanel::recolorIcons(const PlayerColor & color, int indexOffset) -{ - assert(iconsData.size() == currentIcons.size()); - - for(size_t idx = 0; idx < iconsData.size(); idx++) - { - const auto & data = iconsData.at(idx); - currentIcons[idx]->setFrame(data.first + indexOffset); - } -} - -void CAdvMapWorldViewPanel::addChildIcon(std::pair data, int indexOffset) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - iconsData.push_back(data); - currentIcons.push_back(std::make_shared(icons, data.first + indexOffset, 0, data.second.x, data.second.y)); -} diff --git a/client/adventureMap/CList.h b/client/adventureMap/CList.h index 3b4874d9e..6d47188bf 100644 --- a/client/adventureMap/CList.h +++ b/client/adventureMap/CList.h @@ -188,243 +188,3 @@ public: void update(const CGTownInstance * town = nullptr); }; -class CMinimap; - -class CMinimapInstance : public CIntObject -{ - CMinimap * parent; - SDL_Surface * minimap; - int level; - - //get color of selected tile on minimap - const SDL_Color & getTileColor(const int3 & pos); - - void blitTileWithColor(const SDL_Color & color, const int3 & pos, SDL_Surface * to, int x, int y); - - //draw minimap already scaled. - //result is not antialiased. Will result in "missing" pixels on huge maps (>144) - void drawScaled(int level); -public: - CMinimapInstance(CMinimap * parent, int level); - ~CMinimapInstance(); - - void showAll(SDL_Surface * to) override; - void tileToPixels (const int3 & tile, int & x, int & y, int toX = 0, int toY = 0); - void refreshTile(const int3 & pos); -}; - -/// Minimap which is displayed at the right upper corner of adventure map -class CMinimap : public CIntObject -{ -protected: - std::shared_ptr aiShield; //the graphic displayed during AI turn - std::shared_ptr minimap; - int level; - - //to initialize colors - std::map > loadColors(); - - void clickLeft(tribool down, bool previousState) override; - void clickRight(tribool down, bool previousState) override; - void hover (bool on) override; - void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; - - void moveAdvMapSelection(); - -public: - // terrainID -> (normal color, blocked color) - const std::map > colors; - - CMinimap(const Rect & position); - - //should be called to invalidate whole map - different player or level - int3 translateMousePosition(); - void update(); - void setLevel(int level); - void setAIRadar(bool on); - - void showAll(SDL_Surface * to) override; - - void hideTile(const int3 &pos); //puts FoW - void showTile(const int3 &pos); //removes FoW -}; - -/// Info box which shows next week/day information, hold the current date -class CInfoBar : public CIntObject -{ - //all visible information located in one object - for ease of replacing - class CVisibleInfo : public CIntObject - { - public: - void show(SDL_Surface * to) override; - - protected: - std::shared_ptr background; - std::list> forceRefresh; - - CVisibleInfo(); - }; - - class EmptyVisibleInfo : public CVisibleInfo - { - public: - EmptyVisibleInfo(); - }; - - class VisibleHeroInfo : public CVisibleInfo - { - std::shared_ptr heroTooltip; - public: - VisibleHeroInfo(const CGHeroInstance * hero); - }; - - class VisibleTownInfo : public CVisibleInfo - { - std::shared_ptr townTooltip; - public: - VisibleTownInfo(const CGTownInstance * town); - }; - - class VisibleDateInfo : public CVisibleInfo - { - std::shared_ptr animation; - std::shared_ptr label; - - std::string getNewDayName(); - public: - VisibleDateInfo(); - }; - - class VisibleEnemyTurnInfo : public CVisibleInfo - { - std::shared_ptr banner; - std::shared_ptr glass; - std::shared_ptr sand; - public: - VisibleEnemyTurnInfo(PlayerColor player); - }; - - class VisibleGameStatusInfo : public CVisibleInfo - { - std::shared_ptr allyLabel; - std::shared_ptr enemyLabel; - - std::vector> flags; - std::vector> hallIcons; - std::vector> hallLabels; - public: - VisibleGameStatusInfo(); - }; - - class VisibleComponentInfo : public CVisibleInfo - { - std::shared_ptr comp; - std::shared_ptr text; - public: - VisibleComponentInfo(const Component & compToDisplay, std::string message); - }; - - enum EState - { - EMPTY, HERO, TOWN, DATE, GAME, AITURN, COMPONENT - }; - - std::shared_ptr visibleInfo; - EState state; - - //removes all information about current state, deactivates timer (if any) - void reset(); - - void tick() override; - - void clickLeft(tribool down, bool previousState) override; - void clickRight(tribool down, bool previousState) override; - void hover(bool on) override; - - void playNewDaySound(); -public: - CInfoBar(const Rect & pos); - - /// show new day/week animation - void showDate(); - - /// show component for 3 seconds. Used to display picked up resources - void showComponent(const Component & comp, std::string message); - - /// print enemy turn progress - void startEnemyTurn(PlayerColor color); - - /// reset to default view - selected object - void showSelection(); - - /// show hero\town information - void showHeroSelection(const CGHeroInstance * hero); - void showTownSelection(const CGTownInstance * town); - - /// for 3 seconds shows amount of town halls and players status - void showGameStatus(); -}; - -/// simple panel that contains other displayable elements; used to separate groups of controls -class CAdvMapPanel : public CIntObject -{ - std::vector> colorableButtons; - std::vector> otherObjects; - /// the surface passed to this obj will be freed in dtor - std::shared_ptr background; -public: - CAdvMapPanel(std::shared_ptr bg, Point position); - - void addChildToPanel(std::shared_ptr obj, ui8 actions = 0); - void addChildColorableButton(std::shared_ptr button); - /// recolors all buttons to given player color - void setPlayerColor(const PlayerColor & clr); - - void showAll(SDL_Surface * to) override; -}; - -/// specialized version of CAdvMapPanel that handles recolorable def-based pictures for world view info panel -class CAdvMapWorldViewPanel : public CAdvMapPanel -{ - /// data that allows reconstruction of panel info icons - std::vector> iconsData; - /// ptrs to child-pictures constructed from iconsData - std::vector> currentIcons; - /// surface drawn below world view panel on higher resolutions (won't be needed when world view panel is configured for extraResolutions mod) - std::shared_ptr backgroundFiller; - std::shared_ptr icons; -public: - CAdvMapWorldViewPanel(std::shared_ptr _icons, std::shared_ptr bg, Point position, int spaceBottom, const PlayerColor &color); - virtual ~CAdvMapWorldViewPanel(); - - void addChildIcon(std::pair data, int indexOffset); - /// recreates all pictures from given def to recolor them according to current player color - void recolorIcons(const PlayerColor & color, int indexOffset); -}; - -class CInGameConsole : public CIntObject -{ -private: - std::list< std::pair< std::string, uint32_t > > texts; //list - boost::mutex texts_mx; // protects texts - std::vector< std::string > previouslyEntered; //previously entered texts, for up/down arrows to work - int prevEntDisp; //displayed entry from previouslyEntered - if none it's -1 - int defaultTimeout; //timeout for new texts (in ms) - int maxDisplayedTexts; //hiw many texts can be displayed simultaneously - - std::weak_ptr currentStatusBar; -public: - std::string enteredText; - void show(SDL_Surface * to) override; - void print(const std::string &txt); - void keyPressed (const SDL_KeyboardEvent & key) override; //call-in - - void textInputed(const SDL_TextInputEvent & event) override; - void textEdited(const SDL_TextEditingEvent & event) override; - - void startEnteringText(); - void endEnteringText(bool processEnteredText); - void refreshEnteredText(); - - CInGameConsole(); -}; diff --git a/client/adventureMap/CMinimap.cpp b/client/adventureMap/CMinimap.cpp index b2d83416c..f3e5697c0 100644 --- a/client/adventureMap/CMinimap.cpp +++ b/client/adventureMap/CMinimap.cpp @@ -47,317 +47,6 @@ #include #include -CList::CListItem::CListItem(CList * Parent) - : CIntObject(LCLICK | RCLICK | HOVER), - parent(Parent), - selection() -{ - defActions = 255-DISPOSE; -} - -CList::CListItem::~CListItem() -{ -} - -void CList::CListItem::clickRight(tribool down, bool previousState) -{ - if (down == true) - showTooltip(); -} - -void CList::CListItem::clickLeft(tribool down, bool previousState) -{ - if(down == true) - { - //second click on already selected item - if(parent->selected == this->shared_from_this()) - { - open(); - } - else - { - //first click - switch selection - parent->select(this->shared_from_this()); - } - } -} - -void CList::CListItem::hover(bool on) -{ - if (on) - GH.statusbar->write(getHoverText()); - else - GH.statusbar->clear(); -} - -void CList::CListItem::onSelect(bool on) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - selection.reset(); - if(on) - selection = genSelection(); - select(on); - GH.totalRedraw(); -} - -CList::CList(int Size, Point position, std::string btnUp, std::string btnDown, size_t listAmount, int helpUp, int helpDown, CListBox::CreateFunc create) - : CIntObject(0, position), - size(Size), - selected(nullptr) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - scrollUp = std::make_shared(Point(0, 0), btnUp, CGI->generaltexth->zelp[helpUp]); - scrollDown = std::make_shared(Point(0, scrollUp->pos.h + 32*(int)size), btnDown, CGI->generaltexth->zelp[helpDown]); - - listBox = std::make_shared(create, Point(1,scrollUp->pos.h), Point(0, 32), size, listAmount); - - //assign callback only after list was created - scrollUp->addCallback(std::bind(&CListBox::moveToPrev, listBox)); - scrollDown->addCallback(std::bind(&CListBox::moveToNext, listBox)); - - scrollUp->addCallback(std::bind(&CList::update, this)); - scrollDown->addCallback(std::bind(&CList::update, this)); - - update(); -} - -void CList::update() -{ - bool onTop = listBox->getPos() == 0; - bool onBottom = listBox->getPos() + size >= listBox->size(); - - scrollUp->block(onTop); - scrollDown->block(onBottom); -} - -void CList::select(std::shared_ptr which) -{ - if(selected == which) - return; - - if(selected) - selected->onSelect(false); - - selected = which; - if(which) - { - which->onSelect(true); - onSelect(); - } -} - -int CList::getSelectedIndex() -{ - return static_cast(listBox->getIndexOf(selected)); -} - -void CList::selectIndex(int which) -{ - if(which < 0) - { - if(selected) - select(nullptr); - } - else - { - listBox->scrollTo(which); - update(); - select(std::dynamic_pointer_cast(listBox->getItem(which))); - } -} - -void CList::selectNext() -{ - int index = getSelectedIndex() + 1; - if(index >= listBox->size()) - index = 0; - selectIndex(index); -} - -void CList::selectPrev() -{ - int index = getSelectedIndex(); - if(index <= 0) - selectIndex(0); - else - selectIndex(index-1); -} - -CHeroList::CEmptyHeroItem::CEmptyHeroItem() -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - movement = std::make_shared("IMOBIL", 0, 0, 0, 1); - portrait = std::make_shared("HPSXXX", movement->pos.w + 1, 0); - mana = std::make_shared("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1 ); - - pos.w = mana->pos.w + mana->pos.x - pos.x; - pos.h = std::max(std::max(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h); -} - -CHeroList::CHeroItem::CHeroItem(CHeroList *parent, const CGHeroInstance * Hero) - : CListItem(parent), - hero(Hero) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - movement = std::make_shared("IMOBIL", 0, 0, 0, 1); - portrait = std::make_shared("PortraitsSmall", hero->portrait, 0, movement->pos.w + 1); - mana = std::make_shared("IMANA", 0, 0, movement->pos.w + portrait->pos.w + 2, 1); - - pos.w = mana->pos.w + mana->pos.x - pos.x; - pos.h = std::max(std::max(movement->pos.h + 1, mana->pos.h + 1), portrait->pos.h); - - update(); -} - -void CHeroList::CHeroItem::update() -{ - movement->setFrame(std::min(movement->size()-1, hero->movement / 100)); - mana->setFrame(std::min(mana->size()-1, hero->mana / 5)); - redraw(); -} - -std::shared_ptr CHeroList::CHeroItem::genSelection() -{ - return std::make_shared("HPSYYY", movement->pos.w + 1, 0); -} - -void CHeroList::CHeroItem::select(bool on) -{ - if(on && adventureInt->selection != hero) - adventureInt->select(hero); -} - -void CHeroList::CHeroItem::open() -{ - LOCPLINT->openHeroWindow(hero); -} - -void CHeroList::CHeroItem::showTooltip() -{ - CRClickPopup::createAndPush(hero, GH.getCursorPosition()); -} - -std::string CHeroList::CHeroItem::getHoverText() -{ - return boost::str(boost::format(CGI->generaltexth->allTexts[15]) % hero->getNameTranslated() % hero->type->heroClass->getNameTranslated()); -} - -std::shared_ptr CHeroList::createHeroItem(size_t index) -{ - if (LOCPLINT->wanderingHeroes.size() > index) - return std::make_shared(this, LOCPLINT->wanderingHeroes[index]); - return std::make_shared(); -} - -CHeroList::CHeroList(int size, Point position, std::string btnUp, std::string btnDown): - CList(size, position, btnUp, btnDown, LOCPLINT->wanderingHeroes.size(), 303, 304, std::bind(&CHeroList::createHeroItem, this, _1)) -{ -} - -void CHeroList::select(const CGHeroInstance * hero) -{ - selectIndex(vstd::find_pos(LOCPLINT->wanderingHeroes, hero)); -} - -void CHeroList::update(const CGHeroInstance * hero) -{ - //this hero is already present, update its status - for(auto & elem : listBox->getItems()) - { - auto item = std::dynamic_pointer_cast(elem); - if(item && item->hero == hero && vstd::contains(LOCPLINT->wanderingHeroes, hero)) - { - item->update(); - return; - } - } - //simplest solution for now: reset list and restore selection - - listBox->resize(LOCPLINT->wanderingHeroes.size()); - if (adventureInt->selection) - { - auto selectedHero = dynamic_cast(adventureInt->selection); - if (selectedHero) - select(selectedHero); - } - CList::update(); -} - -std::shared_ptr CTownList::createTownItem(size_t index) -{ - if (LOCPLINT->towns.size() > index) - return std::make_shared(this, LOCPLINT->towns[index]); - return std::make_shared("ITPA", 0); -} - -CTownList::CTownItem::CTownItem(CTownList *parent, const CGTownInstance *Town): - CListItem(parent), - town(Town) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - picture = std::make_shared("ITPA", 0); - pos = picture->pos; - update(); -} - -std::shared_ptr CTownList::CTownItem::genSelection() -{ - return std::make_shared("ITPA", 1); -} - -void CTownList::CTownItem::update() -{ - size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN]; - - picture->setFrame(iconIndex + 2); - redraw(); -} - -void CTownList::CTownItem::select(bool on) -{ - if (on && adventureInt->selection != town) - adventureInt->select(town); -} - -void CTownList::CTownItem::open() -{ - LOCPLINT->openTownWindow(town); -} - -void CTownList::CTownItem::showTooltip() -{ - CRClickPopup::createAndPush(town, GH.getCursorPosition()); -} - -std::string CTownList::CTownItem::getHoverText() -{ - return town->getObjectName(); -} - -CTownList::CTownList(int size, Point position, std::string btnUp, std::string btnDown): - CList(size, position, btnUp, btnDown, LOCPLINT->towns.size(), 306, 307, std::bind(&CTownList::createTownItem, this, _1)) -{ -} - -void CTownList::select(const CGTownInstance * town) -{ - selectIndex(vstd::find_pos(LOCPLINT->towns, town)); -} - -void CTownList::update(const CGTownInstance *) -{ - //simplest solution for now: reset list and restore selection - - listBox->resize(LOCPLINT->towns.size()); - if (adventureInt->selection) - { - auto town = dynamic_cast(adventureInt->selection); - if (town) - select(town); - } - CList::update(); -} - const SDL_Color & CMinimapInstance::getTileColor(const int3 & pos) { const TerrainTile * tile = LOCPLINT->cb->getTile(pos, false); @@ -646,606 +335,3 @@ void CMinimap::showTile(const int3 &pos) minimap->refreshTile(pos); } -CInfoBar::CVisibleInfo::CVisibleInfo() - : CIntObject(0, Point(8, 12)) -{ -} - -void CInfoBar::CVisibleInfo::show(SDL_Surface * to) -{ - CIntObject::show(to); - for(auto object : forceRefresh) - object->showAll(to); -} - -CInfoBar::EmptyVisibleInfo::EmptyVisibleInfo() -{ -} - -CInfoBar::VisibleHeroInfo::VisibleHeroInfo(const CGHeroInstance * hero) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared("ADSTATHR"); - heroTooltip = std::make_shared(Point(0,0), hero); -} - -CInfoBar::VisibleTownInfo::VisibleTownInfo(const CGTownInstance * town) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared("ADSTATCS"); - townTooltip = std::make_shared(Point(0,0), town); -} - -CInfoBar::VisibleDateInfo::VisibleDateInfo() -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - - animation = std::make_shared(1, 0, getNewDayName(), CShowableAnim::PLAY_ONCE, 180);// H3 uses around 175-180 ms per frame - - std::string labelText; - if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) == 1 && LOCPLINT->cb->getDate(Date::DAY) != 1) // monday of any week but first - show new week info - labelText = CGI->generaltexth->allTexts[63] + " " + boost::lexical_cast(LOCPLINT->cb->getDate(Date::WEEK)); - else - labelText = CGI->generaltexth->allTexts[64] + " " + boost::lexical_cast(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK)); - - label = std::make_shared(95, 31, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, labelText); - - forceRefresh.push_back(label); -} - -std::string CInfoBar::VisibleDateInfo::getNewDayName() -{ - if(LOCPLINT->cb->getDate(Date::DAY) == 1) - return "NEWDAY"; - - if(LOCPLINT->cb->getDate(Date::DAY) != 1) - return "NEWDAY"; - - switch(LOCPLINT->cb->getDate(Date::WEEK)) - { - case 1: - return "NEWWEEK1"; - case 2: - return "NEWWEEK2"; - case 3: - return "NEWWEEK3"; - case 4: - return "NEWWEEK4"; - default: - return ""; - } -} - -CInfoBar::VisibleEnemyTurnInfo::VisibleEnemyTurnInfo(PlayerColor player) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared("ADSTATNX"); - banner = std::make_shared("CREST58", player.getNum(), 0, 20, 51); - sand = std::make_shared(99, 51, "HOURSAND", 0, 100); // H3 uses around 100 ms per frame - glass = std::make_shared(99, 51, "HOURGLAS", CShowableAnim::PLAY_ONCE, 1000); // H3 scales this nicely for AI turn duration, don't have anything like that in vcmi -} - -CInfoBar::VisibleGameStatusInfo::VisibleGameStatusInfo() -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - //get amount of halls of each level - std::vector halls(4, 0); - for(auto town : LOCPLINT->towns) - { - int hallLevel = town->hallLevel(); - //negative value means no village hall, unlikely but possible - if(hallLevel >= 0) - halls.at(hallLevel)++; - } - - std::vector allies, enemies; - - //generate list of allies and enemies - for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++) - { - if(LOCPLINT->cb->getPlayerStatus(PlayerColor(i), false) == EPlayerStatus::INGAME) - { - if(LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, PlayerColor(i)) != PlayerRelations::ENEMIES) - allies.push_back(PlayerColor(i)); - else - enemies.push_back(PlayerColor(i)); - } - } - - //generate widgets - background = std::make_shared("ADSTATIN"); - allyLabel = std::make_shared(10, 106, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[390] + ":"); - enemyLabel = std::make_shared(10, 136, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[391] + ":"); - - int posx = allyLabel->pos.w + allyLabel->pos.x - pos.x + 4; - for(PlayerColor & player : allies) - { - auto image = std::make_shared("ITGFLAGS", player.getNum(), 0, posx, 102); - posx += image->pos.w; - flags.push_back(image); - } - - posx = enemyLabel->pos.w + enemyLabel->pos.x - pos.x + 4; - for(PlayerColor & player : enemies) - { - auto image = std::make_shared("ITGFLAGS", player.getNum(), 0, posx, 132); - posx += image->pos.w; - flags.push_back(image); - } - - for(size_t i=0; i("itmtl", i, 0, 6 + 42 * (int)i , 11)); - if(halls[i]) - hallLabels.push_back(std::make_shared( 26 + 42 * (int)i, 64, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, boost::lexical_cast(halls[i]))); - } -} - -CInfoBar::VisibleComponentInfo::VisibleComponentInfo(const Component & compToDisplay, std::string message) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - - background = std::make_shared("ADSTATOT", 1, 0); - - comp = std::make_shared(compToDisplay); - comp->moveTo(Point(pos.x+47, pos.y+50)); - - text = std::make_shared(message, Rect(10, 4, 160, 50), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); -} - -void CInfoBar::playNewDaySound() -{ - if(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK) != 1) // not first day of the week - CCS->soundh->playSound(soundBase::newDay); - else if(LOCPLINT->cb->getDate(Date::WEEK) != 1) // not first week in month - CCS->soundh->playSound(soundBase::newWeek); - else if(LOCPLINT->cb->getDate(Date::MONTH) != 1) // not first month - CCS->soundh->playSound(soundBase::newMonth); - else - CCS->soundh->playSound(soundBase::newDay); -} - -void CInfoBar::reset() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = EMPTY; - visibleInfo = std::make_shared(); -} - -void CInfoBar::showSelection() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - if(adventureInt->selection) - { - if(auto hero = dynamic_cast(adventureInt->selection)) - { - showHeroSelection(hero); - return; - } - else if(auto town = dynamic_cast(adventureInt->selection)) - { - showTownSelection(town); - return; - } - } - showGameStatus();//FIXME: may be incorrect but shouldn't happen in general -} - -void CInfoBar::tick() -{ - removeUsedEvents(TIME); - if(GH.topInt() == adventureInt) - showSelection(); -} - -void CInfoBar::clickLeft(tribool down, bool previousState) -{ - if(down) - { - if(state == HERO || state == TOWN) - showGameStatus(); - else if(state == GAME) - showDate(); - else - showSelection(); - } -} - -void CInfoBar::clickRight(tribool down, bool previousState) -{ - adventureInt->handleRightClick(CGI->generaltexth->allTexts[109], down); -} - -void CInfoBar::hover(bool on) -{ - if(on) - GH.statusbar->write(CGI->generaltexth->zelp[292].first); - else - GH.statusbar->clear(); -} - -CInfoBar::CInfoBar(const Rect & position) - : CIntObject(LCLICK | RCLICK | HOVER, position.topLeft()), - state(EMPTY) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - pos.w = position.w; - pos.h = position.h; - reset(); -} - -void CInfoBar::showDate() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - playNewDaySound(); - state = DATE; - visibleInfo = std::make_shared(); - setTimer(3000); // confirmed to match H3 - redraw(); -} - -void CInfoBar::showComponent(const Component & comp, std::string message) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = COMPONENT; - visibleInfo = std::make_shared(comp, message); - setTimer(3000); - redraw(); -} - -void CInfoBar::startEnemyTurn(PlayerColor color) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = AITURN; - visibleInfo = std::make_shared(color); - redraw(); -} - -void CInfoBar::showHeroSelection(const CGHeroInstance * hero) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - if(!hero) - { - reset(); - } - else - { - state = HERO; - visibleInfo = std::make_shared(hero); - } - redraw(); -} - -void CInfoBar::showTownSelection(const CGTownInstance * town) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - if(!town) - { - reset(); - } - else - { - state = TOWN; - visibleInfo = std::make_shared(town); - } - redraw(); -} - -void CInfoBar::showGameStatus() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - state = GAME; - visibleInfo = std::make_shared(); - setTimer(3000); - redraw(); -} - -CInGameConsole::CInGameConsole() - : CIntObject(KEYBOARD | TEXTINPUT), - prevEntDisp(-1), - defaultTimeout(10000), - maxDisplayedTexts(10) -{ -} - -void CInGameConsole::show(SDL_Surface * to) -{ - int number = 0; - - std::vector >::iterator> toDel; - - boost::unique_lock lock(texts_mx); - for(auto it = texts.begin(); it != texts.end(); ++it, ++number) - { - Point leftBottomCorner(0, pos.h); - - graphics->fonts[FONT_MEDIUM]->renderTextLeft(to, it->first, Colors::GREEN, - Point(leftBottomCorner.x + 50, leftBottomCorner.y - (int)texts.size() * 20 - 80 + number*20)); - - if((int)(SDL_GetTicks() - it->second) > defaultTimeout) - { - toDel.push_back(it); - } - } - - for(auto & elem : toDel) - { - texts.erase(elem); - } -} - -void CInGameConsole::print(const std::string &txt) -{ - boost::unique_lock lock(texts_mx); - int lineLen = conf.go()->ac.outputLineLength; - - if(txt.size() < lineLen) - { - texts.push_back(std::make_pair(txt, SDL_GetTicks())); - if(texts.size() > maxDisplayedTexts) - { - texts.pop_front(); - } - } - else - { - assert(lineLen); - for(int g=0; g maxDisplayedTexts) - { - texts.pop_front(); - } - } - } -} - -void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key) -{ - if(key.type != SDL_KEYDOWN) return; - - if(!captureAllKeys && key.keysym.sym != SDLK_TAB) return; //because user is not entering any text - - switch(key.keysym.sym) - { - case SDLK_TAB: - case SDLK_ESCAPE: - { - if(captureAllKeys) - { - endEnteringText(false); - } - else if(SDLK_TAB == key.keysym.sym) - { - startEnteringText(); - } - break; - } - case SDLK_RETURN: //enter key - { - if(!enteredText.empty() && captureAllKeys) - { - bool anyTextExceptCaret = enteredText.size() > 1; - endEnteringText(anyTextExceptCaret); - - if(anyTextExceptCaret) - { - CCS->soundh->playSound("CHAT"); - } - } - break; - } - case SDLK_BACKSPACE: - { - if(enteredText.size() > 1) - { - Unicode::trimRight(enteredText,2); - enteredText += '_'; - refreshEnteredText(); - } - break; - } - case SDLK_UP: //up arrow - { - if(previouslyEntered.size() == 0) - break; - - if(prevEntDisp == -1) - { - prevEntDisp = static_cast(previouslyEntered.size() - 1); - enteredText = previouslyEntered[prevEntDisp] + "_"; - refreshEnteredText(); - } - else if( prevEntDisp > 0) - { - --prevEntDisp; - enteredText = previouslyEntered[prevEntDisp] + "_"; - refreshEnteredText(); - } - break; - } - case SDLK_DOWN: //down arrow - { - if(prevEntDisp != -1 && prevEntDisp+1 < previouslyEntered.size()) - { - ++prevEntDisp; - enteredText = previouslyEntered[prevEntDisp] + "_"; - refreshEnteredText(); - } - else if(prevEntDisp+1 == previouslyEntered.size()) //useful feature - { - prevEntDisp = -1; - enteredText = "_"; - refreshEnteredText(); - } - break; - } - default: - { - break; - } - } -} - -void CInGameConsole::textInputed(const SDL_TextInputEvent & event) -{ - if(!captureAllKeys || enteredText.size() == 0) - return; - enteredText.resize(enteredText.size()-1); - - enteredText += event.text; - enteredText += "_"; - - refreshEnteredText(); -} - -void CInGameConsole::textEdited(const SDL_TextEditingEvent & event) -{ - //do nothing here -} - -void CInGameConsole::startEnteringText() -{ - if (!active) - return; - - if (captureAllKeys) - return; - - assert(GH.statusbar); - assert(currentStatusBar.expired());//effectively, nullptr check - - currentStatusBar = GH.statusbar; - - captureAllKeys = true; - enteredText = "_"; - - GH.statusbar->setEnteringMode(true); - GH.statusbar->setEnteredText(enteredText); -} - -void CInGameConsole::endEnteringText(bool processEnteredText) -{ - captureAllKeys = false; - prevEntDisp = -1; - if(processEnteredText) - { - std::string txt = enteredText.substr(0, enteredText.size()-1); - previouslyEntered.push_back(txt); - - if(txt.at(0) == '/') - { - //some commands like gosolo don't work when executed from GUI thread - auto threadFunction = [=]() - { - ClientCommandManager commandController; - commandController.processCommand(txt.substr(1), true); - }; - - boost::thread clientCommandThread(threadFunction); - clientCommandThread.detach(); - } - else - LOCPLINT->cb->sendMessage(txt, LOCPLINT->getSelection()); - } - enteredText.clear(); - - auto statusbar = currentStatusBar.lock(); - assert(statusbar); - - if (statusbar) - statusbar->setEnteringMode(false); - - currentStatusBar.reset(); -} - -void CInGameConsole::refreshEnteredText() -{ - auto statusbar = currentStatusBar.lock(); - assert(statusbar); - - if (statusbar) - statusbar->setEnteredText(enteredText); -} - -CAdvMapPanel::CAdvMapPanel(std::shared_ptr bg, Point position) - : CIntObject() - , background(bg) -{ - defActions = 255; - recActions = 255; - pos.x += position.x; - pos.y += position.y; - if (bg) - { - pos.w = bg->width(); - pos.h = bg->height(); - } -} - -void CAdvMapPanel::addChildColorableButton(std::shared_ptr button) -{ - colorableButtons.push_back(button); - addChildToPanel(button, ACTIVATE | DEACTIVATE); -} - -void CAdvMapPanel::setPlayerColor(const PlayerColor & clr) -{ - for(auto & button : colorableButtons) - { - button->setPlayerColor(clr); - } -} - -void CAdvMapPanel::showAll(SDL_Surface * to) -{ - if(background) - background->draw(to, pos.x, pos.y); - - CIntObject::showAll(to); -} - -void CAdvMapPanel::addChildToPanel(std::shared_ptr obj, ui8 actions) -{ - otherObjects.push_back(obj); - obj->recActions |= actions | SHOWALL; - obj->recActions &= ~DISPOSE; - addChild(obj.get(), false); -} - -CAdvMapWorldViewPanel::CAdvMapWorldViewPanel(std::shared_ptr _icons, std::shared_ptr bg, Point position, int spaceBottom, const PlayerColor &color) - : CAdvMapPanel(bg, position), icons(_icons) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - int fillerHeight = bg ? spaceBottom - pos.y - pos.h : 0; - - if(fillerHeight > 0) - { - backgroundFiller = std::make_shared("DIBOXBCK", Rect(0, pos.h, pos.w, fillerHeight)); - } -} - -CAdvMapWorldViewPanel::~CAdvMapWorldViewPanel() = default; - -void CAdvMapWorldViewPanel::recolorIcons(const PlayerColor & color, int indexOffset) -{ - assert(iconsData.size() == currentIcons.size()); - - for(size_t idx = 0; idx < iconsData.size(); idx++) - { - const auto & data = iconsData.at(idx); - currentIcons[idx]->setFrame(data.first + indexOffset); - } -} - -void CAdvMapWorldViewPanel::addChildIcon(std::pair data, int indexOffset) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - iconsData.push_back(data); - currentIcons.push_back(std::make_shared(icons, data.first + indexOffset, 0, data.second.x, data.second.y)); -} diff --git a/client/adventureMap/CMinimap.h b/client/adventureMap/CMinimap.h index 3b4874d9e..a772ae5e3 100644 --- a/client/adventureMap/CMinimap.h +++ b/client/adventureMap/CMinimap.h @@ -37,157 +37,6 @@ class CTownTooltip; class CTextBox; class IImage; -/// Base UI Element for hero\town lists -class CList : public CIntObject -{ -protected: - class CListItem : public CIntObject, public std::enable_shared_from_this - { - CList * parent; - std::shared_ptr selection; - public: - CListItem(CList * parent); - ~CListItem(); - - void clickRight(tribool down, bool previousState) override; - void clickLeft(tribool down, bool previousState) override; - void hover(bool on) override; - void onSelect(bool on); - - /// create object with selection rectangle - virtual std::shared_ptr genSelection()=0; - /// reaction on item selection (e.g. enable selection border) - /// NOTE: item may be deleted in selected state - virtual void select(bool on)=0; - /// open item (town or hero screen) - virtual void open()=0; - /// show right-click tooltip - virtual void showTooltip()=0; - /// get hover text for status bar - virtual std::string getHoverText()=0; - }; - - std::shared_ptr listBox; - const size_t size; - - /** - * @brief CList - protected constructor - * @param size - maximal amount of visible at once items - * @param position - cordinates - * @param btnUp - path to image to use as top button - * @param btnDown - path to image to use as bottom button - * @param listAmount - amount of items in the list - * @param helpUp - index in zelp.txt for button help tooltip - * @param helpDown - index in zelp.txt for button help tooltip - * @param create - function for creating items in listbox - * @param destroy - function for deleting items in listbox - */ - CList(int size, Point position, std::string btnUp, std::string btnDown, size_t listAmount, int helpUp, int helpDown, CListBox::CreateFunc create); - - //for selection\deselection - std::shared_ptr selected; - void select(std::shared_ptr which); - friend class CListItem; - - std::shared_ptr scrollUp; - std::shared_ptr scrollDown; - - /// should be called when list is invalidated - void update(); - -public: - /// functions that will be called when selection changes - CFunctionList onSelect; - - /// return index of currently selected element - int getSelectedIndex(); - - /// set of methods to switch selection - void selectIndex(int which); - void selectNext(); - void selectPrev(); -}; - -/// List of heroes which is shown at the right of the adventure map screen -class CHeroList : public CList -{ - /// Empty hero item used as placeholder for unused entries in list - class CEmptyHeroItem : public CIntObject - { - std::shared_ptr movement; - std::shared_ptr mana; - std::shared_ptr portrait; - public: - CEmptyHeroItem(); - }; - - class CHeroItem : public CListItem - { - std::shared_ptr movement; - std::shared_ptr mana; - std::shared_ptr portrait; - public: - const CGHeroInstance * const hero; - - CHeroItem(CHeroList * parent, const CGHeroInstance * hero); - - std::shared_ptr genSelection() override; - void update(); - void select(bool on) override; - void open() override; - void showTooltip() override; - std::string getHoverText() override; - }; - - std::shared_ptr createHeroItem(size_t index); -public: - /** - * @brief CHeroList - * @param size, position, btnUp, btnDown @see CList::CList - */ - CHeroList(int size, Point position, std::string btnUp, std::string btnDown); - - /// Select specific hero and scroll if needed - void select(const CGHeroInstance * hero = nullptr); - - /// Update hero. Will add or remove it from the list if needed - void update(const CGHeroInstance * hero = nullptr); -}; - -/// List of towns which is shown at the right of the adventure map screen or in the town screen -class CTownList : public CList -{ - class CTownItem : public CListItem - { - std::shared_ptr picture; - public: - const CGTownInstance * const town; - - CTownItem(CTownList *parent, const CGTownInstance * town); - - std::shared_ptr genSelection() override; - void update(); - void select(bool on) override; - void open() override; - void showTooltip() override; - std::string getHoverText() override; - }; - - std::shared_ptr createTownItem(size_t index); -public: - /** - * @brief CTownList - * @param size, position, btnUp, btnDown @see CList::CList - */ - CTownList(int size, Point position, std::string btnUp, std::string btnDown); - - /// Select specific town and scroll if needed - void select(const CGTownInstance * town = nullptr); - - /// Update town. Will add or remove it from the list if needed - void update(const CGTownInstance * town = nullptr); -}; - class CMinimap; class CMinimapInstance : public CIntObject @@ -249,182 +98,3 @@ public: void showTile(const int3 &pos); //removes FoW }; -/// Info box which shows next week/day information, hold the current date -class CInfoBar : public CIntObject -{ - //all visible information located in one object - for ease of replacing - class CVisibleInfo : public CIntObject - { - public: - void show(SDL_Surface * to) override; - - protected: - std::shared_ptr background; - std::list> forceRefresh; - - CVisibleInfo(); - }; - - class EmptyVisibleInfo : public CVisibleInfo - { - public: - EmptyVisibleInfo(); - }; - - class VisibleHeroInfo : public CVisibleInfo - { - std::shared_ptr heroTooltip; - public: - VisibleHeroInfo(const CGHeroInstance * hero); - }; - - class VisibleTownInfo : public CVisibleInfo - { - std::shared_ptr townTooltip; - public: - VisibleTownInfo(const CGTownInstance * town); - }; - - class VisibleDateInfo : public CVisibleInfo - { - std::shared_ptr animation; - std::shared_ptr label; - - std::string getNewDayName(); - public: - VisibleDateInfo(); - }; - - class VisibleEnemyTurnInfo : public CVisibleInfo - { - std::shared_ptr banner; - std::shared_ptr glass; - std::shared_ptr sand; - public: - VisibleEnemyTurnInfo(PlayerColor player); - }; - - class VisibleGameStatusInfo : public CVisibleInfo - { - std::shared_ptr allyLabel; - std::shared_ptr enemyLabel; - - std::vector> flags; - std::vector> hallIcons; - std::vector> hallLabels; - public: - VisibleGameStatusInfo(); - }; - - class VisibleComponentInfo : public CVisibleInfo - { - std::shared_ptr comp; - std::shared_ptr text; - public: - VisibleComponentInfo(const Component & compToDisplay, std::string message); - }; - - enum EState - { - EMPTY, HERO, TOWN, DATE, GAME, AITURN, COMPONENT - }; - - std::shared_ptr visibleInfo; - EState state; - - //removes all information about current state, deactivates timer (if any) - void reset(); - - void tick() override; - - void clickLeft(tribool down, bool previousState) override; - void clickRight(tribool down, bool previousState) override; - void hover(bool on) override; - - void playNewDaySound(); -public: - CInfoBar(const Rect & pos); - - /// show new day/week animation - void showDate(); - - /// show component for 3 seconds. Used to display picked up resources - void showComponent(const Component & comp, std::string message); - - /// print enemy turn progress - void startEnemyTurn(PlayerColor color); - - /// reset to default view - selected object - void showSelection(); - - /// show hero\town information - void showHeroSelection(const CGHeroInstance * hero); - void showTownSelection(const CGTownInstance * town); - - /// for 3 seconds shows amount of town halls and players status - void showGameStatus(); -}; - -/// simple panel that contains other displayable elements; used to separate groups of controls -class CAdvMapPanel : public CIntObject -{ - std::vector> colorableButtons; - std::vector> otherObjects; - /// the surface passed to this obj will be freed in dtor - std::shared_ptr background; -public: - CAdvMapPanel(std::shared_ptr bg, Point position); - - void addChildToPanel(std::shared_ptr obj, ui8 actions = 0); - void addChildColorableButton(std::shared_ptr button); - /// recolors all buttons to given player color - void setPlayerColor(const PlayerColor & clr); - - void showAll(SDL_Surface * to) override; -}; - -/// specialized version of CAdvMapPanel that handles recolorable def-based pictures for world view info panel -class CAdvMapWorldViewPanel : public CAdvMapPanel -{ - /// data that allows reconstruction of panel info icons - std::vector> iconsData; - /// ptrs to child-pictures constructed from iconsData - std::vector> currentIcons; - /// surface drawn below world view panel on higher resolutions (won't be needed when world view panel is configured for extraResolutions mod) - std::shared_ptr backgroundFiller; - std::shared_ptr icons; -public: - CAdvMapWorldViewPanel(std::shared_ptr _icons, std::shared_ptr bg, Point position, int spaceBottom, const PlayerColor &color); - virtual ~CAdvMapWorldViewPanel(); - - void addChildIcon(std::pair data, int indexOffset); - /// recreates all pictures from given def to recolor them according to current player color - void recolorIcons(const PlayerColor & color, int indexOffset); -}; - -class CInGameConsole : public CIntObject -{ -private: - std::list< std::pair< std::string, uint32_t > > texts; //list - boost::mutex texts_mx; // protects texts - std::vector< std::string > previouslyEntered; //previously entered texts, for up/down arrows to work - int prevEntDisp; //displayed entry from previouslyEntered - if none it's -1 - int defaultTimeout; //timeout for new texts (in ms) - int maxDisplayedTexts; //hiw many texts can be displayed simultaneously - - std::weak_ptr currentStatusBar; -public: - std::string enteredText; - void show(SDL_Surface * to) override; - void print(const std::string &txt); - void keyPressed (const SDL_KeyboardEvent & key) override; //call-in - - void textInputed(const SDL_TextInputEvent & event) override; - void textEdited(const SDL_TextEditingEvent & event) override; - - void startEnteringText(); - void endEnteringText(bool processEnteredText); - void refreshEnteredText(); - - CInGameConsole(); -}; From 5e0c90dc8af2bc602e867983cdd2c19141c0a9bd Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:13:07 +0200 Subject: [PATCH 51/79] Moved CTerrainRect into a separate file --- client/adventureMap/{CAdvmapInterface.cpp => CTerrainRect.cpp} | 0 client/adventureMap/{CAdvmapInterface.h => CTerrainRect.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/adventureMap/{CAdvmapInterface.cpp => CTerrainRect.cpp} (100%) rename client/adventureMap/{CAdvmapInterface.h => CTerrainRect.h} (100%) diff --git a/client/adventureMap/CAdvmapInterface.cpp b/client/adventureMap/CTerrainRect.cpp similarity index 100% rename from client/adventureMap/CAdvmapInterface.cpp rename to client/adventureMap/CTerrainRect.cpp diff --git a/client/adventureMap/CAdvmapInterface.h b/client/adventureMap/CTerrainRect.h similarity index 100% rename from client/adventureMap/CAdvmapInterface.h rename to client/adventureMap/CTerrainRect.h From 1078c4acb633e2b0dc8e3a983628c83ea6a4ce02 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:14:52 +0200 Subject: [PATCH 52/79] Restore CAdvMapInterface --- client/adventureMap/CAdvmapInterface.cpp | 2021 ++++++++++++++++++++++ client/adventureMap/CAdvmapInterface.h | 276 +++ 2 files changed, 2297 insertions(+) create mode 100644 client/adventureMap/CAdvmapInterface.cpp create mode 100644 client/adventureMap/CAdvmapInterface.h diff --git a/client/adventureMap/CAdvmapInterface.cpp b/client/adventureMap/CAdvmapInterface.cpp new file mode 100644 index 000000000..d0529f744 --- /dev/null +++ b/client/adventureMap/CAdvmapInterface.cpp @@ -0,0 +1,2021 @@ +/* + * CAdvmapInterface.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#include "StdInc.h" +#include "CAdvmapInterface.h" + +#include "CCastleInterface.h" +#include "CHeroWindow.h" +#include "CKingdomInterface.h" +#include "CSpellWindow.h" +#include "CTradeWindow.h" +#include "GUIClasses.h" +#include "InfoWindows.h" + +#include "../CBitmapHandler.h" +#include "../CGameInfo.h" +#include "../CMessage.h" +#include "../CMusicHandler.h" +#include "../CPlayerInterface.h" +#include "../mainmenu/CMainMenu.h" +#include "../lobby/CSelectionBase.h" +#include "../lobby/CCampaignInfoScreen.h" +#include "../lobby/CSavingScreen.h" +#include "../lobby/CScenarioInfoScreen.h" +#include "../Graphics.h" +#include "../mapHandler.h" + +#include "../gui/CAnimation.h" +#include "../gui/CursorHandler.h" +#include "../gui/CGuiHandler.h" +#include "../gui/SDL_Extensions.h" +#include "../widgets/MiscWidgets.h" + +#include "../../CCallback.h" + +#include "../../lib/CConfigHandler.h" +#include "../../lib/CGameState.h" +#include "../../lib/CGeneralTextHandler.h" +#include "../../lib/CHeroHandler.h" +#include "../../lib/CSoundBase.h" +#include "../../lib/spells/CSpellHandler.h" +#include "../../lib/CTownHandler.h" +#include "../../lib/JsonNode.h" +#include "../../lib/mapObjects/CGHeroInstance.h" +#include "../../lib/mapping/CMap.h" +#include "../../lib/UnlockGuard.h" +#include "../../lib/VCMI_Lib.h" +#include "../../lib/StartInfo.h" +#include "../../lib/mapping/CMapInfo.h" +#include "../../lib/TerrainHandler.h" + +#include +#include + +#define ADVOPT (conf.go()->ac) +using namespace CSDL_Ext; + +std::shared_ptr adventureInt; + +static void setScrollingCursor(ui8 direction) +{ + if(direction & CAdvMapInt::RIGHT) + { + if(direction & CAdvMapInt::UP) + CCS->curh->set(Cursor::Map::SCROLL_NORTHEAST); + else if(direction & CAdvMapInt::DOWN) + CCS->curh->set(Cursor::Map::SCROLL_SOUTHEAST); + else + CCS->curh->set(Cursor::Map::SCROLL_EAST); + } + else if(direction & CAdvMapInt::LEFT) + { + if(direction & CAdvMapInt::UP) + CCS->curh->set(Cursor::Map::SCROLL_NORTHWEST); + else if(direction & CAdvMapInt::DOWN) + CCS->curh->set(Cursor::Map::SCROLL_SOUTHWEST); + else + CCS->curh->set(Cursor::Map::SCROLL_WEST); + } + else if(direction & CAdvMapInt::UP) + CCS->curh->set(Cursor::Map::SCROLL_NORTH); + else if(direction & CAdvMapInt::DOWN) + CCS->curh->set(Cursor::Map::SCROLL_SOUTH); +} + +CTerrainRect::CTerrainRect() + : fadeSurface(nullptr), + lastRedrawStatus(EMapAnimRedrawStatus::OK), + fadeAnim(std::make_shared()), + curHoveredTile(-1,-1,-1), + currentPath(nullptr) +{ + tilesw=(ADVOPT.advmapW+31)/32; + tilesh=(ADVOPT.advmapH+31)/32; + pos.x=ADVOPT.advmapX; + pos.y=ADVOPT.advmapY; + pos.w=ADVOPT.advmapW; + pos.h=ADVOPT.advmapH; + moveX = moveY = 0; + addUsedEvents(LCLICK | RCLICK | MCLICK | HOVER | MOVE); +} + +CTerrainRect::~CTerrainRect() +{ + if(fadeSurface) + SDL_FreeSurface(fadeSurface); +} + +void CTerrainRect::deactivate() +{ + CIntObject::deactivate(); + curHoveredTile = int3(-1,-1,-1); //we lost info about hovered tile when disabling +} + +void CTerrainRect::clickLeft(tribool down, bool previousState) +{ + if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) + return; + if(indeterminate(down)) + return; + +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + if(adventureInt->swipeEnabled) + { + if(handleSwipeStateChange((bool)down == true)) + { + return; // if swipe is enabled, we don't process "down" events and wait for "up" (to make sure this wasn't a swiping gesture) + } + } + else + { +#endif + if(down == false) + return; +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + } +#endif + int3 mp = whichTileIsIt(); + if(mp.x < 0 || mp.y < 0 || mp.x >= LOCPLINT->cb->getMapSize().x || mp.y >= LOCPLINT->cb->getMapSize().y) + return; + + adventureInt->tileLClicked(mp); +} + +void CTerrainRect::clickRight(tribool down, bool previousState) +{ +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + if(adventureInt->swipeEnabled && isSwiping) + return; +#endif + if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) + return; + int3 mp = whichTileIsIt(); + + if(CGI->mh->map->isInTheMap(mp) && down) + adventureInt->tileRClicked(mp); +} + +void CTerrainRect::clickMiddle(tribool down, bool previousState) +{ + handleSwipeStateChange((bool)down == true); +} + +void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent) +{ + handleHover(sEvent); + + if(!adventureInt->swipeEnabled) + return; + + handleSwipeMove(sEvent); +} + +void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent) +{ +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + if(sEvent.state == 0 || GH.multifinger) // any "button" is enough on mobile +#else + if((sEvent.state & SDL_BUTTON_MMASK) == 0) // swipe only works with middle mouse on other platforms +#endif + { + return; + } + + if(!isSwiping) + { + // try to distinguish if this touch was meant to be a swipe or just fat-fingering press + if(abs(sEvent.x - swipeInitialRealPos.x) > SwipeTouchSlop || + abs(sEvent.y - swipeInitialRealPos.y) > SwipeTouchSlop) + { + isSwiping = true; + } + } + + if(isSwiping) + { + adventureInt->swipeTargetPosition.x = + swipeInitialMapPos.x + static_cast(swipeInitialRealPos.x - sEvent.x) / 32; + adventureInt->swipeTargetPosition.y = + swipeInitialMapPos.y + static_cast(swipeInitialRealPos.y - sEvent.y) / 32; + adventureInt->swipeMovementRequested = true; + } +} + +bool CTerrainRect::handleSwipeStateChange(bool btnPressed) +{ + if(btnPressed) + { + swipeInitialRealPos = int3(GH.getCursorPosition().x, GH.getCursorPosition().y, 0); + swipeInitialMapPos = int3(adventureInt->position); + return true; + } + else if(isSwiping) // only accept this touch if it wasn't a swipe + { + isSwiping = false; + return true; + } + return false; +} + +void CTerrainRect::handleHover(const SDL_MouseMotionEvent &sEvent) +{ + int3 tHovered = whichTileIsIt(sEvent.x, sEvent.y); + int3 pom = adventureInt->verifyPos(tHovered); + + if(tHovered != pom) //tile outside the map + { + CCS->curh->set(Cursor::Map::POINTER); + return; + } + + if (pom != curHoveredTile) + { + curHoveredTile = pom; + adventureInt->tileHovered(pom); + } +} + +void CTerrainRect::hover(bool on) +{ + if (!on) + { + adventureInt->statusbar->clear(); + CCS->curh->set(Cursor::Map::POINTER); + } + //Hoverable::hover(on); +} +void CTerrainRect::showPath(const Rect & extRect, SDL_Surface * to) +{ + const static int pns[9][9] = { + {16, 17, 18, 7, -1, 19, 6, 5, -1}, + { 8, 9, 18, 7, -1, 19, 6, -1, 20}, + { 8, 1, 10, 7, -1, 19, -1, 21, 20}, + {24, 17, 18, 15, -1, -1, 6, 5, 4}, + {-1, -1, -1, -1, -1, -1, -1, -1, -1}, + { 8, 1, 2, -1, -1, 11, 22, 21, 20}, + {24, 17, -1, 23, -1, 3, 14, 5, 4}, + {24, -1, 2, 23, -1, 3, 22, 13, 4}, + {-1, 1, 2, 23, -1, 3, 22, 21, 12} + }; //table of magic values TODO meaning, change variable name + + for (int i = 0; i < -1 + (int)currentPath->nodes.size(); ++i) + { + const int3 &curPos = currentPath->nodes[i].coord, &nextPos = currentPath->nodes[i+1].coord; + if(curPos.z != adventureInt->position.z) + continue; + + int pn=-1;//number of picture + if (i==0) //last tile + { + int x = 32*(curPos.x-adventureInt->position.x)+CGI->mh->offsetX + pos.x, + y = 32*(curPos.y-adventureInt->position.y)+CGI->mh->offsetY + pos.y; + if (x<0 || y<0 || x>pos.w || y>pos.h) + continue; + pn=0; + } + else + { + const int3 &prevPos = currentPath->nodes[i-1].coord; + std::vector & cv = currentPath->nodes; + + /* Vector directions + * 0 1 2 + * \ | / + * 3 - 4 - 5 + * / | \ + * 6 7 8 + *For example: + * | + * |__\ + * / + * is id1=7, id2=5 (pns[7][5]) + */ + bool pathContinuous = curPos.areNeighbours(nextPos) && curPos.areNeighbours(prevPos); + if(pathContinuous && cv[i].action != CGPathNode::EMBARK && cv[i].action != CGPathNode::DISEMBARK) + { + int id1=(curPos.x-nextPos.x+1)+3*(curPos.y-nextPos.y+1); //Direction of entering vector + int id2=(cv[i-1].coord.x-curPos.x+1)+3*(cv[i-1].coord.y-curPos.y+1); //Direction of exiting vector + pn=pns[id1][id2]; + } + else //path discontinuity or sea/land transition (eg. when moving through Subterranean Gate or Boat) + { + pn = 0; + } + } + if (currentPath->nodes[i].turns) + pn+=25; + if (pn>=0) + { + const auto arrow = graphics->heroMoveArrows->getImage(pn); + + int x = 32*(curPos.x-adventureInt->position.x)+CGI->mh->offsetX + pos.x, + y = 32*(curPos.y-adventureInt->position.y)+CGI->mh->offsetY + pos.y; + if (x< -32 || y< -32 || x>pos.w || y>pos.h) + continue; + int hvx = (x + arrow->width()) - (pos.x + pos.w), + hvy = (y + arrow->height()) - (pos.y + pos.h); + + Rect prevClip; + CSDL_Ext::getClipRect(to, prevClip); + CSDL_Ext::setClipRect(to, extRect); //preventing blitting outside of that rect + + if(ADVOPT.smoothMove) //version for smooth hero move, with pos shifts + { + if (hvx<0 && hvy<0) + { + arrow->draw(to, x + moveX, y + moveY); + } + else if(hvx<0) + { + Rect srcRect = genRect(arrow->height() - hvy, arrow->width(), 0, 0); + arrow->draw(to, x + moveX, y + moveY, &srcRect); + } + else if (hvy<0) + { + Rect srcRect = genRect(arrow->height(), arrow->width() - hvx, 0, 0); + arrow->draw(to, x + moveX, y + moveY, &srcRect); + } + else + { + Rect srcRect = genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); + arrow->draw(to, x + moveX, y + moveY, &srcRect); + } + } + else //standard version + { + if (hvx<0 && hvy<0) + { + arrow->draw(to, x, y); + } + else if(hvx<0) + { + Rect srcRect = genRect(arrow->height() - hvy, arrow->width(), 0, 0); + arrow->draw(to, x, y, &srcRect); + } + else if (hvy<0) + { + Rect srcRect = genRect(arrow->height(), arrow->width() - hvx, 0, 0); + arrow->draw(to, x, y, &srcRect); + } + else + { + Rect srcRect = genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); + arrow->draw(to, x, y, &srcRect); + } + } + CSDL_Ext::setClipRect(to, prevClip); + + } + } //for (int i=0;inodes.size()-1;i++) +} + +void CTerrainRect::show(SDL_Surface * to) +{ + if (adventureInt->mode == EAdvMapMode::NORMAL) + { + MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), pos); + info.otherheroAnim = true; + info.anim = adventureInt->anim; + info.heroAnim = adventureInt->heroAnim; + if (ADVOPT.smoothMove) + info.movement = int3(moveX, moveY, 0); + + lastRedrawStatus = CGI->mh->drawTerrainRectNew(to, &info); + if (fadeAnim->isFading()) + { + Rect r(pos); + fadeAnim->update(); + fadeAnim->draw(to, r.topLeft()); + } + + if (currentPath/* && adventureInt->position.z==currentPath->startPos().z*/) //drawing path + { + showPath(pos, to); + } + } +} + +void CTerrainRect::showAll(SDL_Surface * to) +{ + // world view map is static and doesn't need redraw every frame + if (adventureInt->mode == EAdvMapMode::WORLD_VIEW) + { + MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), pos, adventureInt->worldViewIcons); + info.scaled = true; + info.scale = adventureInt->worldViewScale; + adventureInt->worldViewOptions.adjustDrawingInfo(info); + CGI->mh->drawTerrainRectNew(to, &info); + } +} + +void CTerrainRect::showAnim(SDL_Surface * to) +{ + if (fadeAnim->isFading()) + show(to); + else if (lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED) + show(to); // currently the same; maybe we should pass some flag to map handler so it redraws ONLY tiles that need redraw instead of full +} + +int3 CTerrainRect::whichTileIsIt(const int x, const int y) +{ + int3 ret; + ret.x = adventureInt->position.x + ((x-CGI->mh->offsetX-pos.x)/32); + ret.y = adventureInt->position.y + ((y-CGI->mh->offsetY-pos.y)/32); + ret.z = adventureInt->position.z; + return ret; +} + +int3 CTerrainRect::whichTileIsIt() +{ + return whichTileIsIt(GH.getCursorPosition().x, GH.getCursorPosition().y); +} + +int3 CTerrainRect::tileCountOnScreen() +{ + switch (adventureInt->mode) + { + default: + logGlobal->error("Unknown map mode %d", (int)adventureInt->mode); + return int3(); + case EAdvMapMode::NORMAL: + return int3(tilesw, tilesh, 1); + case EAdvMapMode::WORLD_VIEW: + return int3((si32)(tilesw / adventureInt->worldViewScale), (si32)(tilesh / adventureInt->worldViewScale), 1); + } +} + +void CTerrainRect::fadeFromCurrentView() +{ + if (!ADVOPT.screenFading) + return; + if (adventureInt->mode == EAdvMapMode::WORLD_VIEW) + return; + + if (!fadeSurface) + fadeSurface = CSDL_Ext::newSurface(pos.w, pos.h); + CSDL_Ext::blitSurface(screen, fadeSurface, Point(0,0)); + fadeAnim->init(CFadeAnimation::EMode::OUT, fadeSurface); +} + +bool CTerrainRect::needsAnimUpdate() +{ + return fadeAnim->isFading() || lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED; +} + +void CResDataBar::clickRight(tribool down, bool previousState) +{ +} + +CResDataBar::CResDataBar(const std::string & defname, int x, int y, int offx, int offy, int resdist, int datedist) +{ + pos.x += x; + pos.y += y; + OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); + background = std::make_shared(defname, 0, 0); + background->colorize(LOCPLINT->playerID); + + pos.w = background->pos.w; + pos.h = background->pos.h; + + txtpos.resize(8); + for (int i = 0; i < 8 ; i++) + { + txtpos[i].first = pos.x + offx + resdist*i; + txtpos[i].second = pos.y + offy; + } + txtpos[7].first = txtpos[6].first + datedist; + datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] + + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s"; + addUsedEvents(RCLICK); +} + +CResDataBar::CResDataBar() +{ + pos.x += ADVOPT.resdatabarX; + pos.y += ADVOPT.resdatabarY; + + OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); + background = std::make_shared(ADVOPT.resdatabarG, 0, 0); + background->colorize(LOCPLINT->playerID); + + pos.w = background->pos.w; + pos.h = background->pos.h; + + txtpos.resize(8); + for (int i = 0; i < 8 ; i++) + { + txtpos[i].first = pos.x + ADVOPT.resOffsetX + ADVOPT.resDist*i; + txtpos[i].second = pos.y + ADVOPT.resOffsetY; + } + txtpos[7].first = txtpos[6].first + ADVOPT.resDateDist; + datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] + + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s"; +} + +CResDataBar::~CResDataBar() = default; + +void CResDataBar::draw(SDL_Surface * to) +{ + //TODO: all this should be labels, but they require proper text update on change + for (auto i=Res::WOOD; i<=Res::GOLD; vstd::advance(i, 1)) + { + std::string text = boost::lexical_cast(LOCPLINT->cb->getResourceAmount(i)); + + graphics->fonts[FONT_SMALL]->renderTextLeft(to, text, Colors::WHITE, Point(txtpos[i].first,txtpos[i].second)); + } + std::vector temp; + + temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::MONTH))); + temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::WEEK))); + temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK))); + + graphics->fonts[FONT_SMALL]->renderTextLeft(to, processStr(datetext,temp), Colors::WHITE, Point(txtpos[7].first,txtpos[7].second)); +} + +void CResDataBar::show(SDL_Surface * to) +{ + +} + +void CResDataBar::showAll(SDL_Surface * to) +{ + CIntObject::showAll(to); + draw(to); +} + +CAdvMapInt::CAdvMapInt(): + mode(EAdvMapMode::NORMAL), + worldViewScale(0.0f), //actual init later in changeMode + minimap(Rect(ADVOPT.minimapX, ADVOPT.minimapY, ADVOPT.minimapW, ADVOPT.minimapH)), + statusbar(CGStatusBar::create(ADVOPT.statusbarX,ADVOPT.statusbarY,ADVOPT.statusbarG)), + heroList(ADVOPT.hlistSize, Point(ADVOPT.hlistX, ADVOPT.hlistY), ADVOPT.hlistAU, ADVOPT.hlistAD), + townList(ADVOPT.tlistSize, Point(ADVOPT.tlistX, ADVOPT.tlistY), ADVOPT.tlistAU, ADVOPT.tlistAD), + infoBar(Rect(ADVOPT.infoboxX, ADVOPT.infoboxY, 192, 192)), state(NA), + spellBeingCasted(nullptr), position(int3(0, 0, 0)), selection(nullptr), + updateScreen(false), anim(0), animValHitCount(0), heroAnim(0), heroAnimValHitCount(0), + activeMapPanel(nullptr), duringAITurn(false), scrollingDir(0), scrollingState(false), + swipeEnabled(settings["general"]["swipe"].Bool()), swipeMovementRequested(false), + swipeTargetPosition(int3(-1, -1, -1)) +{ + pos.x = pos.y = 0; + pos.w = screen->w; + pos.h = screen->h; + strongInterest = true; // handle all mouse move events to prevent dead mouse move space in fullscreen mode + townList.onSelect = std::bind(&CAdvMapInt::selectionChanged,this); + bg = IImage::createFromFile(ADVOPT.mainGraphic); + if(!ADVOPT.worldViewGraphic.empty()) + { + bgWorldView = IImage::createFromFile(ADVOPT.worldViewGraphic); + } + else + { + bgWorldView = nullptr; + logGlobal->warn("ADVOPT.worldViewGraphic is empty => bitmap not loaded"); + } + if (!bgWorldView) + { + logGlobal->warn("bgWorldView not defined in resolution config; fallback to VWorld.bmp"); + bgWorldView = IImage::createFromFile("VWorld.bmp"); + } + + worldViewIcons = std::make_shared("VwSymbol");//todo: customize with ADVOPT + worldViewIcons->preload(); + + for(int g = 0; g < ADVOPT.gemG.size(); ++g) + { + gems.push_back(std::make_shared(ADVOPT.gemG[g], 0, 0, ADVOPT.gemX[g], ADVOPT.gemY[g])); + } + + auto makeButton = [&](int textID, std::function callback, config::ButtonInfo info, int key) -> std::shared_ptr + { + auto button = std::make_shared(Point(info.x, info.y), info.defName, CGI->generaltexth->zelp[textID], callback, key, info.playerColoured); + for(auto image : info.additionalDefs) + button->addImage(image); + return button; + }; + + kingOverview = makeButton(293, std::bind(&CAdvMapInt::fshowOverview,this), ADVOPT.kingOverview, SDLK_k); + underground = makeButton(294, std::bind(&CAdvMapInt::fswitchLevel,this), ADVOPT.underground, SDLK_u); + questlog = makeButton(295, std::bind(&CAdvMapInt::fshowQuestlog,this), ADVOPT.questlog, SDLK_q); + sleepWake = makeButton(296, std::bind(&CAdvMapInt::fsleepWake,this), ADVOPT.sleepWake, SDLK_w); + moveHero = makeButton(297, std::bind(&CAdvMapInt::fmoveHero,this), ADVOPT.moveHero, SDLK_m); + spellbook = makeButton(298, std::bind(&CAdvMapInt::fshowSpellbok,this), ADVOPT.spellbook, SDLK_c); + advOptions = makeButton(299, std::bind(&CAdvMapInt::fadventureOPtions,this), ADVOPT.advOptions, SDLK_a); + sysOptions = makeButton(300, std::bind(&CAdvMapInt::fsystemOptions,this), ADVOPT.sysOptions, SDLK_o); + nextHero = makeButton(301, std::bind(&CAdvMapInt::fnextHero,this), ADVOPT.nextHero, SDLK_h); + endTurn = makeButton(302, std::bind(&CAdvMapInt::fendTurn,this), ADVOPT.endTurn, SDLK_e); + + int panelSpaceBottom = screen->h - resdatabar.pos.h - 4; + + panelMain = std::make_shared(nullptr, Point(0, 0)); + // TODO correct drawing position + panelWorldView = std::make_shared(worldViewIcons, bgWorldView, Point(heroList.pos.x - 2, 195), panelSpaceBottom, LOCPLINT->playerID); + + panelMain->addChildColorableButton(kingOverview); + panelMain->addChildColorableButton(underground); + panelMain->addChildColorableButton(questlog); + panelMain->addChildColorableButton(sleepWake); + panelMain->addChildColorableButton(moveHero); + panelMain->addChildColorableButton(spellbook); + panelMain->addChildColorableButton(advOptions); + panelMain->addChildColorableButton(sysOptions); + panelMain->addChildColorableButton(nextHero); + panelMain->addChildColorableButton(endTurn); + + + // TODO move configs to resolutions.json, similarly to previous buttons + config::ButtonInfo worldViewBackConfig = config::ButtonInfo(); + worldViewBackConfig.defName = "IOK6432.DEF"; + worldViewBackConfig.x = screen->w - 73; + worldViewBackConfig.y = 343 + 195; + worldViewBackConfig.playerColoured = false; + panelWorldView->addChildToPanel( + makeButton(288, std::bind(&CAdvMapInt::fworldViewBack,this), worldViewBackConfig, SDLK_ESCAPE), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewPuzzleConfig = config::ButtonInfo(); + worldViewPuzzleConfig.defName = "VWPUZ.DEF"; + worldViewPuzzleConfig.x = screen->w - 188; + worldViewPuzzleConfig.y = 343 + 195; + worldViewPuzzleConfig.playerColoured = false; + panelWorldView->addChildToPanel( // no help text for this one + std::make_shared(Point(worldViewPuzzleConfig.x, worldViewPuzzleConfig.y), worldViewPuzzleConfig.defName, std::pair(), + std::bind(&CPlayerInterface::showPuzzleMap,LOCPLINT), SDLK_p, worldViewPuzzleConfig.playerColoured), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewScale1xConfig = config::ButtonInfo(); + worldViewScale1xConfig.defName = "VWMAG1.DEF"; + worldViewScale1xConfig.x = screen->w - 191; + worldViewScale1xConfig.y = 23 + 195; + worldViewScale1xConfig.playerColoured = false; + panelWorldView->addChildToPanel( // help text is wrong for this button + makeButton(291, std::bind(&CAdvMapInt::fworldViewScale1x,this), worldViewScale1xConfig, SDLK_1), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewScale2xConfig = config::ButtonInfo(); + worldViewScale2xConfig.defName = "VWMAG2.DEF"; + worldViewScale2xConfig.x = screen->w - 191 + 63; + worldViewScale2xConfig.y = 23 + 195; + worldViewScale2xConfig.playerColoured = false; + panelWorldView->addChildToPanel( // help text is wrong for this button + makeButton(291, std::bind(&CAdvMapInt::fworldViewScale2x,this), worldViewScale2xConfig, SDLK_2), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewScale4xConfig = config::ButtonInfo(); + worldViewScale4xConfig.defName = "VWMAG4.DEF"; + worldViewScale4xConfig.x = screen->w - 191 + 126; + worldViewScale4xConfig.y = 23 + 195; + worldViewScale4xConfig.playerColoured = false; + panelWorldView->addChildToPanel( // help text is wrong for this button + makeButton(291, std::bind(&CAdvMapInt::fworldViewScale4x,this), worldViewScale4xConfig, SDLK_4), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewUndergroundConfig = config::ButtonInfo(); + worldViewUndergroundConfig.defName = "IAM010.DEF"; + worldViewUndergroundConfig.additionalDefs.push_back("IAM003.DEF"); + worldViewUndergroundConfig.x = screen->w - 115; + worldViewUndergroundConfig.y = 343 + 195; + worldViewUndergroundConfig.playerColoured = true; + worldViewUnderground = makeButton(294, std::bind(&CAdvMapInt::fswitchLevel,this), worldViewUndergroundConfig, SDLK_u); + panelWorldView->addChildColorableButton(worldViewUnderground); + + setPlayer(LOCPLINT->playerID); + + int iconColorMultiplier = player.getNum() * 19; + int wvLeft = heroList.pos.x - 2; // TODO correct drawing position + //int wvTop = 195; + for (int i = 0; i < 5; ++i) + { + panelWorldView->addChildIcon(std::pair(i, Point(5, 58 + i * 20)), iconColorMultiplier); + panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 263 + i * 20, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, + Colors::WHITE, CGI->generaltexth->allTexts[612 + i])); + } + for (int i = 0; i < 7; ++i) + { + panelWorldView->addChildIcon(std::pair(i + 5, Point(5, 182 + i * 20)), iconColorMultiplier); + panelWorldView->addChildIcon(std::pair(i + 12, Point(160, 182 + i * 20)), iconColorMultiplier); + panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 387 + i * 20, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, + Colors::WHITE, CGI->generaltexth->allTexts[619 + i])); + } + panelWorldView->addChildToPanel(std::make_shared(wvLeft + 5, 367, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, + Colors::WHITE, CGI->generaltexth->allTexts[617])); + panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 367, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, + Colors::WHITE, CGI->generaltexth->allTexts[618])); + + activeMapPanel = panelMain; + + changeMode(EAdvMapMode::NORMAL); + + underground->block(!CGI->mh->map->twoLevel); + questlog->block(!CGI->mh->map->quests.size()); + worldViewUnderground->block(!CGI->mh->map->twoLevel); + + addUsedEvents(MOVE); +} + +void CAdvMapInt::fshowOverview() +{ + GH.pushIntT(); +} + +void CAdvMapInt::fworldViewBack() +{ + changeMode(EAdvMapMode::NORMAL); + CGI->mh->discardWorldViewCache(); + + auto hero = curHero(); + if (hero) + centerOn(hero); +} + +void CAdvMapInt::fworldViewScale1x() +{ + // TODO set corresponding scale button to "selected" mode + changeMode(EAdvMapMode::WORLD_VIEW, 0.22f); +} + +void CAdvMapInt::fworldViewScale2x() +{ + changeMode(EAdvMapMode::WORLD_VIEW, 0.36f); +} + +void CAdvMapInt::fworldViewScale4x() +{ + changeMode(EAdvMapMode::WORLD_VIEW, 0.5f); +} + +void CAdvMapInt::fswitchLevel() +{ + // with support for future multi-level maps :) + int maxLevels = CGI->mh->map->levels(); + if (maxLevels < 2) + return; + + position.z = (position.z + 1) % maxLevels; + + underground->setIndex(position.z, true); + underground->redraw(); + + worldViewUnderground->setIndex(position.z, true); + worldViewUnderground->redraw(); + + updateScreen = true; + minimap.setLevel(position.z); + + if (mode == EAdvMapMode::WORLD_VIEW) + terrain.redraw(); +} +void CAdvMapInt::fshowQuestlog() +{ + LOCPLINT->showQuestLog(); +} +void CAdvMapInt::fsleepWake() +{ + const CGHeroInstance *h = curHero(); + if (!h) + return; + bool newSleep = !isHeroSleeping(h); + setHeroSleeping(h, newSleep); + updateSleepWake(h); + if (newSleep) + { + fnextHero(); + + //moveHero.block(true); + //uncomment to enable original HoMM3 behaviour: + //move button is disabled for hero going to sleep, even though it's enabled when you reselect him + } +} + +void CAdvMapInt::fmoveHero() +{ + const CGHeroInstance *h = curHero(); + if (!h || !terrain.currentPath || !CGI->mh->canStartHeroMovement()) + return; + + LOCPLINT->moveHero(h, *terrain.currentPath); +} + +void CAdvMapInt::fshowSpellbok() +{ + if (!curHero()) //checking necessary values + return; + + centerOn(selection); + + GH.pushIntT(curHero(), LOCPLINT, false); +} + +void CAdvMapInt::fadventureOPtions() +{ + GH.pushIntT(); +} + +void CAdvMapInt::fsystemOptions() +{ + GH.pushIntT(); +} + +void CAdvMapInt::fnextHero() +{ + auto hero = dynamic_cast(selection); + int next = getNextHeroIndex(vstd::find_pos(LOCPLINT->wanderingHeroes, hero)); + if (next < 0) + return; + select(LOCPLINT->wanderingHeroes[next], true); +} + +void CAdvMapInt::fendTurn() +{ + if(!LOCPLINT->makingTurn) + return; + + if(settings["adventure"]["heroReminder"].Bool()) + { + for(auto hero : LOCPLINT->wanderingHeroes) + { + if(!isHeroSleeping(hero) && hero->movement > 0) + { + // Only show hero reminder if conditions met: + // - There still movement points + // - Hero don't have a path or there not points for first step on path + auto path = LOCPLINT->getAndVerifyPath(hero); + if(!path || path->nodes.size() < 2 || !path->nodes[path->nodes.size()-2].turns) + { + LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[55], std::bind(&CAdvMapInt::endingTurn, this), nullptr); + return; + } + } + } + } + endingTurn(); +} + +void CAdvMapInt::updateSleepWake(const CGHeroInstance *h) +{ + sleepWake->block(!h); + if (!h) + return; + bool state = isHeroSleeping(h); + sleepWake->setIndex(state ? 1 : 0, true); + sleepWake->assignedKeys.clear(); + sleepWake->assignedKeys.insert(state ? SDLK_w : SDLK_z); +} + +void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath) +{ + if(!h) + { + moveHero->block(true); + return; + } + //default value is for everywhere but CPlayerInterface::moveHero, because paths are not updated from there immediately + if(boost::logic::indeterminate(hasPath)) + hasPath = LOCPLINT->paths[h].nodes.size() ? true : false; + + moveHero->block(!(bool)hasPath || (h->movement == 0)); +} + +void CAdvMapInt::updateSpellbook(const CGHeroInstance *h) +{ + spellbook->block(!h); +} + +int CAdvMapInt::getNextHeroIndex(int startIndex) +{ + if (LOCPLINT->wanderingHeroes.size() == 0) + return -1; + if (startIndex < 0) + startIndex = 0; + int i = startIndex; + do + { + i++; + if (i >= LOCPLINT->wanderingHeroes.size()) + i = 0; + } + while (((LOCPLINT->wanderingHeroes[i]->movement == 0) || isHeroSleeping(LOCPLINT->wanderingHeroes[i])) && (i != startIndex)); + + if ((LOCPLINT->wanderingHeroes[i]->movement != 0) && !isHeroSleeping(LOCPLINT->wanderingHeroes[i])) + return i; + else + return -1; +} + +void CAdvMapInt::updateNextHero(const CGHeroInstance *h) +{ + int start = vstd::find_pos(LOCPLINT->wanderingHeroes, h); + int next = getNextHeroIndex(start); + if (next < 0) + { + nextHero->block(true); + return; + } + const CGHeroInstance *nextH = LOCPLINT->wanderingHeroes[next]; + bool noActiveHeroes = (next == start) && ((nextH->movement == 0) || isHeroSleeping(nextH)); + nextHero->block(noActiveHeroes); +} + +void CAdvMapInt::activate() +{ + CIntObject::activate(); + if (!(active & KEYBOARD)) + CIntObject::activate(KEYBOARD); + + screenBuf = screen; + GH.statusbar = statusbar; + + if(LOCPLINT) + { + LOCPLINT->cingconsole->activate(); + LOCPLINT->cingconsole->pos = this->pos; + } + + if(!duringAITurn) + { + activeMapPanel->activate(); + if (mode == EAdvMapMode::NORMAL) + { + heroList.activate(); + townList.activate(); + infoBar.activate(); + } + minimap.activate(); + terrain.activate(); + statusbar->activate(); + + GH.fakeMouseMove(); //to restore the cursor + } +} + +void CAdvMapInt::deactivate() +{ + CIntObject::deactivate(); + + if(!duringAITurn) + { + scrollingDir = 0; + + CCS->curh->set(Cursor::Map::POINTER); + activeMapPanel->deactivate(); + if (mode == EAdvMapMode::NORMAL) + { + heroList.deactivate(); + townList.deactivate(); + infoBar.deactivate(); + } + minimap.deactivate(); + terrain.deactivate(); + statusbar->deactivate(); + } +} + +void CAdvMapInt::showAll(SDL_Surface * to) +{ + bg->draw(to, 0, 0); + + if(state != INGAME) + return; + + switch (mode) + { + case EAdvMapMode::NORMAL: + + heroList.showAll(to); + townList.showAll(to); + infoBar.showAll(to); + break; + case EAdvMapMode::WORLD_VIEW: + + terrain.showAll(to); + break; + } + activeMapPanel->showAll(to); + + updateScreen = true; + minimap.showAll(to); + show(to); + + + resdatabar.showAll(to); + + statusbar->show(to); + + LOCPLINT->cingconsole->show(to); +} + +bool CAdvMapInt::isHeroSleeping(const CGHeroInstance *hero) +{ + if (!hero) + return false; + + return vstd::contains(LOCPLINT->sleepingHeroes, hero); +} + +void CAdvMapInt::setHeroSleeping(const CGHeroInstance *hero, bool sleep) +{ + if (sleep) + LOCPLINT->sleepingHeroes.push_back(hero); //FIXME: should we check for existence? + else + LOCPLINT->sleepingHeroes -= hero; + updateNextHero(nullptr); +} + +void CAdvMapInt::show(SDL_Surface * to) +{ + if(state != INGAME) + return; + + ++animValHitCount; //for animations + + if(animValHitCount % 2 == 0) + { + ++heroAnim; + } + if(animValHitCount >= 8) + { + CGI->mh->updateWater(); + animValHitCount = 0; + ++anim; + updateScreen = true; + } + + if(swipeEnabled) + { + handleSwipeUpdate(); + } +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) // on mobile, map-moving mode is exclusive (TODO technically it might work with both enabled; to be checked) + else +#endif + { + handleMapScrollingUpdate(); + } + + for(int i = 0; i < 4; i++) + { + if(settings["session"]["spectate"].Bool()) + gems[i]->setFrame(PlayerColor(1).getNum()); + else + gems[i]->setFrame(LOCPLINT->playerID.getNum()); + } + if(updateScreen) + { + int3 betterPos = LOCPLINT->repairScreenPos(position); + if (betterPos != position) + { + logGlobal->warn("Incorrect position for adventure map!"); + position = betterPos; + } + + terrain.show(to); + for(int i = 0; i < 4; i++) + gems[i]->showAll(to); + updateScreen=false; + LOCPLINT->cingconsole->show(to); + } + else if (terrain.needsAnimUpdate()) + { + terrain.showAnim(to); + for(int i = 0; i < 4; i++) + gems[i]->showAll(to); + } + + infoBar.show(to); + statusbar->showAll(to); +} + +void CAdvMapInt::handleMapScrollingUpdate() +{ + int scrollSpeed = static_cast(settings["adventure"]["scrollSpeed"].Float()); + //if advmap needs updating AND (no dialog is shown OR ctrl is pressed) + if((animValHitCount % (4 / scrollSpeed)) == 0 + && ((GH.topInt().get() == this) || isCtrlKeyDown())) + { + if((scrollingDir & LEFT) && (position.x > -CGI->mh->frameW)) + position.x--; + + if((scrollingDir & RIGHT) && (position.x < CGI->mh->map->width - CGI->mh->tilesW + CGI->mh->frameW)) + position.x++; + + if((scrollingDir & UP) && (position.y > -CGI->mh->frameH)) + position.y--; + + if((scrollingDir & DOWN) && (position.y < CGI->mh->map->height - CGI->mh->tilesH + CGI->mh->frameH)) + position.y++; + + if(scrollingDir) + { + setScrollingCursor(scrollingDir); + scrollingState = true; + updateScreen = true; + minimap.redraw(); + if(mode == EAdvMapMode::WORLD_VIEW) + terrain.redraw(); + } + else if(scrollingState) + { + CCS->curh->set(Cursor::Map::POINTER); + scrollingState = false; + } + } +} + +void CAdvMapInt::handleSwipeUpdate() +{ + if(swipeMovementRequested) + { + auto fixedPos = LOCPLINT->repairScreenPos(swipeTargetPosition); + position.x = fixedPos.x; + position.y = fixedPos.y; + CCS->curh->set(Cursor::Map::POINTER); + updateScreen = true; + minimap.redraw(); + swipeMovementRequested = false; + } +} + +void CAdvMapInt::selectionChanged() +{ + const CGTownInstance *to = LOCPLINT->towns[townList.getSelectedIndex()]; + if (selection != to) + select(to); +} + +void CAdvMapInt::centerOn(int3 on, bool fade) +{ + bool switchedLevels = on.z != position.z; + + if (fade) + { + terrain.fadeFromCurrentView(); + } + + switch (mode) + { + default: + case EAdvMapMode::NORMAL: + on.x -= CGI->mh->frameW; // is this intentional? frame size doesn't really have to correspond to camera size... + on.y -= CGI->mh->frameH; + break; + case EAdvMapMode::WORLD_VIEW: + on.x -= static_cast(CGI->mh->tilesW / 2 / worldViewScale); + on.y -= static_cast(CGI->mh->tilesH / 2 / worldViewScale); + break; + } + + + on = LOCPLINT->repairScreenPos(on); + + position = on; + updateScreen=true; + underground->setIndex(on.z,true); //change underground switch button image + underground->redraw(); + worldViewUnderground->setIndex(on.z, true); + worldViewUnderground->redraw(); + if (switchedLevels) + minimap.setLevel(position.z); + minimap.redraw(); + + if (mode == EAdvMapMode::WORLD_VIEW) + terrain.redraw(); +} + +void CAdvMapInt::centerOn(const CGObjectInstance * obj, bool fade) +{ + centerOn(obj->getSightCenter(), fade); +} + +void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) +{ + + if (mode == EAdvMapMode::WORLD_VIEW) + return; + + ui8 Dir = 0; + SDL_Keycode k = key.keysym.sym; + const CGHeroInstance *h = curHero(); //selected hero + const CGTownInstance *t = curTown(); //selected town + + switch(k) + { + case SDLK_g: + if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) + return; + + { + //find first town with tavern + auto itr = range::find_if(LOCPLINT->towns, [](const CGTownInstance * town) + { + return town->hasBuilt(BuildingID::TAVERN); + }); + + if(itr != LOCPLINT->towns.end()) + LOCPLINT->showThievesGuildWindow(*itr); + else + LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithTavern")); + } + return; + case SDLK_i: + if(isActive()) + CAdventureOptions::showScenarioInfo(); + return; + case SDLK_l: + if(isActive()) + LOCPLINT->proposeLoadingGame(); + return; + case SDLK_s: + if(isActive() && key.type == SDL_KEYUP) + GH.pushIntT(); + return; + case SDLK_d: + { + if(h && isActive() && LOCPLINT->makingTurn && key.state == SDL_PRESSED) + LOCPLINT->tryDiggging(h); + return; + } + case SDLK_p: + if(isActive()) + LOCPLINT->showPuzzleMap(); + return; + case SDLK_v: + if(isActive()) + LOCPLINT->viewWorldMap(); + return; + case SDLK_r: + if(isActive() && LOCPLINT->ctrlPressed()) + { + LOCPLINT->showYesNoDialog(CGI->generaltexth->translate("vcmi.adventureMap.confirmRestartGame"), + [](){ LOCPLINT->sendCustomEvent(EUserEvent::RESTART_GAME); }, nullptr); + } + return; + case SDLK_SPACE: //space - try to revisit current object with selected hero + { + if(!isActive()) + return; + if(h && key.state == SDL_PRESSED) + { + auto unlockPim = vstd::makeUnlockGuard(*CPlayerInterface::pim); + //TODO!!!!!!! possible freeze, when GS mutex is locked and network thread can't apply package + //this thread leaves scope and tries to lock pim while holding gs, + //network thread tries to lock gs (appluy cl) while holding pim + //this thread should first lock pim, however gs locking/unlocking is done inside cb + LOCPLINT->cb->moveHero(h,h->pos); + } + } + return; + case SDLK_RETURN: + { + if(!isActive() || !selection || key.state != SDL_PRESSED) + return; + if(h) + LOCPLINT->openHeroWindow(h); + else if(t) + LOCPLINT->openTownWindow(t); + return; + } + case SDLK_ESCAPE: + { + if(isActive() || GH.topInt().get() != this || !spellBeingCasted || key.state != SDL_PRESSED) + return; + + leaveCastingMode(); + return; + } + case SDLK_t: + { + //act on key down if marketplace windows is not already opened + if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) + return; + + if(LOCPLINT->ctrlPressed()) //CTRL + T => open marketplace + { + //check if we have any marketplace + const CGTownInstance *townWithMarket = nullptr; + for(const CGTownInstance *t : LOCPLINT->cb->getTownsInfo()) + { + if(t->hasBuilt(BuildingID::MARKETPLACE)) + { + townWithMarket = t; + break; + } + } + + if(townWithMarket) //if any town has marketplace, open window + GH.pushIntT(townWithMarket); + else //if not - complain + LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithMarket")); + } + else if(isActive()) //no ctrl, advmapint is on the top => switch to town + { + townList.selectNext(); + } + return; + } + default: + { + static const int3 directions[] = { int3(-1, +1, 0), int3(0, +1, 0), int3(+1, +1, 0), + int3(-1, 0, 0), int3(0, 0, 0), int3(+1, 0, 0), + int3(-1, -1, 0), int3(0, -1, 0), int3(+1, -1, 0) }; + + //numpad arrow + if(CGuiHandler::isArrowKey(k)) + k = CGuiHandler::arrowToNum(k); + + k -= SDLK_KP_1; + + if(k < 0 || k > 8) + return; + + if (!CGI->mh->canStartHeroMovement()) + return; + + int3 dir = directions[k]; + + if(!isActive() || LOCPLINT->ctrlPressed())//ctrl makes arrow move screen, not hero + { + Dir = (dir.x<0 ? LEFT : 0) | + (dir.x>0 ? RIGHT : 0) | + (dir.y<0 ? UP : 0) | + (dir.y>0 ? DOWN : 0) ; + break; + } + + if(!h || key.state != SDL_PRESSED) + break; + + if(k == 4) + { + centerOn(h); + return; + } + + CGPath &path = LOCPLINT->paths[h]; + terrain.currentPath = &path; + int3 dst = h->visitablePos() + dir; + if(dst != verifyPos(dst) || !LOCPLINT->cb->getPathsInfo(h)->getPath(path, dst)) + { + terrain.currentPath = nullptr; + return; + } + + if (path.nodes.size() > 2) + updateMoveHero(h); + else + if(!path.nodes[0].turns) + LOCPLINT->moveHero(h, path); + } + + return; + } + if(Dir && key.state == SDL_PRESSED //arrow is pressed + && LOCPLINT->ctrlPressed() + ) + scrollingDir |= Dir; + else + scrollingDir &= ~Dir; +} +void CAdvMapInt::handleRightClick(std::string text, tribool down) +{ + if(down) + { + CRClickPopup::createAndPush(text); + } +} +int3 CAdvMapInt::verifyPos(int3 ver) +{ + if (ver.x<0) + ver.x=0; + if (ver.y<0) + ver.y=0; + if (ver.z<0) + ver.z=0; + if (ver.x>=CGI->mh->sizes.x) + ver.x=CGI->mh->sizes.x-1; + if (ver.y>=CGI->mh->sizes.y) + ver.y=CGI->mh->sizes.y-1; + if (ver.z>=CGI->mh->sizes.z) + ver.z=CGI->mh->sizes.z-1; + return ver; +} + +void CAdvMapInt::select(const CArmedInstance *sel, bool centerView) +{ + assert(sel); + LOCPLINT->setSelection(sel); + selection = sel; + if (LOCPLINT->battleInt == nullptr && LOCPLINT->makingTurn) + { + auto pos = sel->visitablePos(); + auto tile = LOCPLINT->cb->getTile(pos); + if(tile) + CCS->musich->playMusicFromSet("terrain", tile->terType->getJsonKey(), true, false); + } + if(centerView) + centerOn(sel); + + terrain.currentPath = nullptr; + if(sel->ID==Obj::TOWN) + { + auto town = dynamic_cast(sel); + + infoBar.showTownSelection(town); + townList.select(town); + heroList.select(nullptr); + + updateSleepWake(nullptr); + updateMoveHero(nullptr); + updateSpellbook(nullptr); + } + else //hero selected + { + auto hero = dynamic_cast(sel); + + infoBar.showHeroSelection(hero); + heroList.select(hero); + townList.select(nullptr); + + terrain.currentPath = LOCPLINT->getAndVerifyPath(hero); + + updateSleepWake(hero); + updateMoveHero(hero); + updateSpellbook(hero); + } + townList.redraw(); + heroList.redraw(); +} + +void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent ) +{ +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + if(swipeEnabled) + return; +#endif + // adventure map scrolling with mouse + // currently disabled in world view mode (as it is in OH3), but should work correctly if mode check is removed + // don't scroll if there is no window in focus - these events don't seem to correspond to the actual mouse movement + if(!isCtrlKeyDown() && isActive() && sEvent.windowID != 0 && mode == EAdvMapMode::NORMAL) + { + if(sEvent.x<15) + { + scrollingDir |= LEFT; + } + else + { + scrollingDir &= ~LEFT; + } + if(sEvent.x>screen->w-15) + { + scrollingDir |= RIGHT; + } + else + { + scrollingDir &= ~RIGHT; + } + if(sEvent.y<15) + { + scrollingDir |= UP; + } + else + { + scrollingDir &= ~UP; + } + if(sEvent.y>screen->h-15) + { + scrollingDir |= DOWN; + } + else + { + scrollingDir &= ~DOWN; + } + } +} + +bool CAdvMapInt::isActive() +{ + return active & ~CIntObject::KEYBOARD; +} + +void CAdvMapInt::startHotSeatWait(PlayerColor Player) +{ + state = WAITING; +} + +void CAdvMapInt::setPlayer(PlayerColor Player) +{ + player = Player; + bg->playerColored(player); + + panelMain->setPlayerColor(player); + panelWorldView->setPlayerColor(player); + panelWorldView->recolorIcons(player, player.getNum() * 19); + resdatabar.background->colorize(player); +} + +void CAdvMapInt::startTurn() +{ + state = INGAME; + if(LOCPLINT->cb->getCurrentPlayer() == LOCPLINT->playerID + || settings["session"]["spectate"].Bool()) + { + adjustActiveness(false); + minimap.setAIRadar(false); + } +} + +void CAdvMapInt::endingTurn() +{ + if(settings["session"]["spectate"].Bool()) + return; + + LOCPLINT->makingTurn = false; + LOCPLINT->cb->endTurn(); + CCS->soundh->ambientStopAllChannels(); +} + +const CGObjectInstance* CAdvMapInt::getActiveObject(const int3 &mapPos) +{ + std::vector < const CGObjectInstance * > bobjs = LOCPLINT->cb->getBlockingObjs(mapPos); //blocking objects at tile + + if (bobjs.empty()) + return nullptr; + + return *boost::range::max_element(bobjs, &CMapHandler::compareObjectBlitOrder); +/* + if (bobjs.back()->ID == Obj::HERO) + return bobjs.back(); + else + return bobjs.front();*/ +} + +void CAdvMapInt::tileLClicked(const int3 &mapPos) +{ + if(mode != EAdvMapMode::NORMAL) + return; + if(!LOCPLINT->cb->isVisible(mapPos) || !LOCPLINT->makingTurn) + return; + + const TerrainTile *tile = LOCPLINT->cb->getTile(mapPos); + + const CGObjectInstance *topBlocking = getActiveObject(mapPos); + + int3 selPos = selection->getSightCenter(); + if(spellBeingCasted && isInScreenRange(selPos, mapPos)) + { + const TerrainTile *heroTile = LOCPLINT->cb->getTile(selPos); + + switch(spellBeingCasted->id) + { + case SpellID::SCUTTLE_BOAT: //Scuttle Boat + if(topBlocking && topBlocking->ID == Obj::BOAT) + leaveCastingMode(true, mapPos); + break; + case SpellID::DIMENSION_DOOR: + if(!tile || tile->isClear(heroTile)) + leaveCastingMode(true, mapPos); + break; + } + return; + } + //check if we can select this object + bool canSelect = topBlocking && topBlocking->ID == Obj::HERO && topBlocking->tempOwner == LOCPLINT->playerID; + canSelect |= topBlocking && topBlocking->ID == Obj::TOWN && LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, topBlocking->tempOwner); + + bool isHero = false; + if(selection->ID != Obj::HERO) //hero is not selected (presumably town) + { + assert(!terrain.currentPath); //path can be active only when hero is selected + if(selection == topBlocking) //selected town clicked + LOCPLINT->openTownWindow(static_cast(topBlocking)); + else if(canSelect) + select(static_cast(topBlocking), false); + } + else if(const CGHeroInstance * currentHero = curHero()) //hero is selected + { + isHero = true; + + const CGPathNode *pn = LOCPLINT->cb->getPathsInfo(currentHero)->getPathInfo(mapPos); + if(currentHero == topBlocking) //clicked selected hero + { + LOCPLINT->openHeroWindow(currentHero); + return; + } + else if(canSelect && pn->turns == 255 ) //selectable object at inaccessible tile + { + select(static_cast(topBlocking), false); + return; + } + else //still here? we need to move hero if we clicked end of already selected path or calculate a new path otherwise + { + if(terrain.currentPath && terrain.currentPath->endPos() == mapPos)//we'll be moving + { + if(CGI->mh->canStartHeroMovement()) + LOCPLINT->moveHero(currentHero, *terrain.currentPath); + return; + } + else //remove old path and find a new one if we clicked on accessible tile + { + CGPath &path = LOCPLINT->paths[currentHero]; + CGPath newpath; + bool gotPath = LOCPLINT->cb->getPathsInfo(currentHero)->getPath(newpath, mapPos); //try getting path, erase if failed + if(gotPath && newpath.nodes.size()) + path = newpath; + + if(path.nodes.size()) + terrain.currentPath = &path; + else + LOCPLINT->eraseCurrentPathOf(currentHero); + + updateMoveHero(currentHero); + } + } + } //end of hero is selected "case" + else + { + throw std::runtime_error("Nothing is selected..."); + } + + const auto shipyard = ourInaccessibleShipyard(topBlocking); + if(isHero && shipyard != nullptr) + { + LOCPLINT->showShipyardDialogOrProblemPopup(shipyard); + } +} + +void CAdvMapInt::tileHovered(const int3 &mapPos) +{ + if(mode != EAdvMapMode::NORMAL //disable in world view + || !selection) //may occur just at the start of game (fake move before full intiialization) + return; + if(!LOCPLINT->cb->isVisible(mapPos)) + { + CCS->curh->set(Cursor::Map::POINTER); + statusbar->clear(); + return; + } + auto objRelations = PlayerRelations::ALLIES; + const CGObjectInstance *objAtTile = getActiveObject(mapPos); + if(objAtTile) + { + objRelations = LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, objAtTile->tempOwner); + std::string text = curHero() ? objAtTile->getHoverText(curHero()) : objAtTile->getHoverText(LOCPLINT->playerID); + boost::replace_all(text,"\n"," "); + statusbar->write(text); + } + else + { + std::string hlp; + CGI->mh->getTerrainDescr(mapPos, hlp, false); + statusbar->write(hlp); + } + + if(spellBeingCasted) + { + switch(spellBeingCasted->id) + { + case SpellID::SCUTTLE_BOAT: + if(objAtTile && objAtTile->ID == Obj::BOAT) + CCS->curh->set(Cursor::Map::SCUTTLE_BOAT); + else + CCS->curh->set(Cursor::Map::POINTER); + return; + case SpellID::DIMENSION_DOOR: + { + const TerrainTile * t = LOCPLINT->cb->getTile(mapPos, false); + int3 hpos = selection->getSightCenter(); + if((!t || t->isClear(LOCPLINT->cb->getTile(hpos))) && isInScreenRange(hpos, mapPos)) + CCS->curh->set(Cursor::Map::TELEPORT); + else + CCS->curh->set(Cursor::Map::POINTER); + return; + } + } + } + + if(selection->ID == Obj::TOWN) + { + if(objAtTile) + { + if(objAtTile->ID == Obj::TOWN && objRelations != PlayerRelations::ENEMIES) + CCS->curh->set(Cursor::Map::TOWN); + else if(objAtTile->ID == Obj::HERO && objRelations == PlayerRelations::SAME_PLAYER) + CCS->curh->set(Cursor::Map::HERO); + else + CCS->curh->set(Cursor::Map::POINTER); + } + else + CCS->curh->set(Cursor::Map::POINTER); + } + else if(const CGHeroInstance * hero = curHero()) + { + std::array cursorMove = { Cursor::Map::T1_MOVE, Cursor::Map::T2_MOVE, Cursor::Map::T3_MOVE, Cursor::Map::T4_MOVE, }; + std::array cursorAttack = { Cursor::Map::T1_ATTACK, Cursor::Map::T2_ATTACK, Cursor::Map::T3_ATTACK, Cursor::Map::T4_ATTACK, }; + std::array cursorSail = { Cursor::Map::T1_SAIL, Cursor::Map::T2_SAIL, Cursor::Map::T3_SAIL, Cursor::Map::T4_SAIL, }; + std::array cursorDisembark = { Cursor::Map::T1_DISEMBARK, Cursor::Map::T2_DISEMBARK, Cursor::Map::T3_DISEMBARK, Cursor::Map::T4_DISEMBARK, }; + std::array cursorExchange = { Cursor::Map::T1_EXCHANGE, Cursor::Map::T2_EXCHANGE, Cursor::Map::T3_EXCHANGE, Cursor::Map::T4_EXCHANGE, }; + std::array cursorVisit = { Cursor::Map::T1_VISIT, Cursor::Map::T2_VISIT, Cursor::Map::T3_VISIT, Cursor::Map::T4_VISIT, }; + std::array cursorSailVisit = { Cursor::Map::T1_SAIL_VISIT, Cursor::Map::T2_SAIL_VISIT, Cursor::Map::T3_SAIL_VISIT, Cursor::Map::T4_SAIL_VISIT, }; + + const CGPathNode * pathNode = LOCPLINT->cb->getPathsInfo(hero)->getPathInfo(mapPos); + assert(pathNode); + + if(LOCPLINT->altPressed() && pathNode->reachable()) //overwrite status bar text with movement info + { + ShowMoveDetailsInStatusbar(*hero, *pathNode); + } + + int turns = pathNode->turns; + vstd::amin(turns, 3); + switch(pathNode->action) + { + case CGPathNode::NORMAL: + case CGPathNode::TELEPORT_NORMAL: + if(pathNode->layer == EPathfindingLayer::LAND) + CCS->curh->set(cursorMove[turns]); + else + CCS->curh->set(cursorSailVisit[turns]); + break; + + case CGPathNode::VISIT: + case CGPathNode::BLOCKING_VISIT: + case CGPathNode::TELEPORT_BLOCKING_VISIT: + if(objAtTile && objAtTile->ID == Obj::HERO) + { + if(selection == objAtTile) + CCS->curh->set(Cursor::Map::HERO); + else + CCS->curh->set(cursorExchange[turns]); + } + else if(pathNode->layer == EPathfindingLayer::LAND) + CCS->curh->set(cursorVisit[turns]); + else + CCS->curh->set(cursorSailVisit[turns]); + break; + + case CGPathNode::BATTLE: + case CGPathNode::TELEPORT_BATTLE: + CCS->curh->set(cursorAttack[turns]); + break; + + case CGPathNode::EMBARK: + CCS->curh->set(cursorSail[turns]); + break; + + case CGPathNode::DISEMBARK: + CCS->curh->set(cursorDisembark[turns]); + break; + + default: + if(objAtTile && objRelations != PlayerRelations::ENEMIES) + { + if(objAtTile->ID == Obj::TOWN) + CCS->curh->set(Cursor::Map::TOWN); + else if(objAtTile->ID == Obj::HERO && objRelations == PlayerRelations::SAME_PLAYER) + CCS->curh->set(Cursor::Map::HERO); + else + CCS->curh->set(Cursor::Map::POINTER); + } + else + CCS->curh->set(Cursor::Map::POINTER); + break; + } + } + + if(ourInaccessibleShipyard(objAtTile)) + { + CCS->curh->set(Cursor::Map::T1_SAIL); + } +} + +void CAdvMapInt::ShowMoveDetailsInStatusbar(const CGHeroInstance & hero, const CGPathNode & pathNode) +{ + const int maxMovementPointsAtStartOfLastTurn = pathNode.turns > 0 ? hero.maxMovePoints(pathNode.layer == EPathfindingLayer::LAND) : hero.movement; + const int movementPointsLastTurnCost = maxMovementPointsAtStartOfLastTurn - pathNode.moveRemains; + const int remainingPointsAfterMove = pathNode.turns == 0 ? pathNode.moveRemains : 0; + + std::string result = VLC->generaltexth->translate("vcmi.adventureMap", pathNode.turns > 0 ? "moveCostDetails" : "moveCostDetailsNoTurns"); + + boost::replace_first(result, "%TURNS", std::to_string(pathNode.turns)); + boost::replace_first(result, "%POINTS", std::to_string(movementPointsLastTurnCost)); + boost::replace_first(result, "%REMAINING", std::to_string(remainingPointsAfterMove)); + + statusbar->write(result); +} + +void CAdvMapInt::tileRClicked(const int3 &mapPos) +{ + if(mode != EAdvMapMode::NORMAL) + return; + if(spellBeingCasted) + { + leaveCastingMode(); + return; + } + if(!LOCPLINT->cb->isVisible(mapPos)) + { + CRClickPopup::createAndPush(VLC->generaltexth->allTexts[61]); //Uncharted Territory + return; + } + + const CGObjectInstance * obj = getActiveObject(mapPos); + if(!obj) + { + // Bare or undiscovered terrain + const TerrainTile * tile = LOCPLINT->cb->getTile(mapPos); + if (tile) + { + std::string hlp; + CGI->mh->getTerrainDescr(mapPos, hlp, true); + CRClickPopup::createAndPush(hlp); + } + return; + } + + CRClickPopup::createAndPush(obj, GH.getCursorPosition(), ETextAlignment::CENTER); +} + +void CAdvMapInt::enterCastingMode(const CSpell * sp) +{ + assert(sp->id == SpellID::SCUTTLE_BOAT || sp->id == SpellID::DIMENSION_DOOR); + spellBeingCasted = sp; + + deactivate(); + terrain.activate(); + GH.fakeMouseMove(); +} + +void CAdvMapInt::leaveCastingMode(bool cast, int3 dest) +{ + assert(spellBeingCasted); + SpellID id = spellBeingCasted->id; + spellBeingCasted = nullptr; + terrain.deactivate(); + activate(); + + if(cast) + LOCPLINT->cb->castSpell(curHero(), id, dest); + else + LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[731]); //Spell cancelled +} + +const CGHeroInstance * CAdvMapInt::curHero() const +{ + if(selection && selection->ID == Obj::HERO) + return static_cast(selection); + else + return nullptr; +} + +const CGTownInstance * CAdvMapInt::curTown() const +{ + if(selection && selection->ID == Obj::TOWN) + return static_cast(selection); + else + return nullptr; +} + +const IShipyard * CAdvMapInt::ourInaccessibleShipyard(const CGObjectInstance *obj) const +{ + const IShipyard *ret = IShipyard::castFrom(obj); + + if(!ret || + obj->tempOwner != player || + (CCS->curh->get() != Cursor::Map::T1_SAIL && CCS->curh->get() != Cursor::Map::POINTER)) + return nullptr; + + return ret; +} + +void CAdvMapInt::aiTurnStarted() +{ + if(settings["session"]["spectate"].Bool()) + return; + + adjustActiveness(true); + CCS->musich->playMusicFromSet("enemy-turn", true, false); + adventureInt->minimap.setAIRadar(true); + adventureInt->infoBar.startEnemyTurn(LOCPLINT->cb->getCurrentPlayer()); + adventureInt->infoBar.showAll(screen);//force refresh on inactive object +} + +void CAdvMapInt::adjustActiveness(bool aiTurnStart) +{ + bool wasActive = isActive(); + + if(wasActive) + deactivate(); + adventureInt->duringAITurn = aiTurnStart; + if(wasActive) + activate(); +} + +void CAdvMapInt::quickCombatLock() +{ + if(!duringAITurn) + deactivate(); +} + +void CAdvMapInt::quickCombatUnlock() +{ + if(!duringAITurn) + activate(); +} + +void CAdvMapInt::changeMode(EAdvMapMode newMode, float newScale) +{ + if (mode != newMode) + { + mode = newMode; + + switch (mode) + { + case EAdvMapMode::NORMAL: + panelMain->activate(); + panelWorldView->deactivate(); + activeMapPanel = panelMain; + + townList.activate(); + heroList.activate(); + infoBar.activate(); + + worldViewOptions.clear(); + + break; + case EAdvMapMode::WORLD_VIEW: + panelMain->deactivate(); + panelWorldView->activate(); + + activeMapPanel = panelWorldView; + + townList.deactivate(); + heroList.deactivate(); + infoBar.showSelection(); // to prevent new day animation interfering world view mode + infoBar.deactivate(); + + break; + } + worldViewScale = newScale; + redraw(); + } + else if (worldViewScale != newScale) // still in world view mode, but the scale changed + { + worldViewScale = newScale; + redraw(); + } +} + +CAdventureOptions::CAdventureOptions() + : CWindowObject(PLAYER_COLORED, "ADVOPTS") +{ + OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); + + viewWorld = std::make_shared(Point(24, 23), "ADVVIEW.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_v); + viewWorld->addCallback(std::bind(&CPlayerInterface::viewWorldMap, LOCPLINT)); + + exit = std::make_shared(Point(204, 313), "IOK6432.DEF", CButton::tooltip(), std::bind(&CAdventureOptions::close, this), SDLK_RETURN); + exit->assignedKeys.insert(SDLK_ESCAPE); + + scenInfo = std::make_shared(Point(24, 198), "ADVINFO.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_i); + scenInfo->addCallback(CAdventureOptions::showScenarioInfo); + + puzzle = std::make_shared(Point(24, 81), "ADVPUZ.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_p); + puzzle->addCallback(std::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT)); + + dig = std::make_shared(Point(24, 139), "ADVDIG.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_d); + if(const CGHeroInstance *h = adventureInt->curHero()) + dig->addCallback(std::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h)); + else + dig->block(true); +} + +void CAdventureOptions::showScenarioInfo() +{ + if(LOCPLINT->cb->getStartInfo()->campState) + { + GH.pushIntT(); + } + else + { + GH.pushIntT(); + } +} + +CAdvMapInt::WorldViewOptions::WorldViewOptions() +{ + clear(); +} + +void CAdvMapInt::WorldViewOptions::clear() +{ + showAllTerrain = false; + + iconPositions.clear(); +} + +void CAdvMapInt::WorldViewOptions::adjustDrawingInfo(MapDrawingInfo& info) +{ + info.showAllTerrain = showAllTerrain; + + info.additionalIcons = &iconPositions; +} diff --git a/client/adventureMap/CAdvmapInterface.h b/client/adventureMap/CAdvmapInterface.h new file mode 100644 index 000000000..6b1ae0ddc --- /dev/null +++ b/client/adventureMap/CAdvmapInterface.h @@ -0,0 +1,276 @@ +/* + * CAdvmapInterface.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include "../widgets/AdventureMapClasses.h" +#include "CWindowObject.h" + +#include "../widgets/TextControls.h" +#include "../widgets/Buttons.h" + +#include "../../lib/spells/ViewSpellInt.h" + +VCMI_LIB_NAMESPACE_BEGIN + +struct CGPath; +struct CGPathNode; +class CGHeroInstance; +class CGTownInstance; +class CSpell; +class IShipyard; + +VCMI_LIB_NAMESPACE_END + +class CCallback; +class CAdvMapInt; +class CHeroWindow; +enum class EMapAnimRedrawStatus; +class CFadeAnimation; + +struct MapDrawingInfo; + +/*****************************/ + +enum class EAdvMapMode +{ + NORMAL, + WORLD_VIEW +}; + +/// Adventure options dialog where you can view the world, dig, play the replay of the last turn,... +class CAdventureOptions : public CWindowObject +{ +public: + std::shared_ptr exit; + std::shared_ptr viewWorld; + std::shared_ptr puzzle; + std::shared_ptr dig; + std::shared_ptr scenInfo; + /*std::shared_ptr replay*/ + + CAdventureOptions(); + static void showScenarioInfo(); +}; + +/// Holds information about which tiles of the terrain are shown/not shown at the screen +class CTerrainRect : public CIntObject +{ + SDL_Surface * fadeSurface; + EMapAnimRedrawStatus lastRedrawStatus; + std::shared_ptr fadeAnim; + + int3 swipeInitialMapPos; + int3 swipeInitialRealPos; + bool isSwiping; + static constexpr float SwipeTouchSlop = 16.0f; + + void handleHover(const SDL_MouseMotionEvent & sEvent); + void handleSwipeMove(const SDL_MouseMotionEvent & sEvent); + /// handles start/finish of swipe (press/release of corresponding button); returns true if state change was handled + bool handleSwipeStateChange(bool btnPressed); +public: + int tilesw, tilesh; //width and height of terrain to blit in tiles + int3 curHoveredTile; + int moveX, moveY; //shift between actual position of screen and the one we wil blit; ranges from -31 to 31 (in pixels) + CGPath * currentPath; + + CTerrainRect(); + virtual ~CTerrainRect(); + void deactivate() override; + void clickLeft(tribool down, bool previousState) override; + void clickRight(tribool down, bool previousState) override; + void clickMiddle(tribool down, bool previousState) override; + void hover(bool on) override; + void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; + void show(SDL_Surface * to) override; + void showAll(SDL_Surface * to) override; + void showAnim(SDL_Surface * to); + void showPath(const Rect &extRect, SDL_Surface * to); + int3 whichTileIsIt(const int x, const int y); //x,y are cursor position + int3 whichTileIsIt(); //uses current cursor pos + /// @returns number of visible tiles on screen respecting current map scaling + int3 tileCountOnScreen(); + /// animates view by caching current surface and crossfading it with normal screen + void fadeFromCurrentView(); + bool needsAnimUpdate(); +}; + +/// Resources bar which shows information about how many gold, crystals,... you have +/// Current date is displayed too +class CResDataBar : public CIntObject +{ +public: + std::shared_ptr background; + + std::vector > txtpos; + std::string datetext; + + void clickRight(tribool down, bool previousState) override; + CResDataBar(); + CResDataBar(const std::string &defname, int x, int y, int offx, int offy, int resdist, int datedist); + ~CResDataBar(); + + void draw(SDL_Surface * to); + void show(SDL_Surface * to) override; + void showAll(SDL_Surface * to) override; +}; + +/// That's a huge class which handles general adventure map actions and +/// shows the right menu(questlog, spellbook, end turn,..) from where you +/// can get to the towns and heroes. +class CAdvMapInt : public CIntObject +{ + //Return object that must be active at this tile (=clickable) + const CGObjectInstance *getActiveObject(const int3 &tile); + +public: + CAdvMapInt(); + + int3 position; //top left corner of visible map part + PlayerColor player; + + bool duringAITurn; + + enum{LEFT=1, RIGHT=2, UP=4, DOWN=8}; + ui8 scrollingDir; //uses enum: LEFT RIGHT, UP, DOWN + bool scrollingState; + bool swipeEnabled; + bool swipeMovementRequested; + int3 swipeTargetPosition; + + enum{NA, INGAME, WAITING} state; + + bool updateScreen; + ui8 anim, animValHitCount; //animation frame + ui8 heroAnim, heroAnimValHitCount; //animation frame + + EAdvMapMode mode; + float worldViewScale; + + struct WorldViewOptions + { + bool showAllTerrain; //for expert viewEarth + + std::vector iconPositions; + + WorldViewOptions(); + + void clear(); + + void adjustDrawingInfo(MapDrawingInfo & info); + }; + + WorldViewOptions worldViewOptions; + + std::shared_ptr bg; + std::shared_ptr bgWorldView; + std::vector> gems; + CMinimap minimap; + std::shared_ptr statusbar; + + std::shared_ptr kingOverview; + std::shared_ptr underground; + std::shared_ptr questlog; + std::shared_ptr sleepWake; + std::shared_ptr moveHero; + std::shared_ptr spellbook; + std::shared_ptr advOptions; + std::shared_ptr sysOptions; + std::shared_ptr nextHero; + std::shared_ptr endTurn; + + std::shared_ptr worldViewUnderground; + + CTerrainRect terrain; //visible terrain + CResDataBar resdatabar; + CHeroList heroList; + CTownList townList; + CInfoBar infoBar; + + std::shared_ptr panelMain; // panel that holds all right-side buttons in normal view + std::shared_ptr panelWorldView; // panel that holds all buttons and other ui in world view + std::shared_ptr activeMapPanel; // currently active panel (either main or world view, depending on current mode) + + std::shared_ptr worldViewIcons;// images for world view overlay + + const CSpell *spellBeingCasted; //nullptr if none + + const CArmedInstance *selection; //currently selected town/hero + + //functions bound to buttons + void fshowOverview(); + void fworldViewBack(); + void fworldViewScale1x(); + void fworldViewScale2x(); + void fworldViewScale4x(); + void fswitchLevel(); + void fshowQuestlog(); + void fsleepWake(); + void fmoveHero(); + void fshowSpellbok(); + void fadventureOPtions(); + void fsystemOptions(); + void fnextHero(); + void fendTurn(); + + void activate() override; + void deactivate() override; + + void show(SDL_Surface * to) override; //redraws terrain + void showAll(SDL_Surface * to) override; //shows and activates adv. map interface + + void select(const CArmedInstance *sel, bool centerView = true); + void selectionChanged(); + void centerOn(int3 on, bool fade = false); + void centerOn(const CGObjectInstance *obj, bool fade = false); + int3 verifyPos(int3 ver); + void handleRightClick(std::string text, tribool down); + void keyPressed(const SDL_KeyboardEvent & key) override; + void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; + bool isActive(); + + bool isHeroSleeping(const CGHeroInstance *hero); + void setHeroSleeping(const CGHeroInstance *hero, bool sleep); + int getNextHeroIndex(int startIndex); //for Next Hero button - cycles awake heroes with movement only + + void setPlayer(PlayerColor Player); + void startHotSeatWait(PlayerColor Player); + void startTurn(); + void endingTurn(); + void aiTurnStarted(); + + void adjustActiveness(bool aiTurnStart); //should be called every time at AI/human turn transition; blocks GUI during AI turn + void quickCombatLock(); //should be called when quick battle started + void quickCombatUnlock(); + void tileLClicked(const int3 &mapPos); + void tileHovered(const int3 &mapPos); + void tileRClicked(const int3 &mapPos); + void enterCastingMode(const CSpell * sp); + void leaveCastingMode(bool cast = false, int3 dest = int3(-1, -1, -1)); + const CGHeroInstance * curHero() const; + const CGTownInstance * curTown() const; + const IShipyard * ourInaccessibleShipyard(const CGObjectInstance *obj) const; //checks if obj is our ashipyard and cursor is 0,0 -> returns shipyard or nullptr else + //button updates + void updateSleepWake(const CGHeroInstance *h); + void updateMoveHero(const CGHeroInstance *h, tribool hasPath = boost::logic::indeterminate); + void updateSpellbook(const CGHeroInstance *h); + void updateNextHero(const CGHeroInstance *h); + + /// changes current adventure map mode; used to switch between default view and world view; scale is ignored if EAdvMapMode == NORMAL + void changeMode(EAdvMapMode newMode, float newScale = 0.36f); + + void handleMapScrollingUpdate(); + void handleSwipeUpdate(); + +private: + void ShowMoveDetailsInStatusbar(const CGHeroInstance & hero, const CGPathNode & pathNode); +}; + +extern std::shared_ptr adventureInt; From 540921b96dd2d2169015a34860afae69e7c5336c Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:15:52 +0200 Subject: [PATCH 53/79] Moved CAdventureOptions into a separate file --- .../adventureMap/{CAdvmapInterface.cpp => CAdventureOptions.cpp} | 0 client/adventureMap/{CAdvmapInterface.h => CAdventureOptions.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/adventureMap/{CAdvmapInterface.cpp => CAdventureOptions.cpp} (100%) rename client/adventureMap/{CAdvmapInterface.h => CAdventureOptions.h} (100%) diff --git a/client/adventureMap/CAdvmapInterface.cpp b/client/adventureMap/CAdventureOptions.cpp similarity index 100% rename from client/adventureMap/CAdvmapInterface.cpp rename to client/adventureMap/CAdventureOptions.cpp diff --git a/client/adventureMap/CAdvmapInterface.h b/client/adventureMap/CAdventureOptions.h similarity index 100% rename from client/adventureMap/CAdvmapInterface.h rename to client/adventureMap/CAdventureOptions.h From aaf981a6dcaf187b7b9416aad2f8f1ff5b7e99eb Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:16:07 +0200 Subject: [PATCH 54/79] Restore CAdvMapInterface --- client/adventureMap/CAdvmapInterface.cpp | 2021 ++++++++++++++++++++++ client/adventureMap/CAdvmapInterface.h | 276 +++ 2 files changed, 2297 insertions(+) create mode 100644 client/adventureMap/CAdvmapInterface.cpp create mode 100644 client/adventureMap/CAdvmapInterface.h diff --git a/client/adventureMap/CAdvmapInterface.cpp b/client/adventureMap/CAdvmapInterface.cpp new file mode 100644 index 000000000..d0529f744 --- /dev/null +++ b/client/adventureMap/CAdvmapInterface.cpp @@ -0,0 +1,2021 @@ +/* + * CAdvmapInterface.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#include "StdInc.h" +#include "CAdvmapInterface.h" + +#include "CCastleInterface.h" +#include "CHeroWindow.h" +#include "CKingdomInterface.h" +#include "CSpellWindow.h" +#include "CTradeWindow.h" +#include "GUIClasses.h" +#include "InfoWindows.h" + +#include "../CBitmapHandler.h" +#include "../CGameInfo.h" +#include "../CMessage.h" +#include "../CMusicHandler.h" +#include "../CPlayerInterface.h" +#include "../mainmenu/CMainMenu.h" +#include "../lobby/CSelectionBase.h" +#include "../lobby/CCampaignInfoScreen.h" +#include "../lobby/CSavingScreen.h" +#include "../lobby/CScenarioInfoScreen.h" +#include "../Graphics.h" +#include "../mapHandler.h" + +#include "../gui/CAnimation.h" +#include "../gui/CursorHandler.h" +#include "../gui/CGuiHandler.h" +#include "../gui/SDL_Extensions.h" +#include "../widgets/MiscWidgets.h" + +#include "../../CCallback.h" + +#include "../../lib/CConfigHandler.h" +#include "../../lib/CGameState.h" +#include "../../lib/CGeneralTextHandler.h" +#include "../../lib/CHeroHandler.h" +#include "../../lib/CSoundBase.h" +#include "../../lib/spells/CSpellHandler.h" +#include "../../lib/CTownHandler.h" +#include "../../lib/JsonNode.h" +#include "../../lib/mapObjects/CGHeroInstance.h" +#include "../../lib/mapping/CMap.h" +#include "../../lib/UnlockGuard.h" +#include "../../lib/VCMI_Lib.h" +#include "../../lib/StartInfo.h" +#include "../../lib/mapping/CMapInfo.h" +#include "../../lib/TerrainHandler.h" + +#include +#include + +#define ADVOPT (conf.go()->ac) +using namespace CSDL_Ext; + +std::shared_ptr adventureInt; + +static void setScrollingCursor(ui8 direction) +{ + if(direction & CAdvMapInt::RIGHT) + { + if(direction & CAdvMapInt::UP) + CCS->curh->set(Cursor::Map::SCROLL_NORTHEAST); + else if(direction & CAdvMapInt::DOWN) + CCS->curh->set(Cursor::Map::SCROLL_SOUTHEAST); + else + CCS->curh->set(Cursor::Map::SCROLL_EAST); + } + else if(direction & CAdvMapInt::LEFT) + { + if(direction & CAdvMapInt::UP) + CCS->curh->set(Cursor::Map::SCROLL_NORTHWEST); + else if(direction & CAdvMapInt::DOWN) + CCS->curh->set(Cursor::Map::SCROLL_SOUTHWEST); + else + CCS->curh->set(Cursor::Map::SCROLL_WEST); + } + else if(direction & CAdvMapInt::UP) + CCS->curh->set(Cursor::Map::SCROLL_NORTH); + else if(direction & CAdvMapInt::DOWN) + CCS->curh->set(Cursor::Map::SCROLL_SOUTH); +} + +CTerrainRect::CTerrainRect() + : fadeSurface(nullptr), + lastRedrawStatus(EMapAnimRedrawStatus::OK), + fadeAnim(std::make_shared()), + curHoveredTile(-1,-1,-1), + currentPath(nullptr) +{ + tilesw=(ADVOPT.advmapW+31)/32; + tilesh=(ADVOPT.advmapH+31)/32; + pos.x=ADVOPT.advmapX; + pos.y=ADVOPT.advmapY; + pos.w=ADVOPT.advmapW; + pos.h=ADVOPT.advmapH; + moveX = moveY = 0; + addUsedEvents(LCLICK | RCLICK | MCLICK | HOVER | MOVE); +} + +CTerrainRect::~CTerrainRect() +{ + if(fadeSurface) + SDL_FreeSurface(fadeSurface); +} + +void CTerrainRect::deactivate() +{ + CIntObject::deactivate(); + curHoveredTile = int3(-1,-1,-1); //we lost info about hovered tile when disabling +} + +void CTerrainRect::clickLeft(tribool down, bool previousState) +{ + if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) + return; + if(indeterminate(down)) + return; + +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + if(adventureInt->swipeEnabled) + { + if(handleSwipeStateChange((bool)down == true)) + { + return; // if swipe is enabled, we don't process "down" events and wait for "up" (to make sure this wasn't a swiping gesture) + } + } + else + { +#endif + if(down == false) + return; +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + } +#endif + int3 mp = whichTileIsIt(); + if(mp.x < 0 || mp.y < 0 || mp.x >= LOCPLINT->cb->getMapSize().x || mp.y >= LOCPLINT->cb->getMapSize().y) + return; + + adventureInt->tileLClicked(mp); +} + +void CTerrainRect::clickRight(tribool down, bool previousState) +{ +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + if(adventureInt->swipeEnabled && isSwiping) + return; +#endif + if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) + return; + int3 mp = whichTileIsIt(); + + if(CGI->mh->map->isInTheMap(mp) && down) + adventureInt->tileRClicked(mp); +} + +void CTerrainRect::clickMiddle(tribool down, bool previousState) +{ + handleSwipeStateChange((bool)down == true); +} + +void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent) +{ + handleHover(sEvent); + + if(!adventureInt->swipeEnabled) + return; + + handleSwipeMove(sEvent); +} + +void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent) +{ +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + if(sEvent.state == 0 || GH.multifinger) // any "button" is enough on mobile +#else + if((sEvent.state & SDL_BUTTON_MMASK) == 0) // swipe only works with middle mouse on other platforms +#endif + { + return; + } + + if(!isSwiping) + { + // try to distinguish if this touch was meant to be a swipe or just fat-fingering press + if(abs(sEvent.x - swipeInitialRealPos.x) > SwipeTouchSlop || + abs(sEvent.y - swipeInitialRealPos.y) > SwipeTouchSlop) + { + isSwiping = true; + } + } + + if(isSwiping) + { + adventureInt->swipeTargetPosition.x = + swipeInitialMapPos.x + static_cast(swipeInitialRealPos.x - sEvent.x) / 32; + adventureInt->swipeTargetPosition.y = + swipeInitialMapPos.y + static_cast(swipeInitialRealPos.y - sEvent.y) / 32; + adventureInt->swipeMovementRequested = true; + } +} + +bool CTerrainRect::handleSwipeStateChange(bool btnPressed) +{ + if(btnPressed) + { + swipeInitialRealPos = int3(GH.getCursorPosition().x, GH.getCursorPosition().y, 0); + swipeInitialMapPos = int3(adventureInt->position); + return true; + } + else if(isSwiping) // only accept this touch if it wasn't a swipe + { + isSwiping = false; + return true; + } + return false; +} + +void CTerrainRect::handleHover(const SDL_MouseMotionEvent &sEvent) +{ + int3 tHovered = whichTileIsIt(sEvent.x, sEvent.y); + int3 pom = adventureInt->verifyPos(tHovered); + + if(tHovered != pom) //tile outside the map + { + CCS->curh->set(Cursor::Map::POINTER); + return; + } + + if (pom != curHoveredTile) + { + curHoveredTile = pom; + adventureInt->tileHovered(pom); + } +} + +void CTerrainRect::hover(bool on) +{ + if (!on) + { + adventureInt->statusbar->clear(); + CCS->curh->set(Cursor::Map::POINTER); + } + //Hoverable::hover(on); +} +void CTerrainRect::showPath(const Rect & extRect, SDL_Surface * to) +{ + const static int pns[9][9] = { + {16, 17, 18, 7, -1, 19, 6, 5, -1}, + { 8, 9, 18, 7, -1, 19, 6, -1, 20}, + { 8, 1, 10, 7, -1, 19, -1, 21, 20}, + {24, 17, 18, 15, -1, -1, 6, 5, 4}, + {-1, -1, -1, -1, -1, -1, -1, -1, -1}, + { 8, 1, 2, -1, -1, 11, 22, 21, 20}, + {24, 17, -1, 23, -1, 3, 14, 5, 4}, + {24, -1, 2, 23, -1, 3, 22, 13, 4}, + {-1, 1, 2, 23, -1, 3, 22, 21, 12} + }; //table of magic values TODO meaning, change variable name + + for (int i = 0; i < -1 + (int)currentPath->nodes.size(); ++i) + { + const int3 &curPos = currentPath->nodes[i].coord, &nextPos = currentPath->nodes[i+1].coord; + if(curPos.z != adventureInt->position.z) + continue; + + int pn=-1;//number of picture + if (i==0) //last tile + { + int x = 32*(curPos.x-adventureInt->position.x)+CGI->mh->offsetX + pos.x, + y = 32*(curPos.y-adventureInt->position.y)+CGI->mh->offsetY + pos.y; + if (x<0 || y<0 || x>pos.w || y>pos.h) + continue; + pn=0; + } + else + { + const int3 &prevPos = currentPath->nodes[i-1].coord; + std::vector & cv = currentPath->nodes; + + /* Vector directions + * 0 1 2 + * \ | / + * 3 - 4 - 5 + * / | \ + * 6 7 8 + *For example: + * | + * |__\ + * / + * is id1=7, id2=5 (pns[7][5]) + */ + bool pathContinuous = curPos.areNeighbours(nextPos) && curPos.areNeighbours(prevPos); + if(pathContinuous && cv[i].action != CGPathNode::EMBARK && cv[i].action != CGPathNode::DISEMBARK) + { + int id1=(curPos.x-nextPos.x+1)+3*(curPos.y-nextPos.y+1); //Direction of entering vector + int id2=(cv[i-1].coord.x-curPos.x+1)+3*(cv[i-1].coord.y-curPos.y+1); //Direction of exiting vector + pn=pns[id1][id2]; + } + else //path discontinuity or sea/land transition (eg. when moving through Subterranean Gate or Boat) + { + pn = 0; + } + } + if (currentPath->nodes[i].turns) + pn+=25; + if (pn>=0) + { + const auto arrow = graphics->heroMoveArrows->getImage(pn); + + int x = 32*(curPos.x-adventureInt->position.x)+CGI->mh->offsetX + pos.x, + y = 32*(curPos.y-adventureInt->position.y)+CGI->mh->offsetY + pos.y; + if (x< -32 || y< -32 || x>pos.w || y>pos.h) + continue; + int hvx = (x + arrow->width()) - (pos.x + pos.w), + hvy = (y + arrow->height()) - (pos.y + pos.h); + + Rect prevClip; + CSDL_Ext::getClipRect(to, prevClip); + CSDL_Ext::setClipRect(to, extRect); //preventing blitting outside of that rect + + if(ADVOPT.smoothMove) //version for smooth hero move, with pos shifts + { + if (hvx<0 && hvy<0) + { + arrow->draw(to, x + moveX, y + moveY); + } + else if(hvx<0) + { + Rect srcRect = genRect(arrow->height() - hvy, arrow->width(), 0, 0); + arrow->draw(to, x + moveX, y + moveY, &srcRect); + } + else if (hvy<0) + { + Rect srcRect = genRect(arrow->height(), arrow->width() - hvx, 0, 0); + arrow->draw(to, x + moveX, y + moveY, &srcRect); + } + else + { + Rect srcRect = genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); + arrow->draw(to, x + moveX, y + moveY, &srcRect); + } + } + else //standard version + { + if (hvx<0 && hvy<0) + { + arrow->draw(to, x, y); + } + else if(hvx<0) + { + Rect srcRect = genRect(arrow->height() - hvy, arrow->width(), 0, 0); + arrow->draw(to, x, y, &srcRect); + } + else if (hvy<0) + { + Rect srcRect = genRect(arrow->height(), arrow->width() - hvx, 0, 0); + arrow->draw(to, x, y, &srcRect); + } + else + { + Rect srcRect = genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); + arrow->draw(to, x, y, &srcRect); + } + } + CSDL_Ext::setClipRect(to, prevClip); + + } + } //for (int i=0;inodes.size()-1;i++) +} + +void CTerrainRect::show(SDL_Surface * to) +{ + if (adventureInt->mode == EAdvMapMode::NORMAL) + { + MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), pos); + info.otherheroAnim = true; + info.anim = adventureInt->anim; + info.heroAnim = adventureInt->heroAnim; + if (ADVOPT.smoothMove) + info.movement = int3(moveX, moveY, 0); + + lastRedrawStatus = CGI->mh->drawTerrainRectNew(to, &info); + if (fadeAnim->isFading()) + { + Rect r(pos); + fadeAnim->update(); + fadeAnim->draw(to, r.topLeft()); + } + + if (currentPath/* && adventureInt->position.z==currentPath->startPos().z*/) //drawing path + { + showPath(pos, to); + } + } +} + +void CTerrainRect::showAll(SDL_Surface * to) +{ + // world view map is static and doesn't need redraw every frame + if (adventureInt->mode == EAdvMapMode::WORLD_VIEW) + { + MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), pos, adventureInt->worldViewIcons); + info.scaled = true; + info.scale = adventureInt->worldViewScale; + adventureInt->worldViewOptions.adjustDrawingInfo(info); + CGI->mh->drawTerrainRectNew(to, &info); + } +} + +void CTerrainRect::showAnim(SDL_Surface * to) +{ + if (fadeAnim->isFading()) + show(to); + else if (lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED) + show(to); // currently the same; maybe we should pass some flag to map handler so it redraws ONLY tiles that need redraw instead of full +} + +int3 CTerrainRect::whichTileIsIt(const int x, const int y) +{ + int3 ret; + ret.x = adventureInt->position.x + ((x-CGI->mh->offsetX-pos.x)/32); + ret.y = adventureInt->position.y + ((y-CGI->mh->offsetY-pos.y)/32); + ret.z = adventureInt->position.z; + return ret; +} + +int3 CTerrainRect::whichTileIsIt() +{ + return whichTileIsIt(GH.getCursorPosition().x, GH.getCursorPosition().y); +} + +int3 CTerrainRect::tileCountOnScreen() +{ + switch (adventureInt->mode) + { + default: + logGlobal->error("Unknown map mode %d", (int)adventureInt->mode); + return int3(); + case EAdvMapMode::NORMAL: + return int3(tilesw, tilesh, 1); + case EAdvMapMode::WORLD_VIEW: + return int3((si32)(tilesw / adventureInt->worldViewScale), (si32)(tilesh / adventureInt->worldViewScale), 1); + } +} + +void CTerrainRect::fadeFromCurrentView() +{ + if (!ADVOPT.screenFading) + return; + if (adventureInt->mode == EAdvMapMode::WORLD_VIEW) + return; + + if (!fadeSurface) + fadeSurface = CSDL_Ext::newSurface(pos.w, pos.h); + CSDL_Ext::blitSurface(screen, fadeSurface, Point(0,0)); + fadeAnim->init(CFadeAnimation::EMode::OUT, fadeSurface); +} + +bool CTerrainRect::needsAnimUpdate() +{ + return fadeAnim->isFading() || lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED; +} + +void CResDataBar::clickRight(tribool down, bool previousState) +{ +} + +CResDataBar::CResDataBar(const std::string & defname, int x, int y, int offx, int offy, int resdist, int datedist) +{ + pos.x += x; + pos.y += y; + OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); + background = std::make_shared(defname, 0, 0); + background->colorize(LOCPLINT->playerID); + + pos.w = background->pos.w; + pos.h = background->pos.h; + + txtpos.resize(8); + for (int i = 0; i < 8 ; i++) + { + txtpos[i].first = pos.x + offx + resdist*i; + txtpos[i].second = pos.y + offy; + } + txtpos[7].first = txtpos[6].first + datedist; + datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] + + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s"; + addUsedEvents(RCLICK); +} + +CResDataBar::CResDataBar() +{ + pos.x += ADVOPT.resdatabarX; + pos.y += ADVOPT.resdatabarY; + + OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); + background = std::make_shared(ADVOPT.resdatabarG, 0, 0); + background->colorize(LOCPLINT->playerID); + + pos.w = background->pos.w; + pos.h = background->pos.h; + + txtpos.resize(8); + for (int i = 0; i < 8 ; i++) + { + txtpos[i].first = pos.x + ADVOPT.resOffsetX + ADVOPT.resDist*i; + txtpos[i].second = pos.y + ADVOPT.resOffsetY; + } + txtpos[7].first = txtpos[6].first + ADVOPT.resDateDist; + datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] + + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s"; +} + +CResDataBar::~CResDataBar() = default; + +void CResDataBar::draw(SDL_Surface * to) +{ + //TODO: all this should be labels, but they require proper text update on change + for (auto i=Res::WOOD; i<=Res::GOLD; vstd::advance(i, 1)) + { + std::string text = boost::lexical_cast(LOCPLINT->cb->getResourceAmount(i)); + + graphics->fonts[FONT_SMALL]->renderTextLeft(to, text, Colors::WHITE, Point(txtpos[i].first,txtpos[i].second)); + } + std::vector temp; + + temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::MONTH))); + temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::WEEK))); + temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK))); + + graphics->fonts[FONT_SMALL]->renderTextLeft(to, processStr(datetext,temp), Colors::WHITE, Point(txtpos[7].first,txtpos[7].second)); +} + +void CResDataBar::show(SDL_Surface * to) +{ + +} + +void CResDataBar::showAll(SDL_Surface * to) +{ + CIntObject::showAll(to); + draw(to); +} + +CAdvMapInt::CAdvMapInt(): + mode(EAdvMapMode::NORMAL), + worldViewScale(0.0f), //actual init later in changeMode + minimap(Rect(ADVOPT.minimapX, ADVOPT.minimapY, ADVOPT.minimapW, ADVOPT.minimapH)), + statusbar(CGStatusBar::create(ADVOPT.statusbarX,ADVOPT.statusbarY,ADVOPT.statusbarG)), + heroList(ADVOPT.hlistSize, Point(ADVOPT.hlistX, ADVOPT.hlistY), ADVOPT.hlistAU, ADVOPT.hlistAD), + townList(ADVOPT.tlistSize, Point(ADVOPT.tlistX, ADVOPT.tlistY), ADVOPT.tlistAU, ADVOPT.tlistAD), + infoBar(Rect(ADVOPT.infoboxX, ADVOPT.infoboxY, 192, 192)), state(NA), + spellBeingCasted(nullptr), position(int3(0, 0, 0)), selection(nullptr), + updateScreen(false), anim(0), animValHitCount(0), heroAnim(0), heroAnimValHitCount(0), + activeMapPanel(nullptr), duringAITurn(false), scrollingDir(0), scrollingState(false), + swipeEnabled(settings["general"]["swipe"].Bool()), swipeMovementRequested(false), + swipeTargetPosition(int3(-1, -1, -1)) +{ + pos.x = pos.y = 0; + pos.w = screen->w; + pos.h = screen->h; + strongInterest = true; // handle all mouse move events to prevent dead mouse move space in fullscreen mode + townList.onSelect = std::bind(&CAdvMapInt::selectionChanged,this); + bg = IImage::createFromFile(ADVOPT.mainGraphic); + if(!ADVOPT.worldViewGraphic.empty()) + { + bgWorldView = IImage::createFromFile(ADVOPT.worldViewGraphic); + } + else + { + bgWorldView = nullptr; + logGlobal->warn("ADVOPT.worldViewGraphic is empty => bitmap not loaded"); + } + if (!bgWorldView) + { + logGlobal->warn("bgWorldView not defined in resolution config; fallback to VWorld.bmp"); + bgWorldView = IImage::createFromFile("VWorld.bmp"); + } + + worldViewIcons = std::make_shared("VwSymbol");//todo: customize with ADVOPT + worldViewIcons->preload(); + + for(int g = 0; g < ADVOPT.gemG.size(); ++g) + { + gems.push_back(std::make_shared(ADVOPT.gemG[g], 0, 0, ADVOPT.gemX[g], ADVOPT.gemY[g])); + } + + auto makeButton = [&](int textID, std::function callback, config::ButtonInfo info, int key) -> std::shared_ptr + { + auto button = std::make_shared(Point(info.x, info.y), info.defName, CGI->generaltexth->zelp[textID], callback, key, info.playerColoured); + for(auto image : info.additionalDefs) + button->addImage(image); + return button; + }; + + kingOverview = makeButton(293, std::bind(&CAdvMapInt::fshowOverview,this), ADVOPT.kingOverview, SDLK_k); + underground = makeButton(294, std::bind(&CAdvMapInt::fswitchLevel,this), ADVOPT.underground, SDLK_u); + questlog = makeButton(295, std::bind(&CAdvMapInt::fshowQuestlog,this), ADVOPT.questlog, SDLK_q); + sleepWake = makeButton(296, std::bind(&CAdvMapInt::fsleepWake,this), ADVOPT.sleepWake, SDLK_w); + moveHero = makeButton(297, std::bind(&CAdvMapInt::fmoveHero,this), ADVOPT.moveHero, SDLK_m); + spellbook = makeButton(298, std::bind(&CAdvMapInt::fshowSpellbok,this), ADVOPT.spellbook, SDLK_c); + advOptions = makeButton(299, std::bind(&CAdvMapInt::fadventureOPtions,this), ADVOPT.advOptions, SDLK_a); + sysOptions = makeButton(300, std::bind(&CAdvMapInt::fsystemOptions,this), ADVOPT.sysOptions, SDLK_o); + nextHero = makeButton(301, std::bind(&CAdvMapInt::fnextHero,this), ADVOPT.nextHero, SDLK_h); + endTurn = makeButton(302, std::bind(&CAdvMapInt::fendTurn,this), ADVOPT.endTurn, SDLK_e); + + int panelSpaceBottom = screen->h - resdatabar.pos.h - 4; + + panelMain = std::make_shared(nullptr, Point(0, 0)); + // TODO correct drawing position + panelWorldView = std::make_shared(worldViewIcons, bgWorldView, Point(heroList.pos.x - 2, 195), panelSpaceBottom, LOCPLINT->playerID); + + panelMain->addChildColorableButton(kingOverview); + panelMain->addChildColorableButton(underground); + panelMain->addChildColorableButton(questlog); + panelMain->addChildColorableButton(sleepWake); + panelMain->addChildColorableButton(moveHero); + panelMain->addChildColorableButton(spellbook); + panelMain->addChildColorableButton(advOptions); + panelMain->addChildColorableButton(sysOptions); + panelMain->addChildColorableButton(nextHero); + panelMain->addChildColorableButton(endTurn); + + + // TODO move configs to resolutions.json, similarly to previous buttons + config::ButtonInfo worldViewBackConfig = config::ButtonInfo(); + worldViewBackConfig.defName = "IOK6432.DEF"; + worldViewBackConfig.x = screen->w - 73; + worldViewBackConfig.y = 343 + 195; + worldViewBackConfig.playerColoured = false; + panelWorldView->addChildToPanel( + makeButton(288, std::bind(&CAdvMapInt::fworldViewBack,this), worldViewBackConfig, SDLK_ESCAPE), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewPuzzleConfig = config::ButtonInfo(); + worldViewPuzzleConfig.defName = "VWPUZ.DEF"; + worldViewPuzzleConfig.x = screen->w - 188; + worldViewPuzzleConfig.y = 343 + 195; + worldViewPuzzleConfig.playerColoured = false; + panelWorldView->addChildToPanel( // no help text for this one + std::make_shared(Point(worldViewPuzzleConfig.x, worldViewPuzzleConfig.y), worldViewPuzzleConfig.defName, std::pair(), + std::bind(&CPlayerInterface::showPuzzleMap,LOCPLINT), SDLK_p, worldViewPuzzleConfig.playerColoured), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewScale1xConfig = config::ButtonInfo(); + worldViewScale1xConfig.defName = "VWMAG1.DEF"; + worldViewScale1xConfig.x = screen->w - 191; + worldViewScale1xConfig.y = 23 + 195; + worldViewScale1xConfig.playerColoured = false; + panelWorldView->addChildToPanel( // help text is wrong for this button + makeButton(291, std::bind(&CAdvMapInt::fworldViewScale1x,this), worldViewScale1xConfig, SDLK_1), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewScale2xConfig = config::ButtonInfo(); + worldViewScale2xConfig.defName = "VWMAG2.DEF"; + worldViewScale2xConfig.x = screen->w - 191 + 63; + worldViewScale2xConfig.y = 23 + 195; + worldViewScale2xConfig.playerColoured = false; + panelWorldView->addChildToPanel( // help text is wrong for this button + makeButton(291, std::bind(&CAdvMapInt::fworldViewScale2x,this), worldViewScale2xConfig, SDLK_2), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewScale4xConfig = config::ButtonInfo(); + worldViewScale4xConfig.defName = "VWMAG4.DEF"; + worldViewScale4xConfig.x = screen->w - 191 + 126; + worldViewScale4xConfig.y = 23 + 195; + worldViewScale4xConfig.playerColoured = false; + panelWorldView->addChildToPanel( // help text is wrong for this button + makeButton(291, std::bind(&CAdvMapInt::fworldViewScale4x,this), worldViewScale4xConfig, SDLK_4), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewUndergroundConfig = config::ButtonInfo(); + worldViewUndergroundConfig.defName = "IAM010.DEF"; + worldViewUndergroundConfig.additionalDefs.push_back("IAM003.DEF"); + worldViewUndergroundConfig.x = screen->w - 115; + worldViewUndergroundConfig.y = 343 + 195; + worldViewUndergroundConfig.playerColoured = true; + worldViewUnderground = makeButton(294, std::bind(&CAdvMapInt::fswitchLevel,this), worldViewUndergroundConfig, SDLK_u); + panelWorldView->addChildColorableButton(worldViewUnderground); + + setPlayer(LOCPLINT->playerID); + + int iconColorMultiplier = player.getNum() * 19; + int wvLeft = heroList.pos.x - 2; // TODO correct drawing position + //int wvTop = 195; + for (int i = 0; i < 5; ++i) + { + panelWorldView->addChildIcon(std::pair(i, Point(5, 58 + i * 20)), iconColorMultiplier); + panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 263 + i * 20, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, + Colors::WHITE, CGI->generaltexth->allTexts[612 + i])); + } + for (int i = 0; i < 7; ++i) + { + panelWorldView->addChildIcon(std::pair(i + 5, Point(5, 182 + i * 20)), iconColorMultiplier); + panelWorldView->addChildIcon(std::pair(i + 12, Point(160, 182 + i * 20)), iconColorMultiplier); + panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 387 + i * 20, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, + Colors::WHITE, CGI->generaltexth->allTexts[619 + i])); + } + panelWorldView->addChildToPanel(std::make_shared(wvLeft + 5, 367, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, + Colors::WHITE, CGI->generaltexth->allTexts[617])); + panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 367, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, + Colors::WHITE, CGI->generaltexth->allTexts[618])); + + activeMapPanel = panelMain; + + changeMode(EAdvMapMode::NORMAL); + + underground->block(!CGI->mh->map->twoLevel); + questlog->block(!CGI->mh->map->quests.size()); + worldViewUnderground->block(!CGI->mh->map->twoLevel); + + addUsedEvents(MOVE); +} + +void CAdvMapInt::fshowOverview() +{ + GH.pushIntT(); +} + +void CAdvMapInt::fworldViewBack() +{ + changeMode(EAdvMapMode::NORMAL); + CGI->mh->discardWorldViewCache(); + + auto hero = curHero(); + if (hero) + centerOn(hero); +} + +void CAdvMapInt::fworldViewScale1x() +{ + // TODO set corresponding scale button to "selected" mode + changeMode(EAdvMapMode::WORLD_VIEW, 0.22f); +} + +void CAdvMapInt::fworldViewScale2x() +{ + changeMode(EAdvMapMode::WORLD_VIEW, 0.36f); +} + +void CAdvMapInt::fworldViewScale4x() +{ + changeMode(EAdvMapMode::WORLD_VIEW, 0.5f); +} + +void CAdvMapInt::fswitchLevel() +{ + // with support for future multi-level maps :) + int maxLevels = CGI->mh->map->levels(); + if (maxLevels < 2) + return; + + position.z = (position.z + 1) % maxLevels; + + underground->setIndex(position.z, true); + underground->redraw(); + + worldViewUnderground->setIndex(position.z, true); + worldViewUnderground->redraw(); + + updateScreen = true; + minimap.setLevel(position.z); + + if (mode == EAdvMapMode::WORLD_VIEW) + terrain.redraw(); +} +void CAdvMapInt::fshowQuestlog() +{ + LOCPLINT->showQuestLog(); +} +void CAdvMapInt::fsleepWake() +{ + const CGHeroInstance *h = curHero(); + if (!h) + return; + bool newSleep = !isHeroSleeping(h); + setHeroSleeping(h, newSleep); + updateSleepWake(h); + if (newSleep) + { + fnextHero(); + + //moveHero.block(true); + //uncomment to enable original HoMM3 behaviour: + //move button is disabled for hero going to sleep, even though it's enabled when you reselect him + } +} + +void CAdvMapInt::fmoveHero() +{ + const CGHeroInstance *h = curHero(); + if (!h || !terrain.currentPath || !CGI->mh->canStartHeroMovement()) + return; + + LOCPLINT->moveHero(h, *terrain.currentPath); +} + +void CAdvMapInt::fshowSpellbok() +{ + if (!curHero()) //checking necessary values + return; + + centerOn(selection); + + GH.pushIntT(curHero(), LOCPLINT, false); +} + +void CAdvMapInt::fadventureOPtions() +{ + GH.pushIntT(); +} + +void CAdvMapInt::fsystemOptions() +{ + GH.pushIntT(); +} + +void CAdvMapInt::fnextHero() +{ + auto hero = dynamic_cast(selection); + int next = getNextHeroIndex(vstd::find_pos(LOCPLINT->wanderingHeroes, hero)); + if (next < 0) + return; + select(LOCPLINT->wanderingHeroes[next], true); +} + +void CAdvMapInt::fendTurn() +{ + if(!LOCPLINT->makingTurn) + return; + + if(settings["adventure"]["heroReminder"].Bool()) + { + for(auto hero : LOCPLINT->wanderingHeroes) + { + if(!isHeroSleeping(hero) && hero->movement > 0) + { + // Only show hero reminder if conditions met: + // - There still movement points + // - Hero don't have a path or there not points for first step on path + auto path = LOCPLINT->getAndVerifyPath(hero); + if(!path || path->nodes.size() < 2 || !path->nodes[path->nodes.size()-2].turns) + { + LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[55], std::bind(&CAdvMapInt::endingTurn, this), nullptr); + return; + } + } + } + } + endingTurn(); +} + +void CAdvMapInt::updateSleepWake(const CGHeroInstance *h) +{ + sleepWake->block(!h); + if (!h) + return; + bool state = isHeroSleeping(h); + sleepWake->setIndex(state ? 1 : 0, true); + sleepWake->assignedKeys.clear(); + sleepWake->assignedKeys.insert(state ? SDLK_w : SDLK_z); +} + +void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath) +{ + if(!h) + { + moveHero->block(true); + return; + } + //default value is for everywhere but CPlayerInterface::moveHero, because paths are not updated from there immediately + if(boost::logic::indeterminate(hasPath)) + hasPath = LOCPLINT->paths[h].nodes.size() ? true : false; + + moveHero->block(!(bool)hasPath || (h->movement == 0)); +} + +void CAdvMapInt::updateSpellbook(const CGHeroInstance *h) +{ + spellbook->block(!h); +} + +int CAdvMapInt::getNextHeroIndex(int startIndex) +{ + if (LOCPLINT->wanderingHeroes.size() == 0) + return -1; + if (startIndex < 0) + startIndex = 0; + int i = startIndex; + do + { + i++; + if (i >= LOCPLINT->wanderingHeroes.size()) + i = 0; + } + while (((LOCPLINT->wanderingHeroes[i]->movement == 0) || isHeroSleeping(LOCPLINT->wanderingHeroes[i])) && (i != startIndex)); + + if ((LOCPLINT->wanderingHeroes[i]->movement != 0) && !isHeroSleeping(LOCPLINT->wanderingHeroes[i])) + return i; + else + return -1; +} + +void CAdvMapInt::updateNextHero(const CGHeroInstance *h) +{ + int start = vstd::find_pos(LOCPLINT->wanderingHeroes, h); + int next = getNextHeroIndex(start); + if (next < 0) + { + nextHero->block(true); + return; + } + const CGHeroInstance *nextH = LOCPLINT->wanderingHeroes[next]; + bool noActiveHeroes = (next == start) && ((nextH->movement == 0) || isHeroSleeping(nextH)); + nextHero->block(noActiveHeroes); +} + +void CAdvMapInt::activate() +{ + CIntObject::activate(); + if (!(active & KEYBOARD)) + CIntObject::activate(KEYBOARD); + + screenBuf = screen; + GH.statusbar = statusbar; + + if(LOCPLINT) + { + LOCPLINT->cingconsole->activate(); + LOCPLINT->cingconsole->pos = this->pos; + } + + if(!duringAITurn) + { + activeMapPanel->activate(); + if (mode == EAdvMapMode::NORMAL) + { + heroList.activate(); + townList.activate(); + infoBar.activate(); + } + minimap.activate(); + terrain.activate(); + statusbar->activate(); + + GH.fakeMouseMove(); //to restore the cursor + } +} + +void CAdvMapInt::deactivate() +{ + CIntObject::deactivate(); + + if(!duringAITurn) + { + scrollingDir = 0; + + CCS->curh->set(Cursor::Map::POINTER); + activeMapPanel->deactivate(); + if (mode == EAdvMapMode::NORMAL) + { + heroList.deactivate(); + townList.deactivate(); + infoBar.deactivate(); + } + minimap.deactivate(); + terrain.deactivate(); + statusbar->deactivate(); + } +} + +void CAdvMapInt::showAll(SDL_Surface * to) +{ + bg->draw(to, 0, 0); + + if(state != INGAME) + return; + + switch (mode) + { + case EAdvMapMode::NORMAL: + + heroList.showAll(to); + townList.showAll(to); + infoBar.showAll(to); + break; + case EAdvMapMode::WORLD_VIEW: + + terrain.showAll(to); + break; + } + activeMapPanel->showAll(to); + + updateScreen = true; + minimap.showAll(to); + show(to); + + + resdatabar.showAll(to); + + statusbar->show(to); + + LOCPLINT->cingconsole->show(to); +} + +bool CAdvMapInt::isHeroSleeping(const CGHeroInstance *hero) +{ + if (!hero) + return false; + + return vstd::contains(LOCPLINT->sleepingHeroes, hero); +} + +void CAdvMapInt::setHeroSleeping(const CGHeroInstance *hero, bool sleep) +{ + if (sleep) + LOCPLINT->sleepingHeroes.push_back(hero); //FIXME: should we check for existence? + else + LOCPLINT->sleepingHeroes -= hero; + updateNextHero(nullptr); +} + +void CAdvMapInt::show(SDL_Surface * to) +{ + if(state != INGAME) + return; + + ++animValHitCount; //for animations + + if(animValHitCount % 2 == 0) + { + ++heroAnim; + } + if(animValHitCount >= 8) + { + CGI->mh->updateWater(); + animValHitCount = 0; + ++anim; + updateScreen = true; + } + + if(swipeEnabled) + { + handleSwipeUpdate(); + } +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) // on mobile, map-moving mode is exclusive (TODO technically it might work with both enabled; to be checked) + else +#endif + { + handleMapScrollingUpdate(); + } + + for(int i = 0; i < 4; i++) + { + if(settings["session"]["spectate"].Bool()) + gems[i]->setFrame(PlayerColor(1).getNum()); + else + gems[i]->setFrame(LOCPLINT->playerID.getNum()); + } + if(updateScreen) + { + int3 betterPos = LOCPLINT->repairScreenPos(position); + if (betterPos != position) + { + logGlobal->warn("Incorrect position for adventure map!"); + position = betterPos; + } + + terrain.show(to); + for(int i = 0; i < 4; i++) + gems[i]->showAll(to); + updateScreen=false; + LOCPLINT->cingconsole->show(to); + } + else if (terrain.needsAnimUpdate()) + { + terrain.showAnim(to); + for(int i = 0; i < 4; i++) + gems[i]->showAll(to); + } + + infoBar.show(to); + statusbar->showAll(to); +} + +void CAdvMapInt::handleMapScrollingUpdate() +{ + int scrollSpeed = static_cast(settings["adventure"]["scrollSpeed"].Float()); + //if advmap needs updating AND (no dialog is shown OR ctrl is pressed) + if((animValHitCount % (4 / scrollSpeed)) == 0 + && ((GH.topInt().get() == this) || isCtrlKeyDown())) + { + if((scrollingDir & LEFT) && (position.x > -CGI->mh->frameW)) + position.x--; + + if((scrollingDir & RIGHT) && (position.x < CGI->mh->map->width - CGI->mh->tilesW + CGI->mh->frameW)) + position.x++; + + if((scrollingDir & UP) && (position.y > -CGI->mh->frameH)) + position.y--; + + if((scrollingDir & DOWN) && (position.y < CGI->mh->map->height - CGI->mh->tilesH + CGI->mh->frameH)) + position.y++; + + if(scrollingDir) + { + setScrollingCursor(scrollingDir); + scrollingState = true; + updateScreen = true; + minimap.redraw(); + if(mode == EAdvMapMode::WORLD_VIEW) + terrain.redraw(); + } + else if(scrollingState) + { + CCS->curh->set(Cursor::Map::POINTER); + scrollingState = false; + } + } +} + +void CAdvMapInt::handleSwipeUpdate() +{ + if(swipeMovementRequested) + { + auto fixedPos = LOCPLINT->repairScreenPos(swipeTargetPosition); + position.x = fixedPos.x; + position.y = fixedPos.y; + CCS->curh->set(Cursor::Map::POINTER); + updateScreen = true; + minimap.redraw(); + swipeMovementRequested = false; + } +} + +void CAdvMapInt::selectionChanged() +{ + const CGTownInstance *to = LOCPLINT->towns[townList.getSelectedIndex()]; + if (selection != to) + select(to); +} + +void CAdvMapInt::centerOn(int3 on, bool fade) +{ + bool switchedLevels = on.z != position.z; + + if (fade) + { + terrain.fadeFromCurrentView(); + } + + switch (mode) + { + default: + case EAdvMapMode::NORMAL: + on.x -= CGI->mh->frameW; // is this intentional? frame size doesn't really have to correspond to camera size... + on.y -= CGI->mh->frameH; + break; + case EAdvMapMode::WORLD_VIEW: + on.x -= static_cast(CGI->mh->tilesW / 2 / worldViewScale); + on.y -= static_cast(CGI->mh->tilesH / 2 / worldViewScale); + break; + } + + + on = LOCPLINT->repairScreenPos(on); + + position = on; + updateScreen=true; + underground->setIndex(on.z,true); //change underground switch button image + underground->redraw(); + worldViewUnderground->setIndex(on.z, true); + worldViewUnderground->redraw(); + if (switchedLevels) + minimap.setLevel(position.z); + minimap.redraw(); + + if (mode == EAdvMapMode::WORLD_VIEW) + terrain.redraw(); +} + +void CAdvMapInt::centerOn(const CGObjectInstance * obj, bool fade) +{ + centerOn(obj->getSightCenter(), fade); +} + +void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) +{ + + if (mode == EAdvMapMode::WORLD_VIEW) + return; + + ui8 Dir = 0; + SDL_Keycode k = key.keysym.sym; + const CGHeroInstance *h = curHero(); //selected hero + const CGTownInstance *t = curTown(); //selected town + + switch(k) + { + case SDLK_g: + if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) + return; + + { + //find first town with tavern + auto itr = range::find_if(LOCPLINT->towns, [](const CGTownInstance * town) + { + return town->hasBuilt(BuildingID::TAVERN); + }); + + if(itr != LOCPLINT->towns.end()) + LOCPLINT->showThievesGuildWindow(*itr); + else + LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithTavern")); + } + return; + case SDLK_i: + if(isActive()) + CAdventureOptions::showScenarioInfo(); + return; + case SDLK_l: + if(isActive()) + LOCPLINT->proposeLoadingGame(); + return; + case SDLK_s: + if(isActive() && key.type == SDL_KEYUP) + GH.pushIntT(); + return; + case SDLK_d: + { + if(h && isActive() && LOCPLINT->makingTurn && key.state == SDL_PRESSED) + LOCPLINT->tryDiggging(h); + return; + } + case SDLK_p: + if(isActive()) + LOCPLINT->showPuzzleMap(); + return; + case SDLK_v: + if(isActive()) + LOCPLINT->viewWorldMap(); + return; + case SDLK_r: + if(isActive() && LOCPLINT->ctrlPressed()) + { + LOCPLINT->showYesNoDialog(CGI->generaltexth->translate("vcmi.adventureMap.confirmRestartGame"), + [](){ LOCPLINT->sendCustomEvent(EUserEvent::RESTART_GAME); }, nullptr); + } + return; + case SDLK_SPACE: //space - try to revisit current object with selected hero + { + if(!isActive()) + return; + if(h && key.state == SDL_PRESSED) + { + auto unlockPim = vstd::makeUnlockGuard(*CPlayerInterface::pim); + //TODO!!!!!!! possible freeze, when GS mutex is locked and network thread can't apply package + //this thread leaves scope and tries to lock pim while holding gs, + //network thread tries to lock gs (appluy cl) while holding pim + //this thread should first lock pim, however gs locking/unlocking is done inside cb + LOCPLINT->cb->moveHero(h,h->pos); + } + } + return; + case SDLK_RETURN: + { + if(!isActive() || !selection || key.state != SDL_PRESSED) + return; + if(h) + LOCPLINT->openHeroWindow(h); + else if(t) + LOCPLINT->openTownWindow(t); + return; + } + case SDLK_ESCAPE: + { + if(isActive() || GH.topInt().get() != this || !spellBeingCasted || key.state != SDL_PRESSED) + return; + + leaveCastingMode(); + return; + } + case SDLK_t: + { + //act on key down if marketplace windows is not already opened + if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) + return; + + if(LOCPLINT->ctrlPressed()) //CTRL + T => open marketplace + { + //check if we have any marketplace + const CGTownInstance *townWithMarket = nullptr; + for(const CGTownInstance *t : LOCPLINT->cb->getTownsInfo()) + { + if(t->hasBuilt(BuildingID::MARKETPLACE)) + { + townWithMarket = t; + break; + } + } + + if(townWithMarket) //if any town has marketplace, open window + GH.pushIntT(townWithMarket); + else //if not - complain + LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithMarket")); + } + else if(isActive()) //no ctrl, advmapint is on the top => switch to town + { + townList.selectNext(); + } + return; + } + default: + { + static const int3 directions[] = { int3(-1, +1, 0), int3(0, +1, 0), int3(+1, +1, 0), + int3(-1, 0, 0), int3(0, 0, 0), int3(+1, 0, 0), + int3(-1, -1, 0), int3(0, -1, 0), int3(+1, -1, 0) }; + + //numpad arrow + if(CGuiHandler::isArrowKey(k)) + k = CGuiHandler::arrowToNum(k); + + k -= SDLK_KP_1; + + if(k < 0 || k > 8) + return; + + if (!CGI->mh->canStartHeroMovement()) + return; + + int3 dir = directions[k]; + + if(!isActive() || LOCPLINT->ctrlPressed())//ctrl makes arrow move screen, not hero + { + Dir = (dir.x<0 ? LEFT : 0) | + (dir.x>0 ? RIGHT : 0) | + (dir.y<0 ? UP : 0) | + (dir.y>0 ? DOWN : 0) ; + break; + } + + if(!h || key.state != SDL_PRESSED) + break; + + if(k == 4) + { + centerOn(h); + return; + } + + CGPath &path = LOCPLINT->paths[h]; + terrain.currentPath = &path; + int3 dst = h->visitablePos() + dir; + if(dst != verifyPos(dst) || !LOCPLINT->cb->getPathsInfo(h)->getPath(path, dst)) + { + terrain.currentPath = nullptr; + return; + } + + if (path.nodes.size() > 2) + updateMoveHero(h); + else + if(!path.nodes[0].turns) + LOCPLINT->moveHero(h, path); + } + + return; + } + if(Dir && key.state == SDL_PRESSED //arrow is pressed + && LOCPLINT->ctrlPressed() + ) + scrollingDir |= Dir; + else + scrollingDir &= ~Dir; +} +void CAdvMapInt::handleRightClick(std::string text, tribool down) +{ + if(down) + { + CRClickPopup::createAndPush(text); + } +} +int3 CAdvMapInt::verifyPos(int3 ver) +{ + if (ver.x<0) + ver.x=0; + if (ver.y<0) + ver.y=0; + if (ver.z<0) + ver.z=0; + if (ver.x>=CGI->mh->sizes.x) + ver.x=CGI->mh->sizes.x-1; + if (ver.y>=CGI->mh->sizes.y) + ver.y=CGI->mh->sizes.y-1; + if (ver.z>=CGI->mh->sizes.z) + ver.z=CGI->mh->sizes.z-1; + return ver; +} + +void CAdvMapInt::select(const CArmedInstance *sel, bool centerView) +{ + assert(sel); + LOCPLINT->setSelection(sel); + selection = sel; + if (LOCPLINT->battleInt == nullptr && LOCPLINT->makingTurn) + { + auto pos = sel->visitablePos(); + auto tile = LOCPLINT->cb->getTile(pos); + if(tile) + CCS->musich->playMusicFromSet("terrain", tile->terType->getJsonKey(), true, false); + } + if(centerView) + centerOn(sel); + + terrain.currentPath = nullptr; + if(sel->ID==Obj::TOWN) + { + auto town = dynamic_cast(sel); + + infoBar.showTownSelection(town); + townList.select(town); + heroList.select(nullptr); + + updateSleepWake(nullptr); + updateMoveHero(nullptr); + updateSpellbook(nullptr); + } + else //hero selected + { + auto hero = dynamic_cast(sel); + + infoBar.showHeroSelection(hero); + heroList.select(hero); + townList.select(nullptr); + + terrain.currentPath = LOCPLINT->getAndVerifyPath(hero); + + updateSleepWake(hero); + updateMoveHero(hero); + updateSpellbook(hero); + } + townList.redraw(); + heroList.redraw(); +} + +void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent ) +{ +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + if(swipeEnabled) + return; +#endif + // adventure map scrolling with mouse + // currently disabled in world view mode (as it is in OH3), but should work correctly if mode check is removed + // don't scroll if there is no window in focus - these events don't seem to correspond to the actual mouse movement + if(!isCtrlKeyDown() && isActive() && sEvent.windowID != 0 && mode == EAdvMapMode::NORMAL) + { + if(sEvent.x<15) + { + scrollingDir |= LEFT; + } + else + { + scrollingDir &= ~LEFT; + } + if(sEvent.x>screen->w-15) + { + scrollingDir |= RIGHT; + } + else + { + scrollingDir &= ~RIGHT; + } + if(sEvent.y<15) + { + scrollingDir |= UP; + } + else + { + scrollingDir &= ~UP; + } + if(sEvent.y>screen->h-15) + { + scrollingDir |= DOWN; + } + else + { + scrollingDir &= ~DOWN; + } + } +} + +bool CAdvMapInt::isActive() +{ + return active & ~CIntObject::KEYBOARD; +} + +void CAdvMapInt::startHotSeatWait(PlayerColor Player) +{ + state = WAITING; +} + +void CAdvMapInt::setPlayer(PlayerColor Player) +{ + player = Player; + bg->playerColored(player); + + panelMain->setPlayerColor(player); + panelWorldView->setPlayerColor(player); + panelWorldView->recolorIcons(player, player.getNum() * 19); + resdatabar.background->colorize(player); +} + +void CAdvMapInt::startTurn() +{ + state = INGAME; + if(LOCPLINT->cb->getCurrentPlayer() == LOCPLINT->playerID + || settings["session"]["spectate"].Bool()) + { + adjustActiveness(false); + minimap.setAIRadar(false); + } +} + +void CAdvMapInt::endingTurn() +{ + if(settings["session"]["spectate"].Bool()) + return; + + LOCPLINT->makingTurn = false; + LOCPLINT->cb->endTurn(); + CCS->soundh->ambientStopAllChannels(); +} + +const CGObjectInstance* CAdvMapInt::getActiveObject(const int3 &mapPos) +{ + std::vector < const CGObjectInstance * > bobjs = LOCPLINT->cb->getBlockingObjs(mapPos); //blocking objects at tile + + if (bobjs.empty()) + return nullptr; + + return *boost::range::max_element(bobjs, &CMapHandler::compareObjectBlitOrder); +/* + if (bobjs.back()->ID == Obj::HERO) + return bobjs.back(); + else + return bobjs.front();*/ +} + +void CAdvMapInt::tileLClicked(const int3 &mapPos) +{ + if(mode != EAdvMapMode::NORMAL) + return; + if(!LOCPLINT->cb->isVisible(mapPos) || !LOCPLINT->makingTurn) + return; + + const TerrainTile *tile = LOCPLINT->cb->getTile(mapPos); + + const CGObjectInstance *topBlocking = getActiveObject(mapPos); + + int3 selPos = selection->getSightCenter(); + if(spellBeingCasted && isInScreenRange(selPos, mapPos)) + { + const TerrainTile *heroTile = LOCPLINT->cb->getTile(selPos); + + switch(spellBeingCasted->id) + { + case SpellID::SCUTTLE_BOAT: //Scuttle Boat + if(topBlocking && topBlocking->ID == Obj::BOAT) + leaveCastingMode(true, mapPos); + break; + case SpellID::DIMENSION_DOOR: + if(!tile || tile->isClear(heroTile)) + leaveCastingMode(true, mapPos); + break; + } + return; + } + //check if we can select this object + bool canSelect = topBlocking && topBlocking->ID == Obj::HERO && topBlocking->tempOwner == LOCPLINT->playerID; + canSelect |= topBlocking && topBlocking->ID == Obj::TOWN && LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, topBlocking->tempOwner); + + bool isHero = false; + if(selection->ID != Obj::HERO) //hero is not selected (presumably town) + { + assert(!terrain.currentPath); //path can be active only when hero is selected + if(selection == topBlocking) //selected town clicked + LOCPLINT->openTownWindow(static_cast(topBlocking)); + else if(canSelect) + select(static_cast(topBlocking), false); + } + else if(const CGHeroInstance * currentHero = curHero()) //hero is selected + { + isHero = true; + + const CGPathNode *pn = LOCPLINT->cb->getPathsInfo(currentHero)->getPathInfo(mapPos); + if(currentHero == topBlocking) //clicked selected hero + { + LOCPLINT->openHeroWindow(currentHero); + return; + } + else if(canSelect && pn->turns == 255 ) //selectable object at inaccessible tile + { + select(static_cast(topBlocking), false); + return; + } + else //still here? we need to move hero if we clicked end of already selected path or calculate a new path otherwise + { + if(terrain.currentPath && terrain.currentPath->endPos() == mapPos)//we'll be moving + { + if(CGI->mh->canStartHeroMovement()) + LOCPLINT->moveHero(currentHero, *terrain.currentPath); + return; + } + else //remove old path and find a new one if we clicked on accessible tile + { + CGPath &path = LOCPLINT->paths[currentHero]; + CGPath newpath; + bool gotPath = LOCPLINT->cb->getPathsInfo(currentHero)->getPath(newpath, mapPos); //try getting path, erase if failed + if(gotPath && newpath.nodes.size()) + path = newpath; + + if(path.nodes.size()) + terrain.currentPath = &path; + else + LOCPLINT->eraseCurrentPathOf(currentHero); + + updateMoveHero(currentHero); + } + } + } //end of hero is selected "case" + else + { + throw std::runtime_error("Nothing is selected..."); + } + + const auto shipyard = ourInaccessibleShipyard(topBlocking); + if(isHero && shipyard != nullptr) + { + LOCPLINT->showShipyardDialogOrProblemPopup(shipyard); + } +} + +void CAdvMapInt::tileHovered(const int3 &mapPos) +{ + if(mode != EAdvMapMode::NORMAL //disable in world view + || !selection) //may occur just at the start of game (fake move before full intiialization) + return; + if(!LOCPLINT->cb->isVisible(mapPos)) + { + CCS->curh->set(Cursor::Map::POINTER); + statusbar->clear(); + return; + } + auto objRelations = PlayerRelations::ALLIES; + const CGObjectInstance *objAtTile = getActiveObject(mapPos); + if(objAtTile) + { + objRelations = LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, objAtTile->tempOwner); + std::string text = curHero() ? objAtTile->getHoverText(curHero()) : objAtTile->getHoverText(LOCPLINT->playerID); + boost::replace_all(text,"\n"," "); + statusbar->write(text); + } + else + { + std::string hlp; + CGI->mh->getTerrainDescr(mapPos, hlp, false); + statusbar->write(hlp); + } + + if(spellBeingCasted) + { + switch(spellBeingCasted->id) + { + case SpellID::SCUTTLE_BOAT: + if(objAtTile && objAtTile->ID == Obj::BOAT) + CCS->curh->set(Cursor::Map::SCUTTLE_BOAT); + else + CCS->curh->set(Cursor::Map::POINTER); + return; + case SpellID::DIMENSION_DOOR: + { + const TerrainTile * t = LOCPLINT->cb->getTile(mapPos, false); + int3 hpos = selection->getSightCenter(); + if((!t || t->isClear(LOCPLINT->cb->getTile(hpos))) && isInScreenRange(hpos, mapPos)) + CCS->curh->set(Cursor::Map::TELEPORT); + else + CCS->curh->set(Cursor::Map::POINTER); + return; + } + } + } + + if(selection->ID == Obj::TOWN) + { + if(objAtTile) + { + if(objAtTile->ID == Obj::TOWN && objRelations != PlayerRelations::ENEMIES) + CCS->curh->set(Cursor::Map::TOWN); + else if(objAtTile->ID == Obj::HERO && objRelations == PlayerRelations::SAME_PLAYER) + CCS->curh->set(Cursor::Map::HERO); + else + CCS->curh->set(Cursor::Map::POINTER); + } + else + CCS->curh->set(Cursor::Map::POINTER); + } + else if(const CGHeroInstance * hero = curHero()) + { + std::array cursorMove = { Cursor::Map::T1_MOVE, Cursor::Map::T2_MOVE, Cursor::Map::T3_MOVE, Cursor::Map::T4_MOVE, }; + std::array cursorAttack = { Cursor::Map::T1_ATTACK, Cursor::Map::T2_ATTACK, Cursor::Map::T3_ATTACK, Cursor::Map::T4_ATTACK, }; + std::array cursorSail = { Cursor::Map::T1_SAIL, Cursor::Map::T2_SAIL, Cursor::Map::T3_SAIL, Cursor::Map::T4_SAIL, }; + std::array cursorDisembark = { Cursor::Map::T1_DISEMBARK, Cursor::Map::T2_DISEMBARK, Cursor::Map::T3_DISEMBARK, Cursor::Map::T4_DISEMBARK, }; + std::array cursorExchange = { Cursor::Map::T1_EXCHANGE, Cursor::Map::T2_EXCHANGE, Cursor::Map::T3_EXCHANGE, Cursor::Map::T4_EXCHANGE, }; + std::array cursorVisit = { Cursor::Map::T1_VISIT, Cursor::Map::T2_VISIT, Cursor::Map::T3_VISIT, Cursor::Map::T4_VISIT, }; + std::array cursorSailVisit = { Cursor::Map::T1_SAIL_VISIT, Cursor::Map::T2_SAIL_VISIT, Cursor::Map::T3_SAIL_VISIT, Cursor::Map::T4_SAIL_VISIT, }; + + const CGPathNode * pathNode = LOCPLINT->cb->getPathsInfo(hero)->getPathInfo(mapPos); + assert(pathNode); + + if(LOCPLINT->altPressed() && pathNode->reachable()) //overwrite status bar text with movement info + { + ShowMoveDetailsInStatusbar(*hero, *pathNode); + } + + int turns = pathNode->turns; + vstd::amin(turns, 3); + switch(pathNode->action) + { + case CGPathNode::NORMAL: + case CGPathNode::TELEPORT_NORMAL: + if(pathNode->layer == EPathfindingLayer::LAND) + CCS->curh->set(cursorMove[turns]); + else + CCS->curh->set(cursorSailVisit[turns]); + break; + + case CGPathNode::VISIT: + case CGPathNode::BLOCKING_VISIT: + case CGPathNode::TELEPORT_BLOCKING_VISIT: + if(objAtTile && objAtTile->ID == Obj::HERO) + { + if(selection == objAtTile) + CCS->curh->set(Cursor::Map::HERO); + else + CCS->curh->set(cursorExchange[turns]); + } + else if(pathNode->layer == EPathfindingLayer::LAND) + CCS->curh->set(cursorVisit[turns]); + else + CCS->curh->set(cursorSailVisit[turns]); + break; + + case CGPathNode::BATTLE: + case CGPathNode::TELEPORT_BATTLE: + CCS->curh->set(cursorAttack[turns]); + break; + + case CGPathNode::EMBARK: + CCS->curh->set(cursorSail[turns]); + break; + + case CGPathNode::DISEMBARK: + CCS->curh->set(cursorDisembark[turns]); + break; + + default: + if(objAtTile && objRelations != PlayerRelations::ENEMIES) + { + if(objAtTile->ID == Obj::TOWN) + CCS->curh->set(Cursor::Map::TOWN); + else if(objAtTile->ID == Obj::HERO && objRelations == PlayerRelations::SAME_PLAYER) + CCS->curh->set(Cursor::Map::HERO); + else + CCS->curh->set(Cursor::Map::POINTER); + } + else + CCS->curh->set(Cursor::Map::POINTER); + break; + } + } + + if(ourInaccessibleShipyard(objAtTile)) + { + CCS->curh->set(Cursor::Map::T1_SAIL); + } +} + +void CAdvMapInt::ShowMoveDetailsInStatusbar(const CGHeroInstance & hero, const CGPathNode & pathNode) +{ + const int maxMovementPointsAtStartOfLastTurn = pathNode.turns > 0 ? hero.maxMovePoints(pathNode.layer == EPathfindingLayer::LAND) : hero.movement; + const int movementPointsLastTurnCost = maxMovementPointsAtStartOfLastTurn - pathNode.moveRemains; + const int remainingPointsAfterMove = pathNode.turns == 0 ? pathNode.moveRemains : 0; + + std::string result = VLC->generaltexth->translate("vcmi.adventureMap", pathNode.turns > 0 ? "moveCostDetails" : "moveCostDetailsNoTurns"); + + boost::replace_first(result, "%TURNS", std::to_string(pathNode.turns)); + boost::replace_first(result, "%POINTS", std::to_string(movementPointsLastTurnCost)); + boost::replace_first(result, "%REMAINING", std::to_string(remainingPointsAfterMove)); + + statusbar->write(result); +} + +void CAdvMapInt::tileRClicked(const int3 &mapPos) +{ + if(mode != EAdvMapMode::NORMAL) + return; + if(spellBeingCasted) + { + leaveCastingMode(); + return; + } + if(!LOCPLINT->cb->isVisible(mapPos)) + { + CRClickPopup::createAndPush(VLC->generaltexth->allTexts[61]); //Uncharted Territory + return; + } + + const CGObjectInstance * obj = getActiveObject(mapPos); + if(!obj) + { + // Bare or undiscovered terrain + const TerrainTile * tile = LOCPLINT->cb->getTile(mapPos); + if (tile) + { + std::string hlp; + CGI->mh->getTerrainDescr(mapPos, hlp, true); + CRClickPopup::createAndPush(hlp); + } + return; + } + + CRClickPopup::createAndPush(obj, GH.getCursorPosition(), ETextAlignment::CENTER); +} + +void CAdvMapInt::enterCastingMode(const CSpell * sp) +{ + assert(sp->id == SpellID::SCUTTLE_BOAT || sp->id == SpellID::DIMENSION_DOOR); + spellBeingCasted = sp; + + deactivate(); + terrain.activate(); + GH.fakeMouseMove(); +} + +void CAdvMapInt::leaveCastingMode(bool cast, int3 dest) +{ + assert(spellBeingCasted); + SpellID id = spellBeingCasted->id; + spellBeingCasted = nullptr; + terrain.deactivate(); + activate(); + + if(cast) + LOCPLINT->cb->castSpell(curHero(), id, dest); + else + LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[731]); //Spell cancelled +} + +const CGHeroInstance * CAdvMapInt::curHero() const +{ + if(selection && selection->ID == Obj::HERO) + return static_cast(selection); + else + return nullptr; +} + +const CGTownInstance * CAdvMapInt::curTown() const +{ + if(selection && selection->ID == Obj::TOWN) + return static_cast(selection); + else + return nullptr; +} + +const IShipyard * CAdvMapInt::ourInaccessibleShipyard(const CGObjectInstance *obj) const +{ + const IShipyard *ret = IShipyard::castFrom(obj); + + if(!ret || + obj->tempOwner != player || + (CCS->curh->get() != Cursor::Map::T1_SAIL && CCS->curh->get() != Cursor::Map::POINTER)) + return nullptr; + + return ret; +} + +void CAdvMapInt::aiTurnStarted() +{ + if(settings["session"]["spectate"].Bool()) + return; + + adjustActiveness(true); + CCS->musich->playMusicFromSet("enemy-turn", true, false); + adventureInt->minimap.setAIRadar(true); + adventureInt->infoBar.startEnemyTurn(LOCPLINT->cb->getCurrentPlayer()); + adventureInt->infoBar.showAll(screen);//force refresh on inactive object +} + +void CAdvMapInt::adjustActiveness(bool aiTurnStart) +{ + bool wasActive = isActive(); + + if(wasActive) + deactivate(); + adventureInt->duringAITurn = aiTurnStart; + if(wasActive) + activate(); +} + +void CAdvMapInt::quickCombatLock() +{ + if(!duringAITurn) + deactivate(); +} + +void CAdvMapInt::quickCombatUnlock() +{ + if(!duringAITurn) + activate(); +} + +void CAdvMapInt::changeMode(EAdvMapMode newMode, float newScale) +{ + if (mode != newMode) + { + mode = newMode; + + switch (mode) + { + case EAdvMapMode::NORMAL: + panelMain->activate(); + panelWorldView->deactivate(); + activeMapPanel = panelMain; + + townList.activate(); + heroList.activate(); + infoBar.activate(); + + worldViewOptions.clear(); + + break; + case EAdvMapMode::WORLD_VIEW: + panelMain->deactivate(); + panelWorldView->activate(); + + activeMapPanel = panelWorldView; + + townList.deactivate(); + heroList.deactivate(); + infoBar.showSelection(); // to prevent new day animation interfering world view mode + infoBar.deactivate(); + + break; + } + worldViewScale = newScale; + redraw(); + } + else if (worldViewScale != newScale) // still in world view mode, but the scale changed + { + worldViewScale = newScale; + redraw(); + } +} + +CAdventureOptions::CAdventureOptions() + : CWindowObject(PLAYER_COLORED, "ADVOPTS") +{ + OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); + + viewWorld = std::make_shared(Point(24, 23), "ADVVIEW.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_v); + viewWorld->addCallback(std::bind(&CPlayerInterface::viewWorldMap, LOCPLINT)); + + exit = std::make_shared(Point(204, 313), "IOK6432.DEF", CButton::tooltip(), std::bind(&CAdventureOptions::close, this), SDLK_RETURN); + exit->assignedKeys.insert(SDLK_ESCAPE); + + scenInfo = std::make_shared(Point(24, 198), "ADVINFO.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_i); + scenInfo->addCallback(CAdventureOptions::showScenarioInfo); + + puzzle = std::make_shared(Point(24, 81), "ADVPUZ.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_p); + puzzle->addCallback(std::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT)); + + dig = std::make_shared(Point(24, 139), "ADVDIG.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_d); + if(const CGHeroInstance *h = adventureInt->curHero()) + dig->addCallback(std::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h)); + else + dig->block(true); +} + +void CAdventureOptions::showScenarioInfo() +{ + if(LOCPLINT->cb->getStartInfo()->campState) + { + GH.pushIntT(); + } + else + { + GH.pushIntT(); + } +} + +CAdvMapInt::WorldViewOptions::WorldViewOptions() +{ + clear(); +} + +void CAdvMapInt::WorldViewOptions::clear() +{ + showAllTerrain = false; + + iconPositions.clear(); +} + +void CAdvMapInt::WorldViewOptions::adjustDrawingInfo(MapDrawingInfo& info) +{ + info.showAllTerrain = showAllTerrain; + + info.additionalIcons = &iconPositions; +} diff --git a/client/adventureMap/CAdvmapInterface.h b/client/adventureMap/CAdvmapInterface.h new file mode 100644 index 000000000..6b1ae0ddc --- /dev/null +++ b/client/adventureMap/CAdvmapInterface.h @@ -0,0 +1,276 @@ +/* + * CAdvmapInterface.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include "../widgets/AdventureMapClasses.h" +#include "CWindowObject.h" + +#include "../widgets/TextControls.h" +#include "../widgets/Buttons.h" + +#include "../../lib/spells/ViewSpellInt.h" + +VCMI_LIB_NAMESPACE_BEGIN + +struct CGPath; +struct CGPathNode; +class CGHeroInstance; +class CGTownInstance; +class CSpell; +class IShipyard; + +VCMI_LIB_NAMESPACE_END + +class CCallback; +class CAdvMapInt; +class CHeroWindow; +enum class EMapAnimRedrawStatus; +class CFadeAnimation; + +struct MapDrawingInfo; + +/*****************************/ + +enum class EAdvMapMode +{ + NORMAL, + WORLD_VIEW +}; + +/// Adventure options dialog where you can view the world, dig, play the replay of the last turn,... +class CAdventureOptions : public CWindowObject +{ +public: + std::shared_ptr exit; + std::shared_ptr viewWorld; + std::shared_ptr puzzle; + std::shared_ptr dig; + std::shared_ptr scenInfo; + /*std::shared_ptr replay*/ + + CAdventureOptions(); + static void showScenarioInfo(); +}; + +/// Holds information about which tiles of the terrain are shown/not shown at the screen +class CTerrainRect : public CIntObject +{ + SDL_Surface * fadeSurface; + EMapAnimRedrawStatus lastRedrawStatus; + std::shared_ptr fadeAnim; + + int3 swipeInitialMapPos; + int3 swipeInitialRealPos; + bool isSwiping; + static constexpr float SwipeTouchSlop = 16.0f; + + void handleHover(const SDL_MouseMotionEvent & sEvent); + void handleSwipeMove(const SDL_MouseMotionEvent & sEvent); + /// handles start/finish of swipe (press/release of corresponding button); returns true if state change was handled + bool handleSwipeStateChange(bool btnPressed); +public: + int tilesw, tilesh; //width and height of terrain to blit in tiles + int3 curHoveredTile; + int moveX, moveY; //shift between actual position of screen and the one we wil blit; ranges from -31 to 31 (in pixels) + CGPath * currentPath; + + CTerrainRect(); + virtual ~CTerrainRect(); + void deactivate() override; + void clickLeft(tribool down, bool previousState) override; + void clickRight(tribool down, bool previousState) override; + void clickMiddle(tribool down, bool previousState) override; + void hover(bool on) override; + void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; + void show(SDL_Surface * to) override; + void showAll(SDL_Surface * to) override; + void showAnim(SDL_Surface * to); + void showPath(const Rect &extRect, SDL_Surface * to); + int3 whichTileIsIt(const int x, const int y); //x,y are cursor position + int3 whichTileIsIt(); //uses current cursor pos + /// @returns number of visible tiles on screen respecting current map scaling + int3 tileCountOnScreen(); + /// animates view by caching current surface and crossfading it with normal screen + void fadeFromCurrentView(); + bool needsAnimUpdate(); +}; + +/// Resources bar which shows information about how many gold, crystals,... you have +/// Current date is displayed too +class CResDataBar : public CIntObject +{ +public: + std::shared_ptr background; + + std::vector > txtpos; + std::string datetext; + + void clickRight(tribool down, bool previousState) override; + CResDataBar(); + CResDataBar(const std::string &defname, int x, int y, int offx, int offy, int resdist, int datedist); + ~CResDataBar(); + + void draw(SDL_Surface * to); + void show(SDL_Surface * to) override; + void showAll(SDL_Surface * to) override; +}; + +/// That's a huge class which handles general adventure map actions and +/// shows the right menu(questlog, spellbook, end turn,..) from where you +/// can get to the towns and heroes. +class CAdvMapInt : public CIntObject +{ + //Return object that must be active at this tile (=clickable) + const CGObjectInstance *getActiveObject(const int3 &tile); + +public: + CAdvMapInt(); + + int3 position; //top left corner of visible map part + PlayerColor player; + + bool duringAITurn; + + enum{LEFT=1, RIGHT=2, UP=4, DOWN=8}; + ui8 scrollingDir; //uses enum: LEFT RIGHT, UP, DOWN + bool scrollingState; + bool swipeEnabled; + bool swipeMovementRequested; + int3 swipeTargetPosition; + + enum{NA, INGAME, WAITING} state; + + bool updateScreen; + ui8 anim, animValHitCount; //animation frame + ui8 heroAnim, heroAnimValHitCount; //animation frame + + EAdvMapMode mode; + float worldViewScale; + + struct WorldViewOptions + { + bool showAllTerrain; //for expert viewEarth + + std::vector iconPositions; + + WorldViewOptions(); + + void clear(); + + void adjustDrawingInfo(MapDrawingInfo & info); + }; + + WorldViewOptions worldViewOptions; + + std::shared_ptr bg; + std::shared_ptr bgWorldView; + std::vector> gems; + CMinimap minimap; + std::shared_ptr statusbar; + + std::shared_ptr kingOverview; + std::shared_ptr underground; + std::shared_ptr questlog; + std::shared_ptr sleepWake; + std::shared_ptr moveHero; + std::shared_ptr spellbook; + std::shared_ptr advOptions; + std::shared_ptr sysOptions; + std::shared_ptr nextHero; + std::shared_ptr endTurn; + + std::shared_ptr worldViewUnderground; + + CTerrainRect terrain; //visible terrain + CResDataBar resdatabar; + CHeroList heroList; + CTownList townList; + CInfoBar infoBar; + + std::shared_ptr panelMain; // panel that holds all right-side buttons in normal view + std::shared_ptr panelWorldView; // panel that holds all buttons and other ui in world view + std::shared_ptr activeMapPanel; // currently active panel (either main or world view, depending on current mode) + + std::shared_ptr worldViewIcons;// images for world view overlay + + const CSpell *spellBeingCasted; //nullptr if none + + const CArmedInstance *selection; //currently selected town/hero + + //functions bound to buttons + void fshowOverview(); + void fworldViewBack(); + void fworldViewScale1x(); + void fworldViewScale2x(); + void fworldViewScale4x(); + void fswitchLevel(); + void fshowQuestlog(); + void fsleepWake(); + void fmoveHero(); + void fshowSpellbok(); + void fadventureOPtions(); + void fsystemOptions(); + void fnextHero(); + void fendTurn(); + + void activate() override; + void deactivate() override; + + void show(SDL_Surface * to) override; //redraws terrain + void showAll(SDL_Surface * to) override; //shows and activates adv. map interface + + void select(const CArmedInstance *sel, bool centerView = true); + void selectionChanged(); + void centerOn(int3 on, bool fade = false); + void centerOn(const CGObjectInstance *obj, bool fade = false); + int3 verifyPos(int3 ver); + void handleRightClick(std::string text, tribool down); + void keyPressed(const SDL_KeyboardEvent & key) override; + void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; + bool isActive(); + + bool isHeroSleeping(const CGHeroInstance *hero); + void setHeroSleeping(const CGHeroInstance *hero, bool sleep); + int getNextHeroIndex(int startIndex); //for Next Hero button - cycles awake heroes with movement only + + void setPlayer(PlayerColor Player); + void startHotSeatWait(PlayerColor Player); + void startTurn(); + void endingTurn(); + void aiTurnStarted(); + + void adjustActiveness(bool aiTurnStart); //should be called every time at AI/human turn transition; blocks GUI during AI turn + void quickCombatLock(); //should be called when quick battle started + void quickCombatUnlock(); + void tileLClicked(const int3 &mapPos); + void tileHovered(const int3 &mapPos); + void tileRClicked(const int3 &mapPos); + void enterCastingMode(const CSpell * sp); + void leaveCastingMode(bool cast = false, int3 dest = int3(-1, -1, -1)); + const CGHeroInstance * curHero() const; + const CGTownInstance * curTown() const; + const IShipyard * ourInaccessibleShipyard(const CGObjectInstance *obj) const; //checks if obj is our ashipyard and cursor is 0,0 -> returns shipyard or nullptr else + //button updates + void updateSleepWake(const CGHeroInstance *h); + void updateMoveHero(const CGHeroInstance *h, tribool hasPath = boost::logic::indeterminate); + void updateSpellbook(const CGHeroInstance *h); + void updateNextHero(const CGHeroInstance *h); + + /// changes current adventure map mode; used to switch between default view and world view; scale is ignored if EAdvMapMode == NORMAL + void changeMode(EAdvMapMode newMode, float newScale = 0.36f); + + void handleMapScrollingUpdate(); + void handleSwipeUpdate(); + +private: + void ShowMoveDetailsInStatusbar(const CGHeroInstance & hero, const CGPathNode & pathNode); +}; + +extern std::shared_ptr adventureInt; From 37d6d21e739cdc743672e929d7f231380d45fec3 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:17:14 +0200 Subject: [PATCH 55/79] Moved CResDataBar into a separate file --- client/adventureMap/{CAdvmapInterface.cpp => CResDataBar.cpp} | 0 client/adventureMap/{CAdvmapInterface.h => CResDataBar.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/adventureMap/{CAdvmapInterface.cpp => CResDataBar.cpp} (100%) rename client/adventureMap/{CAdvmapInterface.h => CResDataBar.h} (100%) diff --git a/client/adventureMap/CAdvmapInterface.cpp b/client/adventureMap/CResDataBar.cpp similarity index 100% rename from client/adventureMap/CAdvmapInterface.cpp rename to client/adventureMap/CResDataBar.cpp diff --git a/client/adventureMap/CAdvmapInterface.h b/client/adventureMap/CResDataBar.h similarity index 100% rename from client/adventureMap/CAdvmapInterface.h rename to client/adventureMap/CResDataBar.h From 6fd1b9927c9fc6e4528cc6597a69d56de983c338 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:17:20 +0200 Subject: [PATCH 56/79] Restore CAdvMapInterface --- client/adventureMap/CAdvmapInterface.cpp | 2021 ++++++++++++++++++++++ client/adventureMap/CAdvmapInterface.h | 276 +++ 2 files changed, 2297 insertions(+) create mode 100644 client/adventureMap/CAdvmapInterface.cpp create mode 100644 client/adventureMap/CAdvmapInterface.h diff --git a/client/adventureMap/CAdvmapInterface.cpp b/client/adventureMap/CAdvmapInterface.cpp new file mode 100644 index 000000000..d0529f744 --- /dev/null +++ b/client/adventureMap/CAdvmapInterface.cpp @@ -0,0 +1,2021 @@ +/* + * CAdvmapInterface.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#include "StdInc.h" +#include "CAdvmapInterface.h" + +#include "CCastleInterface.h" +#include "CHeroWindow.h" +#include "CKingdomInterface.h" +#include "CSpellWindow.h" +#include "CTradeWindow.h" +#include "GUIClasses.h" +#include "InfoWindows.h" + +#include "../CBitmapHandler.h" +#include "../CGameInfo.h" +#include "../CMessage.h" +#include "../CMusicHandler.h" +#include "../CPlayerInterface.h" +#include "../mainmenu/CMainMenu.h" +#include "../lobby/CSelectionBase.h" +#include "../lobby/CCampaignInfoScreen.h" +#include "../lobby/CSavingScreen.h" +#include "../lobby/CScenarioInfoScreen.h" +#include "../Graphics.h" +#include "../mapHandler.h" + +#include "../gui/CAnimation.h" +#include "../gui/CursorHandler.h" +#include "../gui/CGuiHandler.h" +#include "../gui/SDL_Extensions.h" +#include "../widgets/MiscWidgets.h" + +#include "../../CCallback.h" + +#include "../../lib/CConfigHandler.h" +#include "../../lib/CGameState.h" +#include "../../lib/CGeneralTextHandler.h" +#include "../../lib/CHeroHandler.h" +#include "../../lib/CSoundBase.h" +#include "../../lib/spells/CSpellHandler.h" +#include "../../lib/CTownHandler.h" +#include "../../lib/JsonNode.h" +#include "../../lib/mapObjects/CGHeroInstance.h" +#include "../../lib/mapping/CMap.h" +#include "../../lib/UnlockGuard.h" +#include "../../lib/VCMI_Lib.h" +#include "../../lib/StartInfo.h" +#include "../../lib/mapping/CMapInfo.h" +#include "../../lib/TerrainHandler.h" + +#include +#include + +#define ADVOPT (conf.go()->ac) +using namespace CSDL_Ext; + +std::shared_ptr adventureInt; + +static void setScrollingCursor(ui8 direction) +{ + if(direction & CAdvMapInt::RIGHT) + { + if(direction & CAdvMapInt::UP) + CCS->curh->set(Cursor::Map::SCROLL_NORTHEAST); + else if(direction & CAdvMapInt::DOWN) + CCS->curh->set(Cursor::Map::SCROLL_SOUTHEAST); + else + CCS->curh->set(Cursor::Map::SCROLL_EAST); + } + else if(direction & CAdvMapInt::LEFT) + { + if(direction & CAdvMapInt::UP) + CCS->curh->set(Cursor::Map::SCROLL_NORTHWEST); + else if(direction & CAdvMapInt::DOWN) + CCS->curh->set(Cursor::Map::SCROLL_SOUTHWEST); + else + CCS->curh->set(Cursor::Map::SCROLL_WEST); + } + else if(direction & CAdvMapInt::UP) + CCS->curh->set(Cursor::Map::SCROLL_NORTH); + else if(direction & CAdvMapInt::DOWN) + CCS->curh->set(Cursor::Map::SCROLL_SOUTH); +} + +CTerrainRect::CTerrainRect() + : fadeSurface(nullptr), + lastRedrawStatus(EMapAnimRedrawStatus::OK), + fadeAnim(std::make_shared()), + curHoveredTile(-1,-1,-1), + currentPath(nullptr) +{ + tilesw=(ADVOPT.advmapW+31)/32; + tilesh=(ADVOPT.advmapH+31)/32; + pos.x=ADVOPT.advmapX; + pos.y=ADVOPT.advmapY; + pos.w=ADVOPT.advmapW; + pos.h=ADVOPT.advmapH; + moveX = moveY = 0; + addUsedEvents(LCLICK | RCLICK | MCLICK | HOVER | MOVE); +} + +CTerrainRect::~CTerrainRect() +{ + if(fadeSurface) + SDL_FreeSurface(fadeSurface); +} + +void CTerrainRect::deactivate() +{ + CIntObject::deactivate(); + curHoveredTile = int3(-1,-1,-1); //we lost info about hovered tile when disabling +} + +void CTerrainRect::clickLeft(tribool down, bool previousState) +{ + if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) + return; + if(indeterminate(down)) + return; + +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + if(adventureInt->swipeEnabled) + { + if(handleSwipeStateChange((bool)down == true)) + { + return; // if swipe is enabled, we don't process "down" events and wait for "up" (to make sure this wasn't a swiping gesture) + } + } + else + { +#endif + if(down == false) + return; +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + } +#endif + int3 mp = whichTileIsIt(); + if(mp.x < 0 || mp.y < 0 || mp.x >= LOCPLINT->cb->getMapSize().x || mp.y >= LOCPLINT->cb->getMapSize().y) + return; + + adventureInt->tileLClicked(mp); +} + +void CTerrainRect::clickRight(tribool down, bool previousState) +{ +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + if(adventureInt->swipeEnabled && isSwiping) + return; +#endif + if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) + return; + int3 mp = whichTileIsIt(); + + if(CGI->mh->map->isInTheMap(mp) && down) + adventureInt->tileRClicked(mp); +} + +void CTerrainRect::clickMiddle(tribool down, bool previousState) +{ + handleSwipeStateChange((bool)down == true); +} + +void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent) +{ + handleHover(sEvent); + + if(!adventureInt->swipeEnabled) + return; + + handleSwipeMove(sEvent); +} + +void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent) +{ +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + if(sEvent.state == 0 || GH.multifinger) // any "button" is enough on mobile +#else + if((sEvent.state & SDL_BUTTON_MMASK) == 0) // swipe only works with middle mouse on other platforms +#endif + { + return; + } + + if(!isSwiping) + { + // try to distinguish if this touch was meant to be a swipe or just fat-fingering press + if(abs(sEvent.x - swipeInitialRealPos.x) > SwipeTouchSlop || + abs(sEvent.y - swipeInitialRealPos.y) > SwipeTouchSlop) + { + isSwiping = true; + } + } + + if(isSwiping) + { + adventureInt->swipeTargetPosition.x = + swipeInitialMapPos.x + static_cast(swipeInitialRealPos.x - sEvent.x) / 32; + adventureInt->swipeTargetPosition.y = + swipeInitialMapPos.y + static_cast(swipeInitialRealPos.y - sEvent.y) / 32; + adventureInt->swipeMovementRequested = true; + } +} + +bool CTerrainRect::handleSwipeStateChange(bool btnPressed) +{ + if(btnPressed) + { + swipeInitialRealPos = int3(GH.getCursorPosition().x, GH.getCursorPosition().y, 0); + swipeInitialMapPos = int3(adventureInt->position); + return true; + } + else if(isSwiping) // only accept this touch if it wasn't a swipe + { + isSwiping = false; + return true; + } + return false; +} + +void CTerrainRect::handleHover(const SDL_MouseMotionEvent &sEvent) +{ + int3 tHovered = whichTileIsIt(sEvent.x, sEvent.y); + int3 pom = adventureInt->verifyPos(tHovered); + + if(tHovered != pom) //tile outside the map + { + CCS->curh->set(Cursor::Map::POINTER); + return; + } + + if (pom != curHoveredTile) + { + curHoveredTile = pom; + adventureInt->tileHovered(pom); + } +} + +void CTerrainRect::hover(bool on) +{ + if (!on) + { + adventureInt->statusbar->clear(); + CCS->curh->set(Cursor::Map::POINTER); + } + //Hoverable::hover(on); +} +void CTerrainRect::showPath(const Rect & extRect, SDL_Surface * to) +{ + const static int pns[9][9] = { + {16, 17, 18, 7, -1, 19, 6, 5, -1}, + { 8, 9, 18, 7, -1, 19, 6, -1, 20}, + { 8, 1, 10, 7, -1, 19, -1, 21, 20}, + {24, 17, 18, 15, -1, -1, 6, 5, 4}, + {-1, -1, -1, -1, -1, -1, -1, -1, -1}, + { 8, 1, 2, -1, -1, 11, 22, 21, 20}, + {24, 17, -1, 23, -1, 3, 14, 5, 4}, + {24, -1, 2, 23, -1, 3, 22, 13, 4}, + {-1, 1, 2, 23, -1, 3, 22, 21, 12} + }; //table of magic values TODO meaning, change variable name + + for (int i = 0; i < -1 + (int)currentPath->nodes.size(); ++i) + { + const int3 &curPos = currentPath->nodes[i].coord, &nextPos = currentPath->nodes[i+1].coord; + if(curPos.z != adventureInt->position.z) + continue; + + int pn=-1;//number of picture + if (i==0) //last tile + { + int x = 32*(curPos.x-adventureInt->position.x)+CGI->mh->offsetX + pos.x, + y = 32*(curPos.y-adventureInt->position.y)+CGI->mh->offsetY + pos.y; + if (x<0 || y<0 || x>pos.w || y>pos.h) + continue; + pn=0; + } + else + { + const int3 &prevPos = currentPath->nodes[i-1].coord; + std::vector & cv = currentPath->nodes; + + /* Vector directions + * 0 1 2 + * \ | / + * 3 - 4 - 5 + * / | \ + * 6 7 8 + *For example: + * | + * |__\ + * / + * is id1=7, id2=5 (pns[7][5]) + */ + bool pathContinuous = curPos.areNeighbours(nextPos) && curPos.areNeighbours(prevPos); + if(pathContinuous && cv[i].action != CGPathNode::EMBARK && cv[i].action != CGPathNode::DISEMBARK) + { + int id1=(curPos.x-nextPos.x+1)+3*(curPos.y-nextPos.y+1); //Direction of entering vector + int id2=(cv[i-1].coord.x-curPos.x+1)+3*(cv[i-1].coord.y-curPos.y+1); //Direction of exiting vector + pn=pns[id1][id2]; + } + else //path discontinuity or sea/land transition (eg. when moving through Subterranean Gate or Boat) + { + pn = 0; + } + } + if (currentPath->nodes[i].turns) + pn+=25; + if (pn>=0) + { + const auto arrow = graphics->heroMoveArrows->getImage(pn); + + int x = 32*(curPos.x-adventureInt->position.x)+CGI->mh->offsetX + pos.x, + y = 32*(curPos.y-adventureInt->position.y)+CGI->mh->offsetY + pos.y; + if (x< -32 || y< -32 || x>pos.w || y>pos.h) + continue; + int hvx = (x + arrow->width()) - (pos.x + pos.w), + hvy = (y + arrow->height()) - (pos.y + pos.h); + + Rect prevClip; + CSDL_Ext::getClipRect(to, prevClip); + CSDL_Ext::setClipRect(to, extRect); //preventing blitting outside of that rect + + if(ADVOPT.smoothMove) //version for smooth hero move, with pos shifts + { + if (hvx<0 && hvy<0) + { + arrow->draw(to, x + moveX, y + moveY); + } + else if(hvx<0) + { + Rect srcRect = genRect(arrow->height() - hvy, arrow->width(), 0, 0); + arrow->draw(to, x + moveX, y + moveY, &srcRect); + } + else if (hvy<0) + { + Rect srcRect = genRect(arrow->height(), arrow->width() - hvx, 0, 0); + arrow->draw(to, x + moveX, y + moveY, &srcRect); + } + else + { + Rect srcRect = genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); + arrow->draw(to, x + moveX, y + moveY, &srcRect); + } + } + else //standard version + { + if (hvx<0 && hvy<0) + { + arrow->draw(to, x, y); + } + else if(hvx<0) + { + Rect srcRect = genRect(arrow->height() - hvy, arrow->width(), 0, 0); + arrow->draw(to, x, y, &srcRect); + } + else if (hvy<0) + { + Rect srcRect = genRect(arrow->height(), arrow->width() - hvx, 0, 0); + arrow->draw(to, x, y, &srcRect); + } + else + { + Rect srcRect = genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); + arrow->draw(to, x, y, &srcRect); + } + } + CSDL_Ext::setClipRect(to, prevClip); + + } + } //for (int i=0;inodes.size()-1;i++) +} + +void CTerrainRect::show(SDL_Surface * to) +{ + if (adventureInt->mode == EAdvMapMode::NORMAL) + { + MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), pos); + info.otherheroAnim = true; + info.anim = adventureInt->anim; + info.heroAnim = adventureInt->heroAnim; + if (ADVOPT.smoothMove) + info.movement = int3(moveX, moveY, 0); + + lastRedrawStatus = CGI->mh->drawTerrainRectNew(to, &info); + if (fadeAnim->isFading()) + { + Rect r(pos); + fadeAnim->update(); + fadeAnim->draw(to, r.topLeft()); + } + + if (currentPath/* && adventureInt->position.z==currentPath->startPos().z*/) //drawing path + { + showPath(pos, to); + } + } +} + +void CTerrainRect::showAll(SDL_Surface * to) +{ + // world view map is static and doesn't need redraw every frame + if (adventureInt->mode == EAdvMapMode::WORLD_VIEW) + { + MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), pos, adventureInt->worldViewIcons); + info.scaled = true; + info.scale = adventureInt->worldViewScale; + adventureInt->worldViewOptions.adjustDrawingInfo(info); + CGI->mh->drawTerrainRectNew(to, &info); + } +} + +void CTerrainRect::showAnim(SDL_Surface * to) +{ + if (fadeAnim->isFading()) + show(to); + else if (lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED) + show(to); // currently the same; maybe we should pass some flag to map handler so it redraws ONLY tiles that need redraw instead of full +} + +int3 CTerrainRect::whichTileIsIt(const int x, const int y) +{ + int3 ret; + ret.x = adventureInt->position.x + ((x-CGI->mh->offsetX-pos.x)/32); + ret.y = adventureInt->position.y + ((y-CGI->mh->offsetY-pos.y)/32); + ret.z = adventureInt->position.z; + return ret; +} + +int3 CTerrainRect::whichTileIsIt() +{ + return whichTileIsIt(GH.getCursorPosition().x, GH.getCursorPosition().y); +} + +int3 CTerrainRect::tileCountOnScreen() +{ + switch (adventureInt->mode) + { + default: + logGlobal->error("Unknown map mode %d", (int)adventureInt->mode); + return int3(); + case EAdvMapMode::NORMAL: + return int3(tilesw, tilesh, 1); + case EAdvMapMode::WORLD_VIEW: + return int3((si32)(tilesw / adventureInt->worldViewScale), (si32)(tilesh / adventureInt->worldViewScale), 1); + } +} + +void CTerrainRect::fadeFromCurrentView() +{ + if (!ADVOPT.screenFading) + return; + if (adventureInt->mode == EAdvMapMode::WORLD_VIEW) + return; + + if (!fadeSurface) + fadeSurface = CSDL_Ext::newSurface(pos.w, pos.h); + CSDL_Ext::blitSurface(screen, fadeSurface, Point(0,0)); + fadeAnim->init(CFadeAnimation::EMode::OUT, fadeSurface); +} + +bool CTerrainRect::needsAnimUpdate() +{ + return fadeAnim->isFading() || lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED; +} + +void CResDataBar::clickRight(tribool down, bool previousState) +{ +} + +CResDataBar::CResDataBar(const std::string & defname, int x, int y, int offx, int offy, int resdist, int datedist) +{ + pos.x += x; + pos.y += y; + OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); + background = std::make_shared(defname, 0, 0); + background->colorize(LOCPLINT->playerID); + + pos.w = background->pos.w; + pos.h = background->pos.h; + + txtpos.resize(8); + for (int i = 0; i < 8 ; i++) + { + txtpos[i].first = pos.x + offx + resdist*i; + txtpos[i].second = pos.y + offy; + } + txtpos[7].first = txtpos[6].first + datedist; + datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] + + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s"; + addUsedEvents(RCLICK); +} + +CResDataBar::CResDataBar() +{ + pos.x += ADVOPT.resdatabarX; + pos.y += ADVOPT.resdatabarY; + + OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); + background = std::make_shared(ADVOPT.resdatabarG, 0, 0); + background->colorize(LOCPLINT->playerID); + + pos.w = background->pos.w; + pos.h = background->pos.h; + + txtpos.resize(8); + for (int i = 0; i < 8 ; i++) + { + txtpos[i].first = pos.x + ADVOPT.resOffsetX + ADVOPT.resDist*i; + txtpos[i].second = pos.y + ADVOPT.resOffsetY; + } + txtpos[7].first = txtpos[6].first + ADVOPT.resDateDist; + datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] + + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s"; +} + +CResDataBar::~CResDataBar() = default; + +void CResDataBar::draw(SDL_Surface * to) +{ + //TODO: all this should be labels, but they require proper text update on change + for (auto i=Res::WOOD; i<=Res::GOLD; vstd::advance(i, 1)) + { + std::string text = boost::lexical_cast(LOCPLINT->cb->getResourceAmount(i)); + + graphics->fonts[FONT_SMALL]->renderTextLeft(to, text, Colors::WHITE, Point(txtpos[i].first,txtpos[i].second)); + } + std::vector temp; + + temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::MONTH))); + temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::WEEK))); + temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK))); + + graphics->fonts[FONT_SMALL]->renderTextLeft(to, processStr(datetext,temp), Colors::WHITE, Point(txtpos[7].first,txtpos[7].second)); +} + +void CResDataBar::show(SDL_Surface * to) +{ + +} + +void CResDataBar::showAll(SDL_Surface * to) +{ + CIntObject::showAll(to); + draw(to); +} + +CAdvMapInt::CAdvMapInt(): + mode(EAdvMapMode::NORMAL), + worldViewScale(0.0f), //actual init later in changeMode + minimap(Rect(ADVOPT.minimapX, ADVOPT.minimapY, ADVOPT.minimapW, ADVOPT.minimapH)), + statusbar(CGStatusBar::create(ADVOPT.statusbarX,ADVOPT.statusbarY,ADVOPT.statusbarG)), + heroList(ADVOPT.hlistSize, Point(ADVOPT.hlistX, ADVOPT.hlistY), ADVOPT.hlistAU, ADVOPT.hlistAD), + townList(ADVOPT.tlistSize, Point(ADVOPT.tlistX, ADVOPT.tlistY), ADVOPT.tlistAU, ADVOPT.tlistAD), + infoBar(Rect(ADVOPT.infoboxX, ADVOPT.infoboxY, 192, 192)), state(NA), + spellBeingCasted(nullptr), position(int3(0, 0, 0)), selection(nullptr), + updateScreen(false), anim(0), animValHitCount(0), heroAnim(0), heroAnimValHitCount(0), + activeMapPanel(nullptr), duringAITurn(false), scrollingDir(0), scrollingState(false), + swipeEnabled(settings["general"]["swipe"].Bool()), swipeMovementRequested(false), + swipeTargetPosition(int3(-1, -1, -1)) +{ + pos.x = pos.y = 0; + pos.w = screen->w; + pos.h = screen->h; + strongInterest = true; // handle all mouse move events to prevent dead mouse move space in fullscreen mode + townList.onSelect = std::bind(&CAdvMapInt::selectionChanged,this); + bg = IImage::createFromFile(ADVOPT.mainGraphic); + if(!ADVOPT.worldViewGraphic.empty()) + { + bgWorldView = IImage::createFromFile(ADVOPT.worldViewGraphic); + } + else + { + bgWorldView = nullptr; + logGlobal->warn("ADVOPT.worldViewGraphic is empty => bitmap not loaded"); + } + if (!bgWorldView) + { + logGlobal->warn("bgWorldView not defined in resolution config; fallback to VWorld.bmp"); + bgWorldView = IImage::createFromFile("VWorld.bmp"); + } + + worldViewIcons = std::make_shared("VwSymbol");//todo: customize with ADVOPT + worldViewIcons->preload(); + + for(int g = 0; g < ADVOPT.gemG.size(); ++g) + { + gems.push_back(std::make_shared(ADVOPT.gemG[g], 0, 0, ADVOPT.gemX[g], ADVOPT.gemY[g])); + } + + auto makeButton = [&](int textID, std::function callback, config::ButtonInfo info, int key) -> std::shared_ptr + { + auto button = std::make_shared(Point(info.x, info.y), info.defName, CGI->generaltexth->zelp[textID], callback, key, info.playerColoured); + for(auto image : info.additionalDefs) + button->addImage(image); + return button; + }; + + kingOverview = makeButton(293, std::bind(&CAdvMapInt::fshowOverview,this), ADVOPT.kingOverview, SDLK_k); + underground = makeButton(294, std::bind(&CAdvMapInt::fswitchLevel,this), ADVOPT.underground, SDLK_u); + questlog = makeButton(295, std::bind(&CAdvMapInt::fshowQuestlog,this), ADVOPT.questlog, SDLK_q); + sleepWake = makeButton(296, std::bind(&CAdvMapInt::fsleepWake,this), ADVOPT.sleepWake, SDLK_w); + moveHero = makeButton(297, std::bind(&CAdvMapInt::fmoveHero,this), ADVOPT.moveHero, SDLK_m); + spellbook = makeButton(298, std::bind(&CAdvMapInt::fshowSpellbok,this), ADVOPT.spellbook, SDLK_c); + advOptions = makeButton(299, std::bind(&CAdvMapInt::fadventureOPtions,this), ADVOPT.advOptions, SDLK_a); + sysOptions = makeButton(300, std::bind(&CAdvMapInt::fsystemOptions,this), ADVOPT.sysOptions, SDLK_o); + nextHero = makeButton(301, std::bind(&CAdvMapInt::fnextHero,this), ADVOPT.nextHero, SDLK_h); + endTurn = makeButton(302, std::bind(&CAdvMapInt::fendTurn,this), ADVOPT.endTurn, SDLK_e); + + int panelSpaceBottom = screen->h - resdatabar.pos.h - 4; + + panelMain = std::make_shared(nullptr, Point(0, 0)); + // TODO correct drawing position + panelWorldView = std::make_shared(worldViewIcons, bgWorldView, Point(heroList.pos.x - 2, 195), panelSpaceBottom, LOCPLINT->playerID); + + panelMain->addChildColorableButton(kingOverview); + panelMain->addChildColorableButton(underground); + panelMain->addChildColorableButton(questlog); + panelMain->addChildColorableButton(sleepWake); + panelMain->addChildColorableButton(moveHero); + panelMain->addChildColorableButton(spellbook); + panelMain->addChildColorableButton(advOptions); + panelMain->addChildColorableButton(sysOptions); + panelMain->addChildColorableButton(nextHero); + panelMain->addChildColorableButton(endTurn); + + + // TODO move configs to resolutions.json, similarly to previous buttons + config::ButtonInfo worldViewBackConfig = config::ButtonInfo(); + worldViewBackConfig.defName = "IOK6432.DEF"; + worldViewBackConfig.x = screen->w - 73; + worldViewBackConfig.y = 343 + 195; + worldViewBackConfig.playerColoured = false; + panelWorldView->addChildToPanel( + makeButton(288, std::bind(&CAdvMapInt::fworldViewBack,this), worldViewBackConfig, SDLK_ESCAPE), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewPuzzleConfig = config::ButtonInfo(); + worldViewPuzzleConfig.defName = "VWPUZ.DEF"; + worldViewPuzzleConfig.x = screen->w - 188; + worldViewPuzzleConfig.y = 343 + 195; + worldViewPuzzleConfig.playerColoured = false; + panelWorldView->addChildToPanel( // no help text for this one + std::make_shared(Point(worldViewPuzzleConfig.x, worldViewPuzzleConfig.y), worldViewPuzzleConfig.defName, std::pair(), + std::bind(&CPlayerInterface::showPuzzleMap,LOCPLINT), SDLK_p, worldViewPuzzleConfig.playerColoured), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewScale1xConfig = config::ButtonInfo(); + worldViewScale1xConfig.defName = "VWMAG1.DEF"; + worldViewScale1xConfig.x = screen->w - 191; + worldViewScale1xConfig.y = 23 + 195; + worldViewScale1xConfig.playerColoured = false; + panelWorldView->addChildToPanel( // help text is wrong for this button + makeButton(291, std::bind(&CAdvMapInt::fworldViewScale1x,this), worldViewScale1xConfig, SDLK_1), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewScale2xConfig = config::ButtonInfo(); + worldViewScale2xConfig.defName = "VWMAG2.DEF"; + worldViewScale2xConfig.x = screen->w - 191 + 63; + worldViewScale2xConfig.y = 23 + 195; + worldViewScale2xConfig.playerColoured = false; + panelWorldView->addChildToPanel( // help text is wrong for this button + makeButton(291, std::bind(&CAdvMapInt::fworldViewScale2x,this), worldViewScale2xConfig, SDLK_2), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewScale4xConfig = config::ButtonInfo(); + worldViewScale4xConfig.defName = "VWMAG4.DEF"; + worldViewScale4xConfig.x = screen->w - 191 + 126; + worldViewScale4xConfig.y = 23 + 195; + worldViewScale4xConfig.playerColoured = false; + panelWorldView->addChildToPanel( // help text is wrong for this button + makeButton(291, std::bind(&CAdvMapInt::fworldViewScale4x,this), worldViewScale4xConfig, SDLK_4), ACTIVATE | DEACTIVATE); + + config::ButtonInfo worldViewUndergroundConfig = config::ButtonInfo(); + worldViewUndergroundConfig.defName = "IAM010.DEF"; + worldViewUndergroundConfig.additionalDefs.push_back("IAM003.DEF"); + worldViewUndergroundConfig.x = screen->w - 115; + worldViewUndergroundConfig.y = 343 + 195; + worldViewUndergroundConfig.playerColoured = true; + worldViewUnderground = makeButton(294, std::bind(&CAdvMapInt::fswitchLevel,this), worldViewUndergroundConfig, SDLK_u); + panelWorldView->addChildColorableButton(worldViewUnderground); + + setPlayer(LOCPLINT->playerID); + + int iconColorMultiplier = player.getNum() * 19; + int wvLeft = heroList.pos.x - 2; // TODO correct drawing position + //int wvTop = 195; + for (int i = 0; i < 5; ++i) + { + panelWorldView->addChildIcon(std::pair(i, Point(5, 58 + i * 20)), iconColorMultiplier); + panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 263 + i * 20, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, + Colors::WHITE, CGI->generaltexth->allTexts[612 + i])); + } + for (int i = 0; i < 7; ++i) + { + panelWorldView->addChildIcon(std::pair(i + 5, Point(5, 182 + i * 20)), iconColorMultiplier); + panelWorldView->addChildIcon(std::pair(i + 12, Point(160, 182 + i * 20)), iconColorMultiplier); + panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 387 + i * 20, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, + Colors::WHITE, CGI->generaltexth->allTexts[619 + i])); + } + panelWorldView->addChildToPanel(std::make_shared(wvLeft + 5, 367, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, + Colors::WHITE, CGI->generaltexth->allTexts[617])); + panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 367, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, + Colors::WHITE, CGI->generaltexth->allTexts[618])); + + activeMapPanel = panelMain; + + changeMode(EAdvMapMode::NORMAL); + + underground->block(!CGI->mh->map->twoLevel); + questlog->block(!CGI->mh->map->quests.size()); + worldViewUnderground->block(!CGI->mh->map->twoLevel); + + addUsedEvents(MOVE); +} + +void CAdvMapInt::fshowOverview() +{ + GH.pushIntT(); +} + +void CAdvMapInt::fworldViewBack() +{ + changeMode(EAdvMapMode::NORMAL); + CGI->mh->discardWorldViewCache(); + + auto hero = curHero(); + if (hero) + centerOn(hero); +} + +void CAdvMapInt::fworldViewScale1x() +{ + // TODO set corresponding scale button to "selected" mode + changeMode(EAdvMapMode::WORLD_VIEW, 0.22f); +} + +void CAdvMapInt::fworldViewScale2x() +{ + changeMode(EAdvMapMode::WORLD_VIEW, 0.36f); +} + +void CAdvMapInt::fworldViewScale4x() +{ + changeMode(EAdvMapMode::WORLD_VIEW, 0.5f); +} + +void CAdvMapInt::fswitchLevel() +{ + // with support for future multi-level maps :) + int maxLevels = CGI->mh->map->levels(); + if (maxLevels < 2) + return; + + position.z = (position.z + 1) % maxLevels; + + underground->setIndex(position.z, true); + underground->redraw(); + + worldViewUnderground->setIndex(position.z, true); + worldViewUnderground->redraw(); + + updateScreen = true; + minimap.setLevel(position.z); + + if (mode == EAdvMapMode::WORLD_VIEW) + terrain.redraw(); +} +void CAdvMapInt::fshowQuestlog() +{ + LOCPLINT->showQuestLog(); +} +void CAdvMapInt::fsleepWake() +{ + const CGHeroInstance *h = curHero(); + if (!h) + return; + bool newSleep = !isHeroSleeping(h); + setHeroSleeping(h, newSleep); + updateSleepWake(h); + if (newSleep) + { + fnextHero(); + + //moveHero.block(true); + //uncomment to enable original HoMM3 behaviour: + //move button is disabled for hero going to sleep, even though it's enabled when you reselect him + } +} + +void CAdvMapInt::fmoveHero() +{ + const CGHeroInstance *h = curHero(); + if (!h || !terrain.currentPath || !CGI->mh->canStartHeroMovement()) + return; + + LOCPLINT->moveHero(h, *terrain.currentPath); +} + +void CAdvMapInt::fshowSpellbok() +{ + if (!curHero()) //checking necessary values + return; + + centerOn(selection); + + GH.pushIntT(curHero(), LOCPLINT, false); +} + +void CAdvMapInt::fadventureOPtions() +{ + GH.pushIntT(); +} + +void CAdvMapInt::fsystemOptions() +{ + GH.pushIntT(); +} + +void CAdvMapInt::fnextHero() +{ + auto hero = dynamic_cast(selection); + int next = getNextHeroIndex(vstd::find_pos(LOCPLINT->wanderingHeroes, hero)); + if (next < 0) + return; + select(LOCPLINT->wanderingHeroes[next], true); +} + +void CAdvMapInt::fendTurn() +{ + if(!LOCPLINT->makingTurn) + return; + + if(settings["adventure"]["heroReminder"].Bool()) + { + for(auto hero : LOCPLINT->wanderingHeroes) + { + if(!isHeroSleeping(hero) && hero->movement > 0) + { + // Only show hero reminder if conditions met: + // - There still movement points + // - Hero don't have a path or there not points for first step on path + auto path = LOCPLINT->getAndVerifyPath(hero); + if(!path || path->nodes.size() < 2 || !path->nodes[path->nodes.size()-2].turns) + { + LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[55], std::bind(&CAdvMapInt::endingTurn, this), nullptr); + return; + } + } + } + } + endingTurn(); +} + +void CAdvMapInt::updateSleepWake(const CGHeroInstance *h) +{ + sleepWake->block(!h); + if (!h) + return; + bool state = isHeroSleeping(h); + sleepWake->setIndex(state ? 1 : 0, true); + sleepWake->assignedKeys.clear(); + sleepWake->assignedKeys.insert(state ? SDLK_w : SDLK_z); +} + +void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath) +{ + if(!h) + { + moveHero->block(true); + return; + } + //default value is for everywhere but CPlayerInterface::moveHero, because paths are not updated from there immediately + if(boost::logic::indeterminate(hasPath)) + hasPath = LOCPLINT->paths[h].nodes.size() ? true : false; + + moveHero->block(!(bool)hasPath || (h->movement == 0)); +} + +void CAdvMapInt::updateSpellbook(const CGHeroInstance *h) +{ + spellbook->block(!h); +} + +int CAdvMapInt::getNextHeroIndex(int startIndex) +{ + if (LOCPLINT->wanderingHeroes.size() == 0) + return -1; + if (startIndex < 0) + startIndex = 0; + int i = startIndex; + do + { + i++; + if (i >= LOCPLINT->wanderingHeroes.size()) + i = 0; + } + while (((LOCPLINT->wanderingHeroes[i]->movement == 0) || isHeroSleeping(LOCPLINT->wanderingHeroes[i])) && (i != startIndex)); + + if ((LOCPLINT->wanderingHeroes[i]->movement != 0) && !isHeroSleeping(LOCPLINT->wanderingHeroes[i])) + return i; + else + return -1; +} + +void CAdvMapInt::updateNextHero(const CGHeroInstance *h) +{ + int start = vstd::find_pos(LOCPLINT->wanderingHeroes, h); + int next = getNextHeroIndex(start); + if (next < 0) + { + nextHero->block(true); + return; + } + const CGHeroInstance *nextH = LOCPLINT->wanderingHeroes[next]; + bool noActiveHeroes = (next == start) && ((nextH->movement == 0) || isHeroSleeping(nextH)); + nextHero->block(noActiveHeroes); +} + +void CAdvMapInt::activate() +{ + CIntObject::activate(); + if (!(active & KEYBOARD)) + CIntObject::activate(KEYBOARD); + + screenBuf = screen; + GH.statusbar = statusbar; + + if(LOCPLINT) + { + LOCPLINT->cingconsole->activate(); + LOCPLINT->cingconsole->pos = this->pos; + } + + if(!duringAITurn) + { + activeMapPanel->activate(); + if (mode == EAdvMapMode::NORMAL) + { + heroList.activate(); + townList.activate(); + infoBar.activate(); + } + minimap.activate(); + terrain.activate(); + statusbar->activate(); + + GH.fakeMouseMove(); //to restore the cursor + } +} + +void CAdvMapInt::deactivate() +{ + CIntObject::deactivate(); + + if(!duringAITurn) + { + scrollingDir = 0; + + CCS->curh->set(Cursor::Map::POINTER); + activeMapPanel->deactivate(); + if (mode == EAdvMapMode::NORMAL) + { + heroList.deactivate(); + townList.deactivate(); + infoBar.deactivate(); + } + minimap.deactivate(); + terrain.deactivate(); + statusbar->deactivate(); + } +} + +void CAdvMapInt::showAll(SDL_Surface * to) +{ + bg->draw(to, 0, 0); + + if(state != INGAME) + return; + + switch (mode) + { + case EAdvMapMode::NORMAL: + + heroList.showAll(to); + townList.showAll(to); + infoBar.showAll(to); + break; + case EAdvMapMode::WORLD_VIEW: + + terrain.showAll(to); + break; + } + activeMapPanel->showAll(to); + + updateScreen = true; + minimap.showAll(to); + show(to); + + + resdatabar.showAll(to); + + statusbar->show(to); + + LOCPLINT->cingconsole->show(to); +} + +bool CAdvMapInt::isHeroSleeping(const CGHeroInstance *hero) +{ + if (!hero) + return false; + + return vstd::contains(LOCPLINT->sleepingHeroes, hero); +} + +void CAdvMapInt::setHeroSleeping(const CGHeroInstance *hero, bool sleep) +{ + if (sleep) + LOCPLINT->sleepingHeroes.push_back(hero); //FIXME: should we check for existence? + else + LOCPLINT->sleepingHeroes -= hero; + updateNextHero(nullptr); +} + +void CAdvMapInt::show(SDL_Surface * to) +{ + if(state != INGAME) + return; + + ++animValHitCount; //for animations + + if(animValHitCount % 2 == 0) + { + ++heroAnim; + } + if(animValHitCount >= 8) + { + CGI->mh->updateWater(); + animValHitCount = 0; + ++anim; + updateScreen = true; + } + + if(swipeEnabled) + { + handleSwipeUpdate(); + } +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) // on mobile, map-moving mode is exclusive (TODO technically it might work with both enabled; to be checked) + else +#endif + { + handleMapScrollingUpdate(); + } + + for(int i = 0; i < 4; i++) + { + if(settings["session"]["spectate"].Bool()) + gems[i]->setFrame(PlayerColor(1).getNum()); + else + gems[i]->setFrame(LOCPLINT->playerID.getNum()); + } + if(updateScreen) + { + int3 betterPos = LOCPLINT->repairScreenPos(position); + if (betterPos != position) + { + logGlobal->warn("Incorrect position for adventure map!"); + position = betterPos; + } + + terrain.show(to); + for(int i = 0; i < 4; i++) + gems[i]->showAll(to); + updateScreen=false; + LOCPLINT->cingconsole->show(to); + } + else if (terrain.needsAnimUpdate()) + { + terrain.showAnim(to); + for(int i = 0; i < 4; i++) + gems[i]->showAll(to); + } + + infoBar.show(to); + statusbar->showAll(to); +} + +void CAdvMapInt::handleMapScrollingUpdate() +{ + int scrollSpeed = static_cast(settings["adventure"]["scrollSpeed"].Float()); + //if advmap needs updating AND (no dialog is shown OR ctrl is pressed) + if((animValHitCount % (4 / scrollSpeed)) == 0 + && ((GH.topInt().get() == this) || isCtrlKeyDown())) + { + if((scrollingDir & LEFT) && (position.x > -CGI->mh->frameW)) + position.x--; + + if((scrollingDir & RIGHT) && (position.x < CGI->mh->map->width - CGI->mh->tilesW + CGI->mh->frameW)) + position.x++; + + if((scrollingDir & UP) && (position.y > -CGI->mh->frameH)) + position.y--; + + if((scrollingDir & DOWN) && (position.y < CGI->mh->map->height - CGI->mh->tilesH + CGI->mh->frameH)) + position.y++; + + if(scrollingDir) + { + setScrollingCursor(scrollingDir); + scrollingState = true; + updateScreen = true; + minimap.redraw(); + if(mode == EAdvMapMode::WORLD_VIEW) + terrain.redraw(); + } + else if(scrollingState) + { + CCS->curh->set(Cursor::Map::POINTER); + scrollingState = false; + } + } +} + +void CAdvMapInt::handleSwipeUpdate() +{ + if(swipeMovementRequested) + { + auto fixedPos = LOCPLINT->repairScreenPos(swipeTargetPosition); + position.x = fixedPos.x; + position.y = fixedPos.y; + CCS->curh->set(Cursor::Map::POINTER); + updateScreen = true; + minimap.redraw(); + swipeMovementRequested = false; + } +} + +void CAdvMapInt::selectionChanged() +{ + const CGTownInstance *to = LOCPLINT->towns[townList.getSelectedIndex()]; + if (selection != to) + select(to); +} + +void CAdvMapInt::centerOn(int3 on, bool fade) +{ + bool switchedLevels = on.z != position.z; + + if (fade) + { + terrain.fadeFromCurrentView(); + } + + switch (mode) + { + default: + case EAdvMapMode::NORMAL: + on.x -= CGI->mh->frameW; // is this intentional? frame size doesn't really have to correspond to camera size... + on.y -= CGI->mh->frameH; + break; + case EAdvMapMode::WORLD_VIEW: + on.x -= static_cast(CGI->mh->tilesW / 2 / worldViewScale); + on.y -= static_cast(CGI->mh->tilesH / 2 / worldViewScale); + break; + } + + + on = LOCPLINT->repairScreenPos(on); + + position = on; + updateScreen=true; + underground->setIndex(on.z,true); //change underground switch button image + underground->redraw(); + worldViewUnderground->setIndex(on.z, true); + worldViewUnderground->redraw(); + if (switchedLevels) + minimap.setLevel(position.z); + minimap.redraw(); + + if (mode == EAdvMapMode::WORLD_VIEW) + terrain.redraw(); +} + +void CAdvMapInt::centerOn(const CGObjectInstance * obj, bool fade) +{ + centerOn(obj->getSightCenter(), fade); +} + +void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) +{ + + if (mode == EAdvMapMode::WORLD_VIEW) + return; + + ui8 Dir = 0; + SDL_Keycode k = key.keysym.sym; + const CGHeroInstance *h = curHero(); //selected hero + const CGTownInstance *t = curTown(); //selected town + + switch(k) + { + case SDLK_g: + if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) + return; + + { + //find first town with tavern + auto itr = range::find_if(LOCPLINT->towns, [](const CGTownInstance * town) + { + return town->hasBuilt(BuildingID::TAVERN); + }); + + if(itr != LOCPLINT->towns.end()) + LOCPLINT->showThievesGuildWindow(*itr); + else + LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithTavern")); + } + return; + case SDLK_i: + if(isActive()) + CAdventureOptions::showScenarioInfo(); + return; + case SDLK_l: + if(isActive()) + LOCPLINT->proposeLoadingGame(); + return; + case SDLK_s: + if(isActive() && key.type == SDL_KEYUP) + GH.pushIntT(); + return; + case SDLK_d: + { + if(h && isActive() && LOCPLINT->makingTurn && key.state == SDL_PRESSED) + LOCPLINT->tryDiggging(h); + return; + } + case SDLK_p: + if(isActive()) + LOCPLINT->showPuzzleMap(); + return; + case SDLK_v: + if(isActive()) + LOCPLINT->viewWorldMap(); + return; + case SDLK_r: + if(isActive() && LOCPLINT->ctrlPressed()) + { + LOCPLINT->showYesNoDialog(CGI->generaltexth->translate("vcmi.adventureMap.confirmRestartGame"), + [](){ LOCPLINT->sendCustomEvent(EUserEvent::RESTART_GAME); }, nullptr); + } + return; + case SDLK_SPACE: //space - try to revisit current object with selected hero + { + if(!isActive()) + return; + if(h && key.state == SDL_PRESSED) + { + auto unlockPim = vstd::makeUnlockGuard(*CPlayerInterface::pim); + //TODO!!!!!!! possible freeze, when GS mutex is locked and network thread can't apply package + //this thread leaves scope and tries to lock pim while holding gs, + //network thread tries to lock gs (appluy cl) while holding pim + //this thread should first lock pim, however gs locking/unlocking is done inside cb + LOCPLINT->cb->moveHero(h,h->pos); + } + } + return; + case SDLK_RETURN: + { + if(!isActive() || !selection || key.state != SDL_PRESSED) + return; + if(h) + LOCPLINT->openHeroWindow(h); + else if(t) + LOCPLINT->openTownWindow(t); + return; + } + case SDLK_ESCAPE: + { + if(isActive() || GH.topInt().get() != this || !spellBeingCasted || key.state != SDL_PRESSED) + return; + + leaveCastingMode(); + return; + } + case SDLK_t: + { + //act on key down if marketplace windows is not already opened + if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) + return; + + if(LOCPLINT->ctrlPressed()) //CTRL + T => open marketplace + { + //check if we have any marketplace + const CGTownInstance *townWithMarket = nullptr; + for(const CGTownInstance *t : LOCPLINT->cb->getTownsInfo()) + { + if(t->hasBuilt(BuildingID::MARKETPLACE)) + { + townWithMarket = t; + break; + } + } + + if(townWithMarket) //if any town has marketplace, open window + GH.pushIntT(townWithMarket); + else //if not - complain + LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithMarket")); + } + else if(isActive()) //no ctrl, advmapint is on the top => switch to town + { + townList.selectNext(); + } + return; + } + default: + { + static const int3 directions[] = { int3(-1, +1, 0), int3(0, +1, 0), int3(+1, +1, 0), + int3(-1, 0, 0), int3(0, 0, 0), int3(+1, 0, 0), + int3(-1, -1, 0), int3(0, -1, 0), int3(+1, -1, 0) }; + + //numpad arrow + if(CGuiHandler::isArrowKey(k)) + k = CGuiHandler::arrowToNum(k); + + k -= SDLK_KP_1; + + if(k < 0 || k > 8) + return; + + if (!CGI->mh->canStartHeroMovement()) + return; + + int3 dir = directions[k]; + + if(!isActive() || LOCPLINT->ctrlPressed())//ctrl makes arrow move screen, not hero + { + Dir = (dir.x<0 ? LEFT : 0) | + (dir.x>0 ? RIGHT : 0) | + (dir.y<0 ? UP : 0) | + (dir.y>0 ? DOWN : 0) ; + break; + } + + if(!h || key.state != SDL_PRESSED) + break; + + if(k == 4) + { + centerOn(h); + return; + } + + CGPath &path = LOCPLINT->paths[h]; + terrain.currentPath = &path; + int3 dst = h->visitablePos() + dir; + if(dst != verifyPos(dst) || !LOCPLINT->cb->getPathsInfo(h)->getPath(path, dst)) + { + terrain.currentPath = nullptr; + return; + } + + if (path.nodes.size() > 2) + updateMoveHero(h); + else + if(!path.nodes[0].turns) + LOCPLINT->moveHero(h, path); + } + + return; + } + if(Dir && key.state == SDL_PRESSED //arrow is pressed + && LOCPLINT->ctrlPressed() + ) + scrollingDir |= Dir; + else + scrollingDir &= ~Dir; +} +void CAdvMapInt::handleRightClick(std::string text, tribool down) +{ + if(down) + { + CRClickPopup::createAndPush(text); + } +} +int3 CAdvMapInt::verifyPos(int3 ver) +{ + if (ver.x<0) + ver.x=0; + if (ver.y<0) + ver.y=0; + if (ver.z<0) + ver.z=0; + if (ver.x>=CGI->mh->sizes.x) + ver.x=CGI->mh->sizes.x-1; + if (ver.y>=CGI->mh->sizes.y) + ver.y=CGI->mh->sizes.y-1; + if (ver.z>=CGI->mh->sizes.z) + ver.z=CGI->mh->sizes.z-1; + return ver; +} + +void CAdvMapInt::select(const CArmedInstance *sel, bool centerView) +{ + assert(sel); + LOCPLINT->setSelection(sel); + selection = sel; + if (LOCPLINT->battleInt == nullptr && LOCPLINT->makingTurn) + { + auto pos = sel->visitablePos(); + auto tile = LOCPLINT->cb->getTile(pos); + if(tile) + CCS->musich->playMusicFromSet("terrain", tile->terType->getJsonKey(), true, false); + } + if(centerView) + centerOn(sel); + + terrain.currentPath = nullptr; + if(sel->ID==Obj::TOWN) + { + auto town = dynamic_cast(sel); + + infoBar.showTownSelection(town); + townList.select(town); + heroList.select(nullptr); + + updateSleepWake(nullptr); + updateMoveHero(nullptr); + updateSpellbook(nullptr); + } + else //hero selected + { + auto hero = dynamic_cast(sel); + + infoBar.showHeroSelection(hero); + heroList.select(hero); + townList.select(nullptr); + + terrain.currentPath = LOCPLINT->getAndVerifyPath(hero); + + updateSleepWake(hero); + updateMoveHero(hero); + updateSpellbook(hero); + } + townList.redraw(); + heroList.redraw(); +} + +void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent ) +{ +#if defined(VCMI_ANDROID) || defined(VCMI_IOS) + if(swipeEnabled) + return; +#endif + // adventure map scrolling with mouse + // currently disabled in world view mode (as it is in OH3), but should work correctly if mode check is removed + // don't scroll if there is no window in focus - these events don't seem to correspond to the actual mouse movement + if(!isCtrlKeyDown() && isActive() && sEvent.windowID != 0 && mode == EAdvMapMode::NORMAL) + { + if(sEvent.x<15) + { + scrollingDir |= LEFT; + } + else + { + scrollingDir &= ~LEFT; + } + if(sEvent.x>screen->w-15) + { + scrollingDir |= RIGHT; + } + else + { + scrollingDir &= ~RIGHT; + } + if(sEvent.y<15) + { + scrollingDir |= UP; + } + else + { + scrollingDir &= ~UP; + } + if(sEvent.y>screen->h-15) + { + scrollingDir |= DOWN; + } + else + { + scrollingDir &= ~DOWN; + } + } +} + +bool CAdvMapInt::isActive() +{ + return active & ~CIntObject::KEYBOARD; +} + +void CAdvMapInt::startHotSeatWait(PlayerColor Player) +{ + state = WAITING; +} + +void CAdvMapInt::setPlayer(PlayerColor Player) +{ + player = Player; + bg->playerColored(player); + + panelMain->setPlayerColor(player); + panelWorldView->setPlayerColor(player); + panelWorldView->recolorIcons(player, player.getNum() * 19); + resdatabar.background->colorize(player); +} + +void CAdvMapInt::startTurn() +{ + state = INGAME; + if(LOCPLINT->cb->getCurrentPlayer() == LOCPLINT->playerID + || settings["session"]["spectate"].Bool()) + { + adjustActiveness(false); + minimap.setAIRadar(false); + } +} + +void CAdvMapInt::endingTurn() +{ + if(settings["session"]["spectate"].Bool()) + return; + + LOCPLINT->makingTurn = false; + LOCPLINT->cb->endTurn(); + CCS->soundh->ambientStopAllChannels(); +} + +const CGObjectInstance* CAdvMapInt::getActiveObject(const int3 &mapPos) +{ + std::vector < const CGObjectInstance * > bobjs = LOCPLINT->cb->getBlockingObjs(mapPos); //blocking objects at tile + + if (bobjs.empty()) + return nullptr; + + return *boost::range::max_element(bobjs, &CMapHandler::compareObjectBlitOrder); +/* + if (bobjs.back()->ID == Obj::HERO) + return bobjs.back(); + else + return bobjs.front();*/ +} + +void CAdvMapInt::tileLClicked(const int3 &mapPos) +{ + if(mode != EAdvMapMode::NORMAL) + return; + if(!LOCPLINT->cb->isVisible(mapPos) || !LOCPLINT->makingTurn) + return; + + const TerrainTile *tile = LOCPLINT->cb->getTile(mapPos); + + const CGObjectInstance *topBlocking = getActiveObject(mapPos); + + int3 selPos = selection->getSightCenter(); + if(spellBeingCasted && isInScreenRange(selPos, mapPos)) + { + const TerrainTile *heroTile = LOCPLINT->cb->getTile(selPos); + + switch(spellBeingCasted->id) + { + case SpellID::SCUTTLE_BOAT: //Scuttle Boat + if(topBlocking && topBlocking->ID == Obj::BOAT) + leaveCastingMode(true, mapPos); + break; + case SpellID::DIMENSION_DOOR: + if(!tile || tile->isClear(heroTile)) + leaveCastingMode(true, mapPos); + break; + } + return; + } + //check if we can select this object + bool canSelect = topBlocking && topBlocking->ID == Obj::HERO && topBlocking->tempOwner == LOCPLINT->playerID; + canSelect |= topBlocking && topBlocking->ID == Obj::TOWN && LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, topBlocking->tempOwner); + + bool isHero = false; + if(selection->ID != Obj::HERO) //hero is not selected (presumably town) + { + assert(!terrain.currentPath); //path can be active only when hero is selected + if(selection == topBlocking) //selected town clicked + LOCPLINT->openTownWindow(static_cast(topBlocking)); + else if(canSelect) + select(static_cast(topBlocking), false); + } + else if(const CGHeroInstance * currentHero = curHero()) //hero is selected + { + isHero = true; + + const CGPathNode *pn = LOCPLINT->cb->getPathsInfo(currentHero)->getPathInfo(mapPos); + if(currentHero == topBlocking) //clicked selected hero + { + LOCPLINT->openHeroWindow(currentHero); + return; + } + else if(canSelect && pn->turns == 255 ) //selectable object at inaccessible tile + { + select(static_cast(topBlocking), false); + return; + } + else //still here? we need to move hero if we clicked end of already selected path or calculate a new path otherwise + { + if(terrain.currentPath && terrain.currentPath->endPos() == mapPos)//we'll be moving + { + if(CGI->mh->canStartHeroMovement()) + LOCPLINT->moveHero(currentHero, *terrain.currentPath); + return; + } + else //remove old path and find a new one if we clicked on accessible tile + { + CGPath &path = LOCPLINT->paths[currentHero]; + CGPath newpath; + bool gotPath = LOCPLINT->cb->getPathsInfo(currentHero)->getPath(newpath, mapPos); //try getting path, erase if failed + if(gotPath && newpath.nodes.size()) + path = newpath; + + if(path.nodes.size()) + terrain.currentPath = &path; + else + LOCPLINT->eraseCurrentPathOf(currentHero); + + updateMoveHero(currentHero); + } + } + } //end of hero is selected "case" + else + { + throw std::runtime_error("Nothing is selected..."); + } + + const auto shipyard = ourInaccessibleShipyard(topBlocking); + if(isHero && shipyard != nullptr) + { + LOCPLINT->showShipyardDialogOrProblemPopup(shipyard); + } +} + +void CAdvMapInt::tileHovered(const int3 &mapPos) +{ + if(mode != EAdvMapMode::NORMAL //disable in world view + || !selection) //may occur just at the start of game (fake move before full intiialization) + return; + if(!LOCPLINT->cb->isVisible(mapPos)) + { + CCS->curh->set(Cursor::Map::POINTER); + statusbar->clear(); + return; + } + auto objRelations = PlayerRelations::ALLIES; + const CGObjectInstance *objAtTile = getActiveObject(mapPos); + if(objAtTile) + { + objRelations = LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, objAtTile->tempOwner); + std::string text = curHero() ? objAtTile->getHoverText(curHero()) : objAtTile->getHoverText(LOCPLINT->playerID); + boost::replace_all(text,"\n"," "); + statusbar->write(text); + } + else + { + std::string hlp; + CGI->mh->getTerrainDescr(mapPos, hlp, false); + statusbar->write(hlp); + } + + if(spellBeingCasted) + { + switch(spellBeingCasted->id) + { + case SpellID::SCUTTLE_BOAT: + if(objAtTile && objAtTile->ID == Obj::BOAT) + CCS->curh->set(Cursor::Map::SCUTTLE_BOAT); + else + CCS->curh->set(Cursor::Map::POINTER); + return; + case SpellID::DIMENSION_DOOR: + { + const TerrainTile * t = LOCPLINT->cb->getTile(mapPos, false); + int3 hpos = selection->getSightCenter(); + if((!t || t->isClear(LOCPLINT->cb->getTile(hpos))) && isInScreenRange(hpos, mapPos)) + CCS->curh->set(Cursor::Map::TELEPORT); + else + CCS->curh->set(Cursor::Map::POINTER); + return; + } + } + } + + if(selection->ID == Obj::TOWN) + { + if(objAtTile) + { + if(objAtTile->ID == Obj::TOWN && objRelations != PlayerRelations::ENEMIES) + CCS->curh->set(Cursor::Map::TOWN); + else if(objAtTile->ID == Obj::HERO && objRelations == PlayerRelations::SAME_PLAYER) + CCS->curh->set(Cursor::Map::HERO); + else + CCS->curh->set(Cursor::Map::POINTER); + } + else + CCS->curh->set(Cursor::Map::POINTER); + } + else if(const CGHeroInstance * hero = curHero()) + { + std::array cursorMove = { Cursor::Map::T1_MOVE, Cursor::Map::T2_MOVE, Cursor::Map::T3_MOVE, Cursor::Map::T4_MOVE, }; + std::array cursorAttack = { Cursor::Map::T1_ATTACK, Cursor::Map::T2_ATTACK, Cursor::Map::T3_ATTACK, Cursor::Map::T4_ATTACK, }; + std::array cursorSail = { Cursor::Map::T1_SAIL, Cursor::Map::T2_SAIL, Cursor::Map::T3_SAIL, Cursor::Map::T4_SAIL, }; + std::array cursorDisembark = { Cursor::Map::T1_DISEMBARK, Cursor::Map::T2_DISEMBARK, Cursor::Map::T3_DISEMBARK, Cursor::Map::T4_DISEMBARK, }; + std::array cursorExchange = { Cursor::Map::T1_EXCHANGE, Cursor::Map::T2_EXCHANGE, Cursor::Map::T3_EXCHANGE, Cursor::Map::T4_EXCHANGE, }; + std::array cursorVisit = { Cursor::Map::T1_VISIT, Cursor::Map::T2_VISIT, Cursor::Map::T3_VISIT, Cursor::Map::T4_VISIT, }; + std::array cursorSailVisit = { Cursor::Map::T1_SAIL_VISIT, Cursor::Map::T2_SAIL_VISIT, Cursor::Map::T3_SAIL_VISIT, Cursor::Map::T4_SAIL_VISIT, }; + + const CGPathNode * pathNode = LOCPLINT->cb->getPathsInfo(hero)->getPathInfo(mapPos); + assert(pathNode); + + if(LOCPLINT->altPressed() && pathNode->reachable()) //overwrite status bar text with movement info + { + ShowMoveDetailsInStatusbar(*hero, *pathNode); + } + + int turns = pathNode->turns; + vstd::amin(turns, 3); + switch(pathNode->action) + { + case CGPathNode::NORMAL: + case CGPathNode::TELEPORT_NORMAL: + if(pathNode->layer == EPathfindingLayer::LAND) + CCS->curh->set(cursorMove[turns]); + else + CCS->curh->set(cursorSailVisit[turns]); + break; + + case CGPathNode::VISIT: + case CGPathNode::BLOCKING_VISIT: + case CGPathNode::TELEPORT_BLOCKING_VISIT: + if(objAtTile && objAtTile->ID == Obj::HERO) + { + if(selection == objAtTile) + CCS->curh->set(Cursor::Map::HERO); + else + CCS->curh->set(cursorExchange[turns]); + } + else if(pathNode->layer == EPathfindingLayer::LAND) + CCS->curh->set(cursorVisit[turns]); + else + CCS->curh->set(cursorSailVisit[turns]); + break; + + case CGPathNode::BATTLE: + case CGPathNode::TELEPORT_BATTLE: + CCS->curh->set(cursorAttack[turns]); + break; + + case CGPathNode::EMBARK: + CCS->curh->set(cursorSail[turns]); + break; + + case CGPathNode::DISEMBARK: + CCS->curh->set(cursorDisembark[turns]); + break; + + default: + if(objAtTile && objRelations != PlayerRelations::ENEMIES) + { + if(objAtTile->ID == Obj::TOWN) + CCS->curh->set(Cursor::Map::TOWN); + else if(objAtTile->ID == Obj::HERO && objRelations == PlayerRelations::SAME_PLAYER) + CCS->curh->set(Cursor::Map::HERO); + else + CCS->curh->set(Cursor::Map::POINTER); + } + else + CCS->curh->set(Cursor::Map::POINTER); + break; + } + } + + if(ourInaccessibleShipyard(objAtTile)) + { + CCS->curh->set(Cursor::Map::T1_SAIL); + } +} + +void CAdvMapInt::ShowMoveDetailsInStatusbar(const CGHeroInstance & hero, const CGPathNode & pathNode) +{ + const int maxMovementPointsAtStartOfLastTurn = pathNode.turns > 0 ? hero.maxMovePoints(pathNode.layer == EPathfindingLayer::LAND) : hero.movement; + const int movementPointsLastTurnCost = maxMovementPointsAtStartOfLastTurn - pathNode.moveRemains; + const int remainingPointsAfterMove = pathNode.turns == 0 ? pathNode.moveRemains : 0; + + std::string result = VLC->generaltexth->translate("vcmi.adventureMap", pathNode.turns > 0 ? "moveCostDetails" : "moveCostDetailsNoTurns"); + + boost::replace_first(result, "%TURNS", std::to_string(pathNode.turns)); + boost::replace_first(result, "%POINTS", std::to_string(movementPointsLastTurnCost)); + boost::replace_first(result, "%REMAINING", std::to_string(remainingPointsAfterMove)); + + statusbar->write(result); +} + +void CAdvMapInt::tileRClicked(const int3 &mapPos) +{ + if(mode != EAdvMapMode::NORMAL) + return; + if(spellBeingCasted) + { + leaveCastingMode(); + return; + } + if(!LOCPLINT->cb->isVisible(mapPos)) + { + CRClickPopup::createAndPush(VLC->generaltexth->allTexts[61]); //Uncharted Territory + return; + } + + const CGObjectInstance * obj = getActiveObject(mapPos); + if(!obj) + { + // Bare or undiscovered terrain + const TerrainTile * tile = LOCPLINT->cb->getTile(mapPos); + if (tile) + { + std::string hlp; + CGI->mh->getTerrainDescr(mapPos, hlp, true); + CRClickPopup::createAndPush(hlp); + } + return; + } + + CRClickPopup::createAndPush(obj, GH.getCursorPosition(), ETextAlignment::CENTER); +} + +void CAdvMapInt::enterCastingMode(const CSpell * sp) +{ + assert(sp->id == SpellID::SCUTTLE_BOAT || sp->id == SpellID::DIMENSION_DOOR); + spellBeingCasted = sp; + + deactivate(); + terrain.activate(); + GH.fakeMouseMove(); +} + +void CAdvMapInt::leaveCastingMode(bool cast, int3 dest) +{ + assert(spellBeingCasted); + SpellID id = spellBeingCasted->id; + spellBeingCasted = nullptr; + terrain.deactivate(); + activate(); + + if(cast) + LOCPLINT->cb->castSpell(curHero(), id, dest); + else + LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[731]); //Spell cancelled +} + +const CGHeroInstance * CAdvMapInt::curHero() const +{ + if(selection && selection->ID == Obj::HERO) + return static_cast(selection); + else + return nullptr; +} + +const CGTownInstance * CAdvMapInt::curTown() const +{ + if(selection && selection->ID == Obj::TOWN) + return static_cast(selection); + else + return nullptr; +} + +const IShipyard * CAdvMapInt::ourInaccessibleShipyard(const CGObjectInstance *obj) const +{ + const IShipyard *ret = IShipyard::castFrom(obj); + + if(!ret || + obj->tempOwner != player || + (CCS->curh->get() != Cursor::Map::T1_SAIL && CCS->curh->get() != Cursor::Map::POINTER)) + return nullptr; + + return ret; +} + +void CAdvMapInt::aiTurnStarted() +{ + if(settings["session"]["spectate"].Bool()) + return; + + adjustActiveness(true); + CCS->musich->playMusicFromSet("enemy-turn", true, false); + adventureInt->minimap.setAIRadar(true); + adventureInt->infoBar.startEnemyTurn(LOCPLINT->cb->getCurrentPlayer()); + adventureInt->infoBar.showAll(screen);//force refresh on inactive object +} + +void CAdvMapInt::adjustActiveness(bool aiTurnStart) +{ + bool wasActive = isActive(); + + if(wasActive) + deactivate(); + adventureInt->duringAITurn = aiTurnStart; + if(wasActive) + activate(); +} + +void CAdvMapInt::quickCombatLock() +{ + if(!duringAITurn) + deactivate(); +} + +void CAdvMapInt::quickCombatUnlock() +{ + if(!duringAITurn) + activate(); +} + +void CAdvMapInt::changeMode(EAdvMapMode newMode, float newScale) +{ + if (mode != newMode) + { + mode = newMode; + + switch (mode) + { + case EAdvMapMode::NORMAL: + panelMain->activate(); + panelWorldView->deactivate(); + activeMapPanel = panelMain; + + townList.activate(); + heroList.activate(); + infoBar.activate(); + + worldViewOptions.clear(); + + break; + case EAdvMapMode::WORLD_VIEW: + panelMain->deactivate(); + panelWorldView->activate(); + + activeMapPanel = panelWorldView; + + townList.deactivate(); + heroList.deactivate(); + infoBar.showSelection(); // to prevent new day animation interfering world view mode + infoBar.deactivate(); + + break; + } + worldViewScale = newScale; + redraw(); + } + else if (worldViewScale != newScale) // still in world view mode, but the scale changed + { + worldViewScale = newScale; + redraw(); + } +} + +CAdventureOptions::CAdventureOptions() + : CWindowObject(PLAYER_COLORED, "ADVOPTS") +{ + OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); + + viewWorld = std::make_shared(Point(24, 23), "ADVVIEW.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_v); + viewWorld->addCallback(std::bind(&CPlayerInterface::viewWorldMap, LOCPLINT)); + + exit = std::make_shared(Point(204, 313), "IOK6432.DEF", CButton::tooltip(), std::bind(&CAdventureOptions::close, this), SDLK_RETURN); + exit->assignedKeys.insert(SDLK_ESCAPE); + + scenInfo = std::make_shared(Point(24, 198), "ADVINFO.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_i); + scenInfo->addCallback(CAdventureOptions::showScenarioInfo); + + puzzle = std::make_shared(Point(24, 81), "ADVPUZ.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_p); + puzzle->addCallback(std::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT)); + + dig = std::make_shared(Point(24, 139), "ADVDIG.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_d); + if(const CGHeroInstance *h = adventureInt->curHero()) + dig->addCallback(std::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h)); + else + dig->block(true); +} + +void CAdventureOptions::showScenarioInfo() +{ + if(LOCPLINT->cb->getStartInfo()->campState) + { + GH.pushIntT(); + } + else + { + GH.pushIntT(); + } +} + +CAdvMapInt::WorldViewOptions::WorldViewOptions() +{ + clear(); +} + +void CAdvMapInt::WorldViewOptions::clear() +{ + showAllTerrain = false; + + iconPositions.clear(); +} + +void CAdvMapInt::WorldViewOptions::adjustDrawingInfo(MapDrawingInfo& info) +{ + info.showAllTerrain = showAllTerrain; + + info.additionalIcons = &iconPositions; +} diff --git a/client/adventureMap/CAdvmapInterface.h b/client/adventureMap/CAdvmapInterface.h new file mode 100644 index 000000000..6b1ae0ddc --- /dev/null +++ b/client/adventureMap/CAdvmapInterface.h @@ -0,0 +1,276 @@ +/* + * CAdvmapInterface.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include "../widgets/AdventureMapClasses.h" +#include "CWindowObject.h" + +#include "../widgets/TextControls.h" +#include "../widgets/Buttons.h" + +#include "../../lib/spells/ViewSpellInt.h" + +VCMI_LIB_NAMESPACE_BEGIN + +struct CGPath; +struct CGPathNode; +class CGHeroInstance; +class CGTownInstance; +class CSpell; +class IShipyard; + +VCMI_LIB_NAMESPACE_END + +class CCallback; +class CAdvMapInt; +class CHeroWindow; +enum class EMapAnimRedrawStatus; +class CFadeAnimation; + +struct MapDrawingInfo; + +/*****************************/ + +enum class EAdvMapMode +{ + NORMAL, + WORLD_VIEW +}; + +/// Adventure options dialog where you can view the world, dig, play the replay of the last turn,... +class CAdventureOptions : public CWindowObject +{ +public: + std::shared_ptr exit; + std::shared_ptr viewWorld; + std::shared_ptr puzzle; + std::shared_ptr dig; + std::shared_ptr scenInfo; + /*std::shared_ptr replay*/ + + CAdventureOptions(); + static void showScenarioInfo(); +}; + +/// Holds information about which tiles of the terrain are shown/not shown at the screen +class CTerrainRect : public CIntObject +{ + SDL_Surface * fadeSurface; + EMapAnimRedrawStatus lastRedrawStatus; + std::shared_ptr fadeAnim; + + int3 swipeInitialMapPos; + int3 swipeInitialRealPos; + bool isSwiping; + static constexpr float SwipeTouchSlop = 16.0f; + + void handleHover(const SDL_MouseMotionEvent & sEvent); + void handleSwipeMove(const SDL_MouseMotionEvent & sEvent); + /// handles start/finish of swipe (press/release of corresponding button); returns true if state change was handled + bool handleSwipeStateChange(bool btnPressed); +public: + int tilesw, tilesh; //width and height of terrain to blit in tiles + int3 curHoveredTile; + int moveX, moveY; //shift between actual position of screen and the one we wil blit; ranges from -31 to 31 (in pixels) + CGPath * currentPath; + + CTerrainRect(); + virtual ~CTerrainRect(); + void deactivate() override; + void clickLeft(tribool down, bool previousState) override; + void clickRight(tribool down, bool previousState) override; + void clickMiddle(tribool down, bool previousState) override; + void hover(bool on) override; + void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; + void show(SDL_Surface * to) override; + void showAll(SDL_Surface * to) override; + void showAnim(SDL_Surface * to); + void showPath(const Rect &extRect, SDL_Surface * to); + int3 whichTileIsIt(const int x, const int y); //x,y are cursor position + int3 whichTileIsIt(); //uses current cursor pos + /// @returns number of visible tiles on screen respecting current map scaling + int3 tileCountOnScreen(); + /// animates view by caching current surface and crossfading it with normal screen + void fadeFromCurrentView(); + bool needsAnimUpdate(); +}; + +/// Resources bar which shows information about how many gold, crystals,... you have +/// Current date is displayed too +class CResDataBar : public CIntObject +{ +public: + std::shared_ptr background; + + std::vector > txtpos; + std::string datetext; + + void clickRight(tribool down, bool previousState) override; + CResDataBar(); + CResDataBar(const std::string &defname, int x, int y, int offx, int offy, int resdist, int datedist); + ~CResDataBar(); + + void draw(SDL_Surface * to); + void show(SDL_Surface * to) override; + void showAll(SDL_Surface * to) override; +}; + +/// That's a huge class which handles general adventure map actions and +/// shows the right menu(questlog, spellbook, end turn,..) from where you +/// can get to the towns and heroes. +class CAdvMapInt : public CIntObject +{ + //Return object that must be active at this tile (=clickable) + const CGObjectInstance *getActiveObject(const int3 &tile); + +public: + CAdvMapInt(); + + int3 position; //top left corner of visible map part + PlayerColor player; + + bool duringAITurn; + + enum{LEFT=1, RIGHT=2, UP=4, DOWN=8}; + ui8 scrollingDir; //uses enum: LEFT RIGHT, UP, DOWN + bool scrollingState; + bool swipeEnabled; + bool swipeMovementRequested; + int3 swipeTargetPosition; + + enum{NA, INGAME, WAITING} state; + + bool updateScreen; + ui8 anim, animValHitCount; //animation frame + ui8 heroAnim, heroAnimValHitCount; //animation frame + + EAdvMapMode mode; + float worldViewScale; + + struct WorldViewOptions + { + bool showAllTerrain; //for expert viewEarth + + std::vector iconPositions; + + WorldViewOptions(); + + void clear(); + + void adjustDrawingInfo(MapDrawingInfo & info); + }; + + WorldViewOptions worldViewOptions; + + std::shared_ptr bg; + std::shared_ptr bgWorldView; + std::vector> gems; + CMinimap minimap; + std::shared_ptr statusbar; + + std::shared_ptr kingOverview; + std::shared_ptr underground; + std::shared_ptr questlog; + std::shared_ptr sleepWake; + std::shared_ptr moveHero; + std::shared_ptr spellbook; + std::shared_ptr advOptions; + std::shared_ptr sysOptions; + std::shared_ptr nextHero; + std::shared_ptr endTurn; + + std::shared_ptr worldViewUnderground; + + CTerrainRect terrain; //visible terrain + CResDataBar resdatabar; + CHeroList heroList; + CTownList townList; + CInfoBar infoBar; + + std::shared_ptr panelMain; // panel that holds all right-side buttons in normal view + std::shared_ptr panelWorldView; // panel that holds all buttons and other ui in world view + std::shared_ptr activeMapPanel; // currently active panel (either main or world view, depending on current mode) + + std::shared_ptr worldViewIcons;// images for world view overlay + + const CSpell *spellBeingCasted; //nullptr if none + + const CArmedInstance *selection; //currently selected town/hero + + //functions bound to buttons + void fshowOverview(); + void fworldViewBack(); + void fworldViewScale1x(); + void fworldViewScale2x(); + void fworldViewScale4x(); + void fswitchLevel(); + void fshowQuestlog(); + void fsleepWake(); + void fmoveHero(); + void fshowSpellbok(); + void fadventureOPtions(); + void fsystemOptions(); + void fnextHero(); + void fendTurn(); + + void activate() override; + void deactivate() override; + + void show(SDL_Surface * to) override; //redraws terrain + void showAll(SDL_Surface * to) override; //shows and activates adv. map interface + + void select(const CArmedInstance *sel, bool centerView = true); + void selectionChanged(); + void centerOn(int3 on, bool fade = false); + void centerOn(const CGObjectInstance *obj, bool fade = false); + int3 verifyPos(int3 ver); + void handleRightClick(std::string text, tribool down); + void keyPressed(const SDL_KeyboardEvent & key) override; + void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; + bool isActive(); + + bool isHeroSleeping(const CGHeroInstance *hero); + void setHeroSleeping(const CGHeroInstance *hero, bool sleep); + int getNextHeroIndex(int startIndex); //for Next Hero button - cycles awake heroes with movement only + + void setPlayer(PlayerColor Player); + void startHotSeatWait(PlayerColor Player); + void startTurn(); + void endingTurn(); + void aiTurnStarted(); + + void adjustActiveness(bool aiTurnStart); //should be called every time at AI/human turn transition; blocks GUI during AI turn + void quickCombatLock(); //should be called when quick battle started + void quickCombatUnlock(); + void tileLClicked(const int3 &mapPos); + void tileHovered(const int3 &mapPos); + void tileRClicked(const int3 &mapPos); + void enterCastingMode(const CSpell * sp); + void leaveCastingMode(bool cast = false, int3 dest = int3(-1, -1, -1)); + const CGHeroInstance * curHero() const; + const CGTownInstance * curTown() const; + const IShipyard * ourInaccessibleShipyard(const CGObjectInstance *obj) const; //checks if obj is our ashipyard and cursor is 0,0 -> returns shipyard or nullptr else + //button updates + void updateSleepWake(const CGHeroInstance *h); + void updateMoveHero(const CGHeroInstance *h, tribool hasPath = boost::logic::indeterminate); + void updateSpellbook(const CGHeroInstance *h); + void updateNextHero(const CGHeroInstance *h); + + /// changes current adventure map mode; used to switch between default view and world view; scale is ignored if EAdvMapMode == NORMAL + void changeMode(EAdvMapMode newMode, float newScale = 0.36f); + + void handleMapScrollingUpdate(); + void handleSwipeUpdate(); + +private: + void ShowMoveDetailsInStatusbar(const CGHeroInstance & hero, const CGPathNode & pathNode); +}; + +extern std::shared_ptr adventureInt; From bfea28b2b59a88beb84e3408082eb4699d9d546c Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:24:43 +0200 Subject: [PATCH 57/79] Remove duplicated code from changed files --- client/adventureMap/CAdventureOptions.cpp | 1894 --------------------- client/adventureMap/CAdventureOptions.h | 222 --- client/adventureMap/CAdvmapInterface.cpp | 498 +----- client/adventureMap/CAdvmapInterface.h | 78 - client/adventureMap/CResDataBar.cpp | 1849 -------------------- client/adventureMap/CResDataBar.h | 218 --- client/adventureMap/CTerrainRect.cpp | 1550 ----------------- client/adventureMap/CTerrainRect.h | 195 --- 8 files changed, 1 insertion(+), 6503 deletions(-) diff --git a/client/adventureMap/CAdventureOptions.cpp b/client/adventureMap/CAdventureOptions.cpp index d0529f744..50c466066 100644 --- a/client/adventureMap/CAdventureOptions.cpp +++ b/client/adventureMap/CAdventureOptions.cpp @@ -89,1882 +89,6 @@ static void setScrollingCursor(ui8 direction) CCS->curh->set(Cursor::Map::SCROLL_SOUTH); } -CTerrainRect::CTerrainRect() - : fadeSurface(nullptr), - lastRedrawStatus(EMapAnimRedrawStatus::OK), - fadeAnim(std::make_shared()), - curHoveredTile(-1,-1,-1), - currentPath(nullptr) -{ - tilesw=(ADVOPT.advmapW+31)/32; - tilesh=(ADVOPT.advmapH+31)/32; - pos.x=ADVOPT.advmapX; - pos.y=ADVOPT.advmapY; - pos.w=ADVOPT.advmapW; - pos.h=ADVOPT.advmapH; - moveX = moveY = 0; - addUsedEvents(LCLICK | RCLICK | MCLICK | HOVER | MOVE); -} - -CTerrainRect::~CTerrainRect() -{ - if(fadeSurface) - SDL_FreeSurface(fadeSurface); -} - -void CTerrainRect::deactivate() -{ - CIntObject::deactivate(); - curHoveredTile = int3(-1,-1,-1); //we lost info about hovered tile when disabling -} - -void CTerrainRect::clickLeft(tribool down, bool previousState) -{ - if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) - return; - if(indeterminate(down)) - return; - -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - if(adventureInt->swipeEnabled) - { - if(handleSwipeStateChange((bool)down == true)) - { - return; // if swipe is enabled, we don't process "down" events and wait for "up" (to make sure this wasn't a swiping gesture) - } - } - else - { -#endif - if(down == false) - return; -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - } -#endif - int3 mp = whichTileIsIt(); - if(mp.x < 0 || mp.y < 0 || mp.x >= LOCPLINT->cb->getMapSize().x || mp.y >= LOCPLINT->cb->getMapSize().y) - return; - - adventureInt->tileLClicked(mp); -} - -void CTerrainRect::clickRight(tribool down, bool previousState) -{ -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - if(adventureInt->swipeEnabled && isSwiping) - return; -#endif - if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) - return; - int3 mp = whichTileIsIt(); - - if(CGI->mh->map->isInTheMap(mp) && down) - adventureInt->tileRClicked(mp); -} - -void CTerrainRect::clickMiddle(tribool down, bool previousState) -{ - handleSwipeStateChange((bool)down == true); -} - -void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent) -{ - handleHover(sEvent); - - if(!adventureInt->swipeEnabled) - return; - - handleSwipeMove(sEvent); -} - -void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent) -{ -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - if(sEvent.state == 0 || GH.multifinger) // any "button" is enough on mobile -#else - if((sEvent.state & SDL_BUTTON_MMASK) == 0) // swipe only works with middle mouse on other platforms -#endif - { - return; - } - - if(!isSwiping) - { - // try to distinguish if this touch was meant to be a swipe or just fat-fingering press - if(abs(sEvent.x - swipeInitialRealPos.x) > SwipeTouchSlop || - abs(sEvent.y - swipeInitialRealPos.y) > SwipeTouchSlop) - { - isSwiping = true; - } - } - - if(isSwiping) - { - adventureInt->swipeTargetPosition.x = - swipeInitialMapPos.x + static_cast(swipeInitialRealPos.x - sEvent.x) / 32; - adventureInt->swipeTargetPosition.y = - swipeInitialMapPos.y + static_cast(swipeInitialRealPos.y - sEvent.y) / 32; - adventureInt->swipeMovementRequested = true; - } -} - -bool CTerrainRect::handleSwipeStateChange(bool btnPressed) -{ - if(btnPressed) - { - swipeInitialRealPos = int3(GH.getCursorPosition().x, GH.getCursorPosition().y, 0); - swipeInitialMapPos = int3(adventureInt->position); - return true; - } - else if(isSwiping) // only accept this touch if it wasn't a swipe - { - isSwiping = false; - return true; - } - return false; -} - -void CTerrainRect::handleHover(const SDL_MouseMotionEvent &sEvent) -{ - int3 tHovered = whichTileIsIt(sEvent.x, sEvent.y); - int3 pom = adventureInt->verifyPos(tHovered); - - if(tHovered != pom) //tile outside the map - { - CCS->curh->set(Cursor::Map::POINTER); - return; - } - - if (pom != curHoveredTile) - { - curHoveredTile = pom; - adventureInt->tileHovered(pom); - } -} - -void CTerrainRect::hover(bool on) -{ - if (!on) - { - adventureInt->statusbar->clear(); - CCS->curh->set(Cursor::Map::POINTER); - } - //Hoverable::hover(on); -} -void CTerrainRect::showPath(const Rect & extRect, SDL_Surface * to) -{ - const static int pns[9][9] = { - {16, 17, 18, 7, -1, 19, 6, 5, -1}, - { 8, 9, 18, 7, -1, 19, 6, -1, 20}, - { 8, 1, 10, 7, -1, 19, -1, 21, 20}, - {24, 17, 18, 15, -1, -1, 6, 5, 4}, - {-1, -1, -1, -1, -1, -1, -1, -1, -1}, - { 8, 1, 2, -1, -1, 11, 22, 21, 20}, - {24, 17, -1, 23, -1, 3, 14, 5, 4}, - {24, -1, 2, 23, -1, 3, 22, 13, 4}, - {-1, 1, 2, 23, -1, 3, 22, 21, 12} - }; //table of magic values TODO meaning, change variable name - - for (int i = 0; i < -1 + (int)currentPath->nodes.size(); ++i) - { - const int3 &curPos = currentPath->nodes[i].coord, &nextPos = currentPath->nodes[i+1].coord; - if(curPos.z != adventureInt->position.z) - continue; - - int pn=-1;//number of picture - if (i==0) //last tile - { - int x = 32*(curPos.x-adventureInt->position.x)+CGI->mh->offsetX + pos.x, - y = 32*(curPos.y-adventureInt->position.y)+CGI->mh->offsetY + pos.y; - if (x<0 || y<0 || x>pos.w || y>pos.h) - continue; - pn=0; - } - else - { - const int3 &prevPos = currentPath->nodes[i-1].coord; - std::vector & cv = currentPath->nodes; - - /* Vector directions - * 0 1 2 - * \ | / - * 3 - 4 - 5 - * / | \ - * 6 7 8 - *For example: - * | - * |__\ - * / - * is id1=7, id2=5 (pns[7][5]) - */ - bool pathContinuous = curPos.areNeighbours(nextPos) && curPos.areNeighbours(prevPos); - if(pathContinuous && cv[i].action != CGPathNode::EMBARK && cv[i].action != CGPathNode::DISEMBARK) - { - int id1=(curPos.x-nextPos.x+1)+3*(curPos.y-nextPos.y+1); //Direction of entering vector - int id2=(cv[i-1].coord.x-curPos.x+1)+3*(cv[i-1].coord.y-curPos.y+1); //Direction of exiting vector - pn=pns[id1][id2]; - } - else //path discontinuity or sea/land transition (eg. when moving through Subterranean Gate or Boat) - { - pn = 0; - } - } - if (currentPath->nodes[i].turns) - pn+=25; - if (pn>=0) - { - const auto arrow = graphics->heroMoveArrows->getImage(pn); - - int x = 32*(curPos.x-adventureInt->position.x)+CGI->mh->offsetX + pos.x, - y = 32*(curPos.y-adventureInt->position.y)+CGI->mh->offsetY + pos.y; - if (x< -32 || y< -32 || x>pos.w || y>pos.h) - continue; - int hvx = (x + arrow->width()) - (pos.x + pos.w), - hvy = (y + arrow->height()) - (pos.y + pos.h); - - Rect prevClip; - CSDL_Ext::getClipRect(to, prevClip); - CSDL_Ext::setClipRect(to, extRect); //preventing blitting outside of that rect - - if(ADVOPT.smoothMove) //version for smooth hero move, with pos shifts - { - if (hvx<0 && hvy<0) - { - arrow->draw(to, x + moveX, y + moveY); - } - else if(hvx<0) - { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width(), 0, 0); - arrow->draw(to, x + moveX, y + moveY, &srcRect); - } - else if (hvy<0) - { - Rect srcRect = genRect(arrow->height(), arrow->width() - hvx, 0, 0); - arrow->draw(to, x + moveX, y + moveY, &srcRect); - } - else - { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); - arrow->draw(to, x + moveX, y + moveY, &srcRect); - } - } - else //standard version - { - if (hvx<0 && hvy<0) - { - arrow->draw(to, x, y); - } - else if(hvx<0) - { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width(), 0, 0); - arrow->draw(to, x, y, &srcRect); - } - else if (hvy<0) - { - Rect srcRect = genRect(arrow->height(), arrow->width() - hvx, 0, 0); - arrow->draw(to, x, y, &srcRect); - } - else - { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); - arrow->draw(to, x, y, &srcRect); - } - } - CSDL_Ext::setClipRect(to, prevClip); - - } - } //for (int i=0;inodes.size()-1;i++) -} - -void CTerrainRect::show(SDL_Surface * to) -{ - if (adventureInt->mode == EAdvMapMode::NORMAL) - { - MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), pos); - info.otherheroAnim = true; - info.anim = adventureInt->anim; - info.heroAnim = adventureInt->heroAnim; - if (ADVOPT.smoothMove) - info.movement = int3(moveX, moveY, 0); - - lastRedrawStatus = CGI->mh->drawTerrainRectNew(to, &info); - if (fadeAnim->isFading()) - { - Rect r(pos); - fadeAnim->update(); - fadeAnim->draw(to, r.topLeft()); - } - - if (currentPath/* && adventureInt->position.z==currentPath->startPos().z*/) //drawing path - { - showPath(pos, to); - } - } -} - -void CTerrainRect::showAll(SDL_Surface * to) -{ - // world view map is static and doesn't need redraw every frame - if (adventureInt->mode == EAdvMapMode::WORLD_VIEW) - { - MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), pos, adventureInt->worldViewIcons); - info.scaled = true; - info.scale = adventureInt->worldViewScale; - adventureInt->worldViewOptions.adjustDrawingInfo(info); - CGI->mh->drawTerrainRectNew(to, &info); - } -} - -void CTerrainRect::showAnim(SDL_Surface * to) -{ - if (fadeAnim->isFading()) - show(to); - else if (lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED) - show(to); // currently the same; maybe we should pass some flag to map handler so it redraws ONLY tiles that need redraw instead of full -} - -int3 CTerrainRect::whichTileIsIt(const int x, const int y) -{ - int3 ret; - ret.x = adventureInt->position.x + ((x-CGI->mh->offsetX-pos.x)/32); - ret.y = adventureInt->position.y + ((y-CGI->mh->offsetY-pos.y)/32); - ret.z = adventureInt->position.z; - return ret; -} - -int3 CTerrainRect::whichTileIsIt() -{ - return whichTileIsIt(GH.getCursorPosition().x, GH.getCursorPosition().y); -} - -int3 CTerrainRect::tileCountOnScreen() -{ - switch (adventureInt->mode) - { - default: - logGlobal->error("Unknown map mode %d", (int)adventureInt->mode); - return int3(); - case EAdvMapMode::NORMAL: - return int3(tilesw, tilesh, 1); - case EAdvMapMode::WORLD_VIEW: - return int3((si32)(tilesw / adventureInt->worldViewScale), (si32)(tilesh / adventureInt->worldViewScale), 1); - } -} - -void CTerrainRect::fadeFromCurrentView() -{ - if (!ADVOPT.screenFading) - return; - if (adventureInt->mode == EAdvMapMode::WORLD_VIEW) - return; - - if (!fadeSurface) - fadeSurface = CSDL_Ext::newSurface(pos.w, pos.h); - CSDL_Ext::blitSurface(screen, fadeSurface, Point(0,0)); - fadeAnim->init(CFadeAnimation::EMode::OUT, fadeSurface); -} - -bool CTerrainRect::needsAnimUpdate() -{ - return fadeAnim->isFading() || lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED; -} - -void CResDataBar::clickRight(tribool down, bool previousState) -{ -} - -CResDataBar::CResDataBar(const std::string & defname, int x, int y, int offx, int offy, int resdist, int datedist) -{ - pos.x += x; - pos.y += y; - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared(defname, 0, 0); - background->colorize(LOCPLINT->playerID); - - pos.w = background->pos.w; - pos.h = background->pos.h; - - txtpos.resize(8); - for (int i = 0; i < 8 ; i++) - { - txtpos[i].first = pos.x + offx + resdist*i; - txtpos[i].second = pos.y + offy; - } - txtpos[7].first = txtpos[6].first + datedist; - datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] - + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s"; - addUsedEvents(RCLICK); -} - -CResDataBar::CResDataBar() -{ - pos.x += ADVOPT.resdatabarX; - pos.y += ADVOPT.resdatabarY; - - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared(ADVOPT.resdatabarG, 0, 0); - background->colorize(LOCPLINT->playerID); - - pos.w = background->pos.w; - pos.h = background->pos.h; - - txtpos.resize(8); - for (int i = 0; i < 8 ; i++) - { - txtpos[i].first = pos.x + ADVOPT.resOffsetX + ADVOPT.resDist*i; - txtpos[i].second = pos.y + ADVOPT.resOffsetY; - } - txtpos[7].first = txtpos[6].first + ADVOPT.resDateDist; - datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] - + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s"; -} - -CResDataBar::~CResDataBar() = default; - -void CResDataBar::draw(SDL_Surface * to) -{ - //TODO: all this should be labels, but they require proper text update on change - for (auto i=Res::WOOD; i<=Res::GOLD; vstd::advance(i, 1)) - { - std::string text = boost::lexical_cast(LOCPLINT->cb->getResourceAmount(i)); - - graphics->fonts[FONT_SMALL]->renderTextLeft(to, text, Colors::WHITE, Point(txtpos[i].first,txtpos[i].second)); - } - std::vector temp; - - temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::MONTH))); - temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::WEEK))); - temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK))); - - graphics->fonts[FONT_SMALL]->renderTextLeft(to, processStr(datetext,temp), Colors::WHITE, Point(txtpos[7].first,txtpos[7].second)); -} - -void CResDataBar::show(SDL_Surface * to) -{ - -} - -void CResDataBar::showAll(SDL_Surface * to) -{ - CIntObject::showAll(to); - draw(to); -} - -CAdvMapInt::CAdvMapInt(): - mode(EAdvMapMode::NORMAL), - worldViewScale(0.0f), //actual init later in changeMode - minimap(Rect(ADVOPT.minimapX, ADVOPT.minimapY, ADVOPT.minimapW, ADVOPT.minimapH)), - statusbar(CGStatusBar::create(ADVOPT.statusbarX,ADVOPT.statusbarY,ADVOPT.statusbarG)), - heroList(ADVOPT.hlistSize, Point(ADVOPT.hlistX, ADVOPT.hlistY), ADVOPT.hlistAU, ADVOPT.hlistAD), - townList(ADVOPT.tlistSize, Point(ADVOPT.tlistX, ADVOPT.tlistY), ADVOPT.tlistAU, ADVOPT.tlistAD), - infoBar(Rect(ADVOPT.infoboxX, ADVOPT.infoboxY, 192, 192)), state(NA), - spellBeingCasted(nullptr), position(int3(0, 0, 0)), selection(nullptr), - updateScreen(false), anim(0), animValHitCount(0), heroAnim(0), heroAnimValHitCount(0), - activeMapPanel(nullptr), duringAITurn(false), scrollingDir(0), scrollingState(false), - swipeEnabled(settings["general"]["swipe"].Bool()), swipeMovementRequested(false), - swipeTargetPosition(int3(-1, -1, -1)) -{ - pos.x = pos.y = 0; - pos.w = screen->w; - pos.h = screen->h; - strongInterest = true; // handle all mouse move events to prevent dead mouse move space in fullscreen mode - townList.onSelect = std::bind(&CAdvMapInt::selectionChanged,this); - bg = IImage::createFromFile(ADVOPT.mainGraphic); - if(!ADVOPT.worldViewGraphic.empty()) - { - bgWorldView = IImage::createFromFile(ADVOPT.worldViewGraphic); - } - else - { - bgWorldView = nullptr; - logGlobal->warn("ADVOPT.worldViewGraphic is empty => bitmap not loaded"); - } - if (!bgWorldView) - { - logGlobal->warn("bgWorldView not defined in resolution config; fallback to VWorld.bmp"); - bgWorldView = IImage::createFromFile("VWorld.bmp"); - } - - worldViewIcons = std::make_shared("VwSymbol");//todo: customize with ADVOPT - worldViewIcons->preload(); - - for(int g = 0; g < ADVOPT.gemG.size(); ++g) - { - gems.push_back(std::make_shared(ADVOPT.gemG[g], 0, 0, ADVOPT.gemX[g], ADVOPT.gemY[g])); - } - - auto makeButton = [&](int textID, std::function callback, config::ButtonInfo info, int key) -> std::shared_ptr - { - auto button = std::make_shared(Point(info.x, info.y), info.defName, CGI->generaltexth->zelp[textID], callback, key, info.playerColoured); - for(auto image : info.additionalDefs) - button->addImage(image); - return button; - }; - - kingOverview = makeButton(293, std::bind(&CAdvMapInt::fshowOverview,this), ADVOPT.kingOverview, SDLK_k); - underground = makeButton(294, std::bind(&CAdvMapInt::fswitchLevel,this), ADVOPT.underground, SDLK_u); - questlog = makeButton(295, std::bind(&CAdvMapInt::fshowQuestlog,this), ADVOPT.questlog, SDLK_q); - sleepWake = makeButton(296, std::bind(&CAdvMapInt::fsleepWake,this), ADVOPT.sleepWake, SDLK_w); - moveHero = makeButton(297, std::bind(&CAdvMapInt::fmoveHero,this), ADVOPT.moveHero, SDLK_m); - spellbook = makeButton(298, std::bind(&CAdvMapInt::fshowSpellbok,this), ADVOPT.spellbook, SDLK_c); - advOptions = makeButton(299, std::bind(&CAdvMapInt::fadventureOPtions,this), ADVOPT.advOptions, SDLK_a); - sysOptions = makeButton(300, std::bind(&CAdvMapInt::fsystemOptions,this), ADVOPT.sysOptions, SDLK_o); - nextHero = makeButton(301, std::bind(&CAdvMapInt::fnextHero,this), ADVOPT.nextHero, SDLK_h); - endTurn = makeButton(302, std::bind(&CAdvMapInt::fendTurn,this), ADVOPT.endTurn, SDLK_e); - - int panelSpaceBottom = screen->h - resdatabar.pos.h - 4; - - panelMain = std::make_shared(nullptr, Point(0, 0)); - // TODO correct drawing position - panelWorldView = std::make_shared(worldViewIcons, bgWorldView, Point(heroList.pos.x - 2, 195), panelSpaceBottom, LOCPLINT->playerID); - - panelMain->addChildColorableButton(kingOverview); - panelMain->addChildColorableButton(underground); - panelMain->addChildColorableButton(questlog); - panelMain->addChildColorableButton(sleepWake); - panelMain->addChildColorableButton(moveHero); - panelMain->addChildColorableButton(spellbook); - panelMain->addChildColorableButton(advOptions); - panelMain->addChildColorableButton(sysOptions); - panelMain->addChildColorableButton(nextHero); - panelMain->addChildColorableButton(endTurn); - - - // TODO move configs to resolutions.json, similarly to previous buttons - config::ButtonInfo worldViewBackConfig = config::ButtonInfo(); - worldViewBackConfig.defName = "IOK6432.DEF"; - worldViewBackConfig.x = screen->w - 73; - worldViewBackConfig.y = 343 + 195; - worldViewBackConfig.playerColoured = false; - panelWorldView->addChildToPanel( - makeButton(288, std::bind(&CAdvMapInt::fworldViewBack,this), worldViewBackConfig, SDLK_ESCAPE), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewPuzzleConfig = config::ButtonInfo(); - worldViewPuzzleConfig.defName = "VWPUZ.DEF"; - worldViewPuzzleConfig.x = screen->w - 188; - worldViewPuzzleConfig.y = 343 + 195; - worldViewPuzzleConfig.playerColoured = false; - panelWorldView->addChildToPanel( // no help text for this one - std::make_shared(Point(worldViewPuzzleConfig.x, worldViewPuzzleConfig.y), worldViewPuzzleConfig.defName, std::pair(), - std::bind(&CPlayerInterface::showPuzzleMap,LOCPLINT), SDLK_p, worldViewPuzzleConfig.playerColoured), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewScale1xConfig = config::ButtonInfo(); - worldViewScale1xConfig.defName = "VWMAG1.DEF"; - worldViewScale1xConfig.x = screen->w - 191; - worldViewScale1xConfig.y = 23 + 195; - worldViewScale1xConfig.playerColoured = false; - panelWorldView->addChildToPanel( // help text is wrong for this button - makeButton(291, std::bind(&CAdvMapInt::fworldViewScale1x,this), worldViewScale1xConfig, SDLK_1), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewScale2xConfig = config::ButtonInfo(); - worldViewScale2xConfig.defName = "VWMAG2.DEF"; - worldViewScale2xConfig.x = screen->w - 191 + 63; - worldViewScale2xConfig.y = 23 + 195; - worldViewScale2xConfig.playerColoured = false; - panelWorldView->addChildToPanel( // help text is wrong for this button - makeButton(291, std::bind(&CAdvMapInt::fworldViewScale2x,this), worldViewScale2xConfig, SDLK_2), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewScale4xConfig = config::ButtonInfo(); - worldViewScale4xConfig.defName = "VWMAG4.DEF"; - worldViewScale4xConfig.x = screen->w - 191 + 126; - worldViewScale4xConfig.y = 23 + 195; - worldViewScale4xConfig.playerColoured = false; - panelWorldView->addChildToPanel( // help text is wrong for this button - makeButton(291, std::bind(&CAdvMapInt::fworldViewScale4x,this), worldViewScale4xConfig, SDLK_4), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewUndergroundConfig = config::ButtonInfo(); - worldViewUndergroundConfig.defName = "IAM010.DEF"; - worldViewUndergroundConfig.additionalDefs.push_back("IAM003.DEF"); - worldViewUndergroundConfig.x = screen->w - 115; - worldViewUndergroundConfig.y = 343 + 195; - worldViewUndergroundConfig.playerColoured = true; - worldViewUnderground = makeButton(294, std::bind(&CAdvMapInt::fswitchLevel,this), worldViewUndergroundConfig, SDLK_u); - panelWorldView->addChildColorableButton(worldViewUnderground); - - setPlayer(LOCPLINT->playerID); - - int iconColorMultiplier = player.getNum() * 19; - int wvLeft = heroList.pos.x - 2; // TODO correct drawing position - //int wvTop = 195; - for (int i = 0; i < 5; ++i) - { - panelWorldView->addChildIcon(std::pair(i, Point(5, 58 + i * 20)), iconColorMultiplier); - panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 263 + i * 20, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, - Colors::WHITE, CGI->generaltexth->allTexts[612 + i])); - } - for (int i = 0; i < 7; ++i) - { - panelWorldView->addChildIcon(std::pair(i + 5, Point(5, 182 + i * 20)), iconColorMultiplier); - panelWorldView->addChildIcon(std::pair(i + 12, Point(160, 182 + i * 20)), iconColorMultiplier); - panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 387 + i * 20, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, - Colors::WHITE, CGI->generaltexth->allTexts[619 + i])); - } - panelWorldView->addChildToPanel(std::make_shared(wvLeft + 5, 367, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, - Colors::WHITE, CGI->generaltexth->allTexts[617])); - panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 367, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, - Colors::WHITE, CGI->generaltexth->allTexts[618])); - - activeMapPanel = panelMain; - - changeMode(EAdvMapMode::NORMAL); - - underground->block(!CGI->mh->map->twoLevel); - questlog->block(!CGI->mh->map->quests.size()); - worldViewUnderground->block(!CGI->mh->map->twoLevel); - - addUsedEvents(MOVE); -} - -void CAdvMapInt::fshowOverview() -{ - GH.pushIntT(); -} - -void CAdvMapInt::fworldViewBack() -{ - changeMode(EAdvMapMode::NORMAL); - CGI->mh->discardWorldViewCache(); - - auto hero = curHero(); - if (hero) - centerOn(hero); -} - -void CAdvMapInt::fworldViewScale1x() -{ - // TODO set corresponding scale button to "selected" mode - changeMode(EAdvMapMode::WORLD_VIEW, 0.22f); -} - -void CAdvMapInt::fworldViewScale2x() -{ - changeMode(EAdvMapMode::WORLD_VIEW, 0.36f); -} - -void CAdvMapInt::fworldViewScale4x() -{ - changeMode(EAdvMapMode::WORLD_VIEW, 0.5f); -} - -void CAdvMapInt::fswitchLevel() -{ - // with support for future multi-level maps :) - int maxLevels = CGI->mh->map->levels(); - if (maxLevels < 2) - return; - - position.z = (position.z + 1) % maxLevels; - - underground->setIndex(position.z, true); - underground->redraw(); - - worldViewUnderground->setIndex(position.z, true); - worldViewUnderground->redraw(); - - updateScreen = true; - minimap.setLevel(position.z); - - if (mode == EAdvMapMode::WORLD_VIEW) - terrain.redraw(); -} -void CAdvMapInt::fshowQuestlog() -{ - LOCPLINT->showQuestLog(); -} -void CAdvMapInt::fsleepWake() -{ - const CGHeroInstance *h = curHero(); - if (!h) - return; - bool newSleep = !isHeroSleeping(h); - setHeroSleeping(h, newSleep); - updateSleepWake(h); - if (newSleep) - { - fnextHero(); - - //moveHero.block(true); - //uncomment to enable original HoMM3 behaviour: - //move button is disabled for hero going to sleep, even though it's enabled when you reselect him - } -} - -void CAdvMapInt::fmoveHero() -{ - const CGHeroInstance *h = curHero(); - if (!h || !terrain.currentPath || !CGI->mh->canStartHeroMovement()) - return; - - LOCPLINT->moveHero(h, *terrain.currentPath); -} - -void CAdvMapInt::fshowSpellbok() -{ - if (!curHero()) //checking necessary values - return; - - centerOn(selection); - - GH.pushIntT(curHero(), LOCPLINT, false); -} - -void CAdvMapInt::fadventureOPtions() -{ - GH.pushIntT(); -} - -void CAdvMapInt::fsystemOptions() -{ - GH.pushIntT(); -} - -void CAdvMapInt::fnextHero() -{ - auto hero = dynamic_cast(selection); - int next = getNextHeroIndex(vstd::find_pos(LOCPLINT->wanderingHeroes, hero)); - if (next < 0) - return; - select(LOCPLINT->wanderingHeroes[next], true); -} - -void CAdvMapInt::fendTurn() -{ - if(!LOCPLINT->makingTurn) - return; - - if(settings["adventure"]["heroReminder"].Bool()) - { - for(auto hero : LOCPLINT->wanderingHeroes) - { - if(!isHeroSleeping(hero) && hero->movement > 0) - { - // Only show hero reminder if conditions met: - // - There still movement points - // - Hero don't have a path or there not points for first step on path - auto path = LOCPLINT->getAndVerifyPath(hero); - if(!path || path->nodes.size() < 2 || !path->nodes[path->nodes.size()-2].turns) - { - LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[55], std::bind(&CAdvMapInt::endingTurn, this), nullptr); - return; - } - } - } - } - endingTurn(); -} - -void CAdvMapInt::updateSleepWake(const CGHeroInstance *h) -{ - sleepWake->block(!h); - if (!h) - return; - bool state = isHeroSleeping(h); - sleepWake->setIndex(state ? 1 : 0, true); - sleepWake->assignedKeys.clear(); - sleepWake->assignedKeys.insert(state ? SDLK_w : SDLK_z); -} - -void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath) -{ - if(!h) - { - moveHero->block(true); - return; - } - //default value is for everywhere but CPlayerInterface::moveHero, because paths are not updated from there immediately - if(boost::logic::indeterminate(hasPath)) - hasPath = LOCPLINT->paths[h].nodes.size() ? true : false; - - moveHero->block(!(bool)hasPath || (h->movement == 0)); -} - -void CAdvMapInt::updateSpellbook(const CGHeroInstance *h) -{ - spellbook->block(!h); -} - -int CAdvMapInt::getNextHeroIndex(int startIndex) -{ - if (LOCPLINT->wanderingHeroes.size() == 0) - return -1; - if (startIndex < 0) - startIndex = 0; - int i = startIndex; - do - { - i++; - if (i >= LOCPLINT->wanderingHeroes.size()) - i = 0; - } - while (((LOCPLINT->wanderingHeroes[i]->movement == 0) || isHeroSleeping(LOCPLINT->wanderingHeroes[i])) && (i != startIndex)); - - if ((LOCPLINT->wanderingHeroes[i]->movement != 0) && !isHeroSleeping(LOCPLINT->wanderingHeroes[i])) - return i; - else - return -1; -} - -void CAdvMapInt::updateNextHero(const CGHeroInstance *h) -{ - int start = vstd::find_pos(LOCPLINT->wanderingHeroes, h); - int next = getNextHeroIndex(start); - if (next < 0) - { - nextHero->block(true); - return; - } - const CGHeroInstance *nextH = LOCPLINT->wanderingHeroes[next]; - bool noActiveHeroes = (next == start) && ((nextH->movement == 0) || isHeroSleeping(nextH)); - nextHero->block(noActiveHeroes); -} - -void CAdvMapInt::activate() -{ - CIntObject::activate(); - if (!(active & KEYBOARD)) - CIntObject::activate(KEYBOARD); - - screenBuf = screen; - GH.statusbar = statusbar; - - if(LOCPLINT) - { - LOCPLINT->cingconsole->activate(); - LOCPLINT->cingconsole->pos = this->pos; - } - - if(!duringAITurn) - { - activeMapPanel->activate(); - if (mode == EAdvMapMode::NORMAL) - { - heroList.activate(); - townList.activate(); - infoBar.activate(); - } - minimap.activate(); - terrain.activate(); - statusbar->activate(); - - GH.fakeMouseMove(); //to restore the cursor - } -} - -void CAdvMapInt::deactivate() -{ - CIntObject::deactivate(); - - if(!duringAITurn) - { - scrollingDir = 0; - - CCS->curh->set(Cursor::Map::POINTER); - activeMapPanel->deactivate(); - if (mode == EAdvMapMode::NORMAL) - { - heroList.deactivate(); - townList.deactivate(); - infoBar.deactivate(); - } - minimap.deactivate(); - terrain.deactivate(); - statusbar->deactivate(); - } -} - -void CAdvMapInt::showAll(SDL_Surface * to) -{ - bg->draw(to, 0, 0); - - if(state != INGAME) - return; - - switch (mode) - { - case EAdvMapMode::NORMAL: - - heroList.showAll(to); - townList.showAll(to); - infoBar.showAll(to); - break; - case EAdvMapMode::WORLD_VIEW: - - terrain.showAll(to); - break; - } - activeMapPanel->showAll(to); - - updateScreen = true; - minimap.showAll(to); - show(to); - - - resdatabar.showAll(to); - - statusbar->show(to); - - LOCPLINT->cingconsole->show(to); -} - -bool CAdvMapInt::isHeroSleeping(const CGHeroInstance *hero) -{ - if (!hero) - return false; - - return vstd::contains(LOCPLINT->sleepingHeroes, hero); -} - -void CAdvMapInt::setHeroSleeping(const CGHeroInstance *hero, bool sleep) -{ - if (sleep) - LOCPLINT->sleepingHeroes.push_back(hero); //FIXME: should we check for existence? - else - LOCPLINT->sleepingHeroes -= hero; - updateNextHero(nullptr); -} - -void CAdvMapInt::show(SDL_Surface * to) -{ - if(state != INGAME) - return; - - ++animValHitCount; //for animations - - if(animValHitCount % 2 == 0) - { - ++heroAnim; - } - if(animValHitCount >= 8) - { - CGI->mh->updateWater(); - animValHitCount = 0; - ++anim; - updateScreen = true; - } - - if(swipeEnabled) - { - handleSwipeUpdate(); - } -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) // on mobile, map-moving mode is exclusive (TODO technically it might work with both enabled; to be checked) - else -#endif - { - handleMapScrollingUpdate(); - } - - for(int i = 0; i < 4; i++) - { - if(settings["session"]["spectate"].Bool()) - gems[i]->setFrame(PlayerColor(1).getNum()); - else - gems[i]->setFrame(LOCPLINT->playerID.getNum()); - } - if(updateScreen) - { - int3 betterPos = LOCPLINT->repairScreenPos(position); - if (betterPos != position) - { - logGlobal->warn("Incorrect position for adventure map!"); - position = betterPos; - } - - terrain.show(to); - for(int i = 0; i < 4; i++) - gems[i]->showAll(to); - updateScreen=false; - LOCPLINT->cingconsole->show(to); - } - else if (terrain.needsAnimUpdate()) - { - terrain.showAnim(to); - for(int i = 0; i < 4; i++) - gems[i]->showAll(to); - } - - infoBar.show(to); - statusbar->showAll(to); -} - -void CAdvMapInt::handleMapScrollingUpdate() -{ - int scrollSpeed = static_cast(settings["adventure"]["scrollSpeed"].Float()); - //if advmap needs updating AND (no dialog is shown OR ctrl is pressed) - if((animValHitCount % (4 / scrollSpeed)) == 0 - && ((GH.topInt().get() == this) || isCtrlKeyDown())) - { - if((scrollingDir & LEFT) && (position.x > -CGI->mh->frameW)) - position.x--; - - if((scrollingDir & RIGHT) && (position.x < CGI->mh->map->width - CGI->mh->tilesW + CGI->mh->frameW)) - position.x++; - - if((scrollingDir & UP) && (position.y > -CGI->mh->frameH)) - position.y--; - - if((scrollingDir & DOWN) && (position.y < CGI->mh->map->height - CGI->mh->tilesH + CGI->mh->frameH)) - position.y++; - - if(scrollingDir) - { - setScrollingCursor(scrollingDir); - scrollingState = true; - updateScreen = true; - minimap.redraw(); - if(mode == EAdvMapMode::WORLD_VIEW) - terrain.redraw(); - } - else if(scrollingState) - { - CCS->curh->set(Cursor::Map::POINTER); - scrollingState = false; - } - } -} - -void CAdvMapInt::handleSwipeUpdate() -{ - if(swipeMovementRequested) - { - auto fixedPos = LOCPLINT->repairScreenPos(swipeTargetPosition); - position.x = fixedPos.x; - position.y = fixedPos.y; - CCS->curh->set(Cursor::Map::POINTER); - updateScreen = true; - minimap.redraw(); - swipeMovementRequested = false; - } -} - -void CAdvMapInt::selectionChanged() -{ - const CGTownInstance *to = LOCPLINT->towns[townList.getSelectedIndex()]; - if (selection != to) - select(to); -} - -void CAdvMapInt::centerOn(int3 on, bool fade) -{ - bool switchedLevels = on.z != position.z; - - if (fade) - { - terrain.fadeFromCurrentView(); - } - - switch (mode) - { - default: - case EAdvMapMode::NORMAL: - on.x -= CGI->mh->frameW; // is this intentional? frame size doesn't really have to correspond to camera size... - on.y -= CGI->mh->frameH; - break; - case EAdvMapMode::WORLD_VIEW: - on.x -= static_cast(CGI->mh->tilesW / 2 / worldViewScale); - on.y -= static_cast(CGI->mh->tilesH / 2 / worldViewScale); - break; - } - - - on = LOCPLINT->repairScreenPos(on); - - position = on; - updateScreen=true; - underground->setIndex(on.z,true); //change underground switch button image - underground->redraw(); - worldViewUnderground->setIndex(on.z, true); - worldViewUnderground->redraw(); - if (switchedLevels) - minimap.setLevel(position.z); - minimap.redraw(); - - if (mode == EAdvMapMode::WORLD_VIEW) - terrain.redraw(); -} - -void CAdvMapInt::centerOn(const CGObjectInstance * obj, bool fade) -{ - centerOn(obj->getSightCenter(), fade); -} - -void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) -{ - - if (mode == EAdvMapMode::WORLD_VIEW) - return; - - ui8 Dir = 0; - SDL_Keycode k = key.keysym.sym; - const CGHeroInstance *h = curHero(); //selected hero - const CGTownInstance *t = curTown(); //selected town - - switch(k) - { - case SDLK_g: - if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) - return; - - { - //find first town with tavern - auto itr = range::find_if(LOCPLINT->towns, [](const CGTownInstance * town) - { - return town->hasBuilt(BuildingID::TAVERN); - }); - - if(itr != LOCPLINT->towns.end()) - LOCPLINT->showThievesGuildWindow(*itr); - else - LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithTavern")); - } - return; - case SDLK_i: - if(isActive()) - CAdventureOptions::showScenarioInfo(); - return; - case SDLK_l: - if(isActive()) - LOCPLINT->proposeLoadingGame(); - return; - case SDLK_s: - if(isActive() && key.type == SDL_KEYUP) - GH.pushIntT(); - return; - case SDLK_d: - { - if(h && isActive() && LOCPLINT->makingTurn && key.state == SDL_PRESSED) - LOCPLINT->tryDiggging(h); - return; - } - case SDLK_p: - if(isActive()) - LOCPLINT->showPuzzleMap(); - return; - case SDLK_v: - if(isActive()) - LOCPLINT->viewWorldMap(); - return; - case SDLK_r: - if(isActive() && LOCPLINT->ctrlPressed()) - { - LOCPLINT->showYesNoDialog(CGI->generaltexth->translate("vcmi.adventureMap.confirmRestartGame"), - [](){ LOCPLINT->sendCustomEvent(EUserEvent::RESTART_GAME); }, nullptr); - } - return; - case SDLK_SPACE: //space - try to revisit current object with selected hero - { - if(!isActive()) - return; - if(h && key.state == SDL_PRESSED) - { - auto unlockPim = vstd::makeUnlockGuard(*CPlayerInterface::pim); - //TODO!!!!!!! possible freeze, when GS mutex is locked and network thread can't apply package - //this thread leaves scope and tries to lock pim while holding gs, - //network thread tries to lock gs (appluy cl) while holding pim - //this thread should first lock pim, however gs locking/unlocking is done inside cb - LOCPLINT->cb->moveHero(h,h->pos); - } - } - return; - case SDLK_RETURN: - { - if(!isActive() || !selection || key.state != SDL_PRESSED) - return; - if(h) - LOCPLINT->openHeroWindow(h); - else if(t) - LOCPLINT->openTownWindow(t); - return; - } - case SDLK_ESCAPE: - { - if(isActive() || GH.topInt().get() != this || !spellBeingCasted || key.state != SDL_PRESSED) - return; - - leaveCastingMode(); - return; - } - case SDLK_t: - { - //act on key down if marketplace windows is not already opened - if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) - return; - - if(LOCPLINT->ctrlPressed()) //CTRL + T => open marketplace - { - //check if we have any marketplace - const CGTownInstance *townWithMarket = nullptr; - for(const CGTownInstance *t : LOCPLINT->cb->getTownsInfo()) - { - if(t->hasBuilt(BuildingID::MARKETPLACE)) - { - townWithMarket = t; - break; - } - } - - if(townWithMarket) //if any town has marketplace, open window - GH.pushIntT(townWithMarket); - else //if not - complain - LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithMarket")); - } - else if(isActive()) //no ctrl, advmapint is on the top => switch to town - { - townList.selectNext(); - } - return; - } - default: - { - static const int3 directions[] = { int3(-1, +1, 0), int3(0, +1, 0), int3(+1, +1, 0), - int3(-1, 0, 0), int3(0, 0, 0), int3(+1, 0, 0), - int3(-1, -1, 0), int3(0, -1, 0), int3(+1, -1, 0) }; - - //numpad arrow - if(CGuiHandler::isArrowKey(k)) - k = CGuiHandler::arrowToNum(k); - - k -= SDLK_KP_1; - - if(k < 0 || k > 8) - return; - - if (!CGI->mh->canStartHeroMovement()) - return; - - int3 dir = directions[k]; - - if(!isActive() || LOCPLINT->ctrlPressed())//ctrl makes arrow move screen, not hero - { - Dir = (dir.x<0 ? LEFT : 0) | - (dir.x>0 ? RIGHT : 0) | - (dir.y<0 ? UP : 0) | - (dir.y>0 ? DOWN : 0) ; - break; - } - - if(!h || key.state != SDL_PRESSED) - break; - - if(k == 4) - { - centerOn(h); - return; - } - - CGPath &path = LOCPLINT->paths[h]; - terrain.currentPath = &path; - int3 dst = h->visitablePos() + dir; - if(dst != verifyPos(dst) || !LOCPLINT->cb->getPathsInfo(h)->getPath(path, dst)) - { - terrain.currentPath = nullptr; - return; - } - - if (path.nodes.size() > 2) - updateMoveHero(h); - else - if(!path.nodes[0].turns) - LOCPLINT->moveHero(h, path); - } - - return; - } - if(Dir && key.state == SDL_PRESSED //arrow is pressed - && LOCPLINT->ctrlPressed() - ) - scrollingDir |= Dir; - else - scrollingDir &= ~Dir; -} -void CAdvMapInt::handleRightClick(std::string text, tribool down) -{ - if(down) - { - CRClickPopup::createAndPush(text); - } -} -int3 CAdvMapInt::verifyPos(int3 ver) -{ - if (ver.x<0) - ver.x=0; - if (ver.y<0) - ver.y=0; - if (ver.z<0) - ver.z=0; - if (ver.x>=CGI->mh->sizes.x) - ver.x=CGI->mh->sizes.x-1; - if (ver.y>=CGI->mh->sizes.y) - ver.y=CGI->mh->sizes.y-1; - if (ver.z>=CGI->mh->sizes.z) - ver.z=CGI->mh->sizes.z-1; - return ver; -} - -void CAdvMapInt::select(const CArmedInstance *sel, bool centerView) -{ - assert(sel); - LOCPLINT->setSelection(sel); - selection = sel; - if (LOCPLINT->battleInt == nullptr && LOCPLINT->makingTurn) - { - auto pos = sel->visitablePos(); - auto tile = LOCPLINT->cb->getTile(pos); - if(tile) - CCS->musich->playMusicFromSet("terrain", tile->terType->getJsonKey(), true, false); - } - if(centerView) - centerOn(sel); - - terrain.currentPath = nullptr; - if(sel->ID==Obj::TOWN) - { - auto town = dynamic_cast(sel); - - infoBar.showTownSelection(town); - townList.select(town); - heroList.select(nullptr); - - updateSleepWake(nullptr); - updateMoveHero(nullptr); - updateSpellbook(nullptr); - } - else //hero selected - { - auto hero = dynamic_cast(sel); - - infoBar.showHeroSelection(hero); - heroList.select(hero); - townList.select(nullptr); - - terrain.currentPath = LOCPLINT->getAndVerifyPath(hero); - - updateSleepWake(hero); - updateMoveHero(hero); - updateSpellbook(hero); - } - townList.redraw(); - heroList.redraw(); -} - -void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent ) -{ -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - if(swipeEnabled) - return; -#endif - // adventure map scrolling with mouse - // currently disabled in world view mode (as it is in OH3), but should work correctly if mode check is removed - // don't scroll if there is no window in focus - these events don't seem to correspond to the actual mouse movement - if(!isCtrlKeyDown() && isActive() && sEvent.windowID != 0 && mode == EAdvMapMode::NORMAL) - { - if(sEvent.x<15) - { - scrollingDir |= LEFT; - } - else - { - scrollingDir &= ~LEFT; - } - if(sEvent.x>screen->w-15) - { - scrollingDir |= RIGHT; - } - else - { - scrollingDir &= ~RIGHT; - } - if(sEvent.y<15) - { - scrollingDir |= UP; - } - else - { - scrollingDir &= ~UP; - } - if(sEvent.y>screen->h-15) - { - scrollingDir |= DOWN; - } - else - { - scrollingDir &= ~DOWN; - } - } -} - -bool CAdvMapInt::isActive() -{ - return active & ~CIntObject::KEYBOARD; -} - -void CAdvMapInt::startHotSeatWait(PlayerColor Player) -{ - state = WAITING; -} - -void CAdvMapInt::setPlayer(PlayerColor Player) -{ - player = Player; - bg->playerColored(player); - - panelMain->setPlayerColor(player); - panelWorldView->setPlayerColor(player); - panelWorldView->recolorIcons(player, player.getNum() * 19); - resdatabar.background->colorize(player); -} - -void CAdvMapInt::startTurn() -{ - state = INGAME; - if(LOCPLINT->cb->getCurrentPlayer() == LOCPLINT->playerID - || settings["session"]["spectate"].Bool()) - { - adjustActiveness(false); - minimap.setAIRadar(false); - } -} - -void CAdvMapInt::endingTurn() -{ - if(settings["session"]["spectate"].Bool()) - return; - - LOCPLINT->makingTurn = false; - LOCPLINT->cb->endTurn(); - CCS->soundh->ambientStopAllChannels(); -} - -const CGObjectInstance* CAdvMapInt::getActiveObject(const int3 &mapPos) -{ - std::vector < const CGObjectInstance * > bobjs = LOCPLINT->cb->getBlockingObjs(mapPos); //blocking objects at tile - - if (bobjs.empty()) - return nullptr; - - return *boost::range::max_element(bobjs, &CMapHandler::compareObjectBlitOrder); -/* - if (bobjs.back()->ID == Obj::HERO) - return bobjs.back(); - else - return bobjs.front();*/ -} - -void CAdvMapInt::tileLClicked(const int3 &mapPos) -{ - if(mode != EAdvMapMode::NORMAL) - return; - if(!LOCPLINT->cb->isVisible(mapPos) || !LOCPLINT->makingTurn) - return; - - const TerrainTile *tile = LOCPLINT->cb->getTile(mapPos); - - const CGObjectInstance *topBlocking = getActiveObject(mapPos); - - int3 selPos = selection->getSightCenter(); - if(spellBeingCasted && isInScreenRange(selPos, mapPos)) - { - const TerrainTile *heroTile = LOCPLINT->cb->getTile(selPos); - - switch(spellBeingCasted->id) - { - case SpellID::SCUTTLE_BOAT: //Scuttle Boat - if(topBlocking && topBlocking->ID == Obj::BOAT) - leaveCastingMode(true, mapPos); - break; - case SpellID::DIMENSION_DOOR: - if(!tile || tile->isClear(heroTile)) - leaveCastingMode(true, mapPos); - break; - } - return; - } - //check if we can select this object - bool canSelect = topBlocking && topBlocking->ID == Obj::HERO && topBlocking->tempOwner == LOCPLINT->playerID; - canSelect |= topBlocking && topBlocking->ID == Obj::TOWN && LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, topBlocking->tempOwner); - - bool isHero = false; - if(selection->ID != Obj::HERO) //hero is not selected (presumably town) - { - assert(!terrain.currentPath); //path can be active only when hero is selected - if(selection == topBlocking) //selected town clicked - LOCPLINT->openTownWindow(static_cast(topBlocking)); - else if(canSelect) - select(static_cast(topBlocking), false); - } - else if(const CGHeroInstance * currentHero = curHero()) //hero is selected - { - isHero = true; - - const CGPathNode *pn = LOCPLINT->cb->getPathsInfo(currentHero)->getPathInfo(mapPos); - if(currentHero == topBlocking) //clicked selected hero - { - LOCPLINT->openHeroWindow(currentHero); - return; - } - else if(canSelect && pn->turns == 255 ) //selectable object at inaccessible tile - { - select(static_cast(topBlocking), false); - return; - } - else //still here? we need to move hero if we clicked end of already selected path or calculate a new path otherwise - { - if(terrain.currentPath && terrain.currentPath->endPos() == mapPos)//we'll be moving - { - if(CGI->mh->canStartHeroMovement()) - LOCPLINT->moveHero(currentHero, *terrain.currentPath); - return; - } - else //remove old path and find a new one if we clicked on accessible tile - { - CGPath &path = LOCPLINT->paths[currentHero]; - CGPath newpath; - bool gotPath = LOCPLINT->cb->getPathsInfo(currentHero)->getPath(newpath, mapPos); //try getting path, erase if failed - if(gotPath && newpath.nodes.size()) - path = newpath; - - if(path.nodes.size()) - terrain.currentPath = &path; - else - LOCPLINT->eraseCurrentPathOf(currentHero); - - updateMoveHero(currentHero); - } - } - } //end of hero is selected "case" - else - { - throw std::runtime_error("Nothing is selected..."); - } - - const auto shipyard = ourInaccessibleShipyard(topBlocking); - if(isHero && shipyard != nullptr) - { - LOCPLINT->showShipyardDialogOrProblemPopup(shipyard); - } -} - -void CAdvMapInt::tileHovered(const int3 &mapPos) -{ - if(mode != EAdvMapMode::NORMAL //disable in world view - || !selection) //may occur just at the start of game (fake move before full intiialization) - return; - if(!LOCPLINT->cb->isVisible(mapPos)) - { - CCS->curh->set(Cursor::Map::POINTER); - statusbar->clear(); - return; - } - auto objRelations = PlayerRelations::ALLIES; - const CGObjectInstance *objAtTile = getActiveObject(mapPos); - if(objAtTile) - { - objRelations = LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, objAtTile->tempOwner); - std::string text = curHero() ? objAtTile->getHoverText(curHero()) : objAtTile->getHoverText(LOCPLINT->playerID); - boost::replace_all(text,"\n"," "); - statusbar->write(text); - } - else - { - std::string hlp; - CGI->mh->getTerrainDescr(mapPos, hlp, false); - statusbar->write(hlp); - } - - if(spellBeingCasted) - { - switch(spellBeingCasted->id) - { - case SpellID::SCUTTLE_BOAT: - if(objAtTile && objAtTile->ID == Obj::BOAT) - CCS->curh->set(Cursor::Map::SCUTTLE_BOAT); - else - CCS->curh->set(Cursor::Map::POINTER); - return; - case SpellID::DIMENSION_DOOR: - { - const TerrainTile * t = LOCPLINT->cb->getTile(mapPos, false); - int3 hpos = selection->getSightCenter(); - if((!t || t->isClear(LOCPLINT->cb->getTile(hpos))) && isInScreenRange(hpos, mapPos)) - CCS->curh->set(Cursor::Map::TELEPORT); - else - CCS->curh->set(Cursor::Map::POINTER); - return; - } - } - } - - if(selection->ID == Obj::TOWN) - { - if(objAtTile) - { - if(objAtTile->ID == Obj::TOWN && objRelations != PlayerRelations::ENEMIES) - CCS->curh->set(Cursor::Map::TOWN); - else if(objAtTile->ID == Obj::HERO && objRelations == PlayerRelations::SAME_PLAYER) - CCS->curh->set(Cursor::Map::HERO); - else - CCS->curh->set(Cursor::Map::POINTER); - } - else - CCS->curh->set(Cursor::Map::POINTER); - } - else if(const CGHeroInstance * hero = curHero()) - { - std::array cursorMove = { Cursor::Map::T1_MOVE, Cursor::Map::T2_MOVE, Cursor::Map::T3_MOVE, Cursor::Map::T4_MOVE, }; - std::array cursorAttack = { Cursor::Map::T1_ATTACK, Cursor::Map::T2_ATTACK, Cursor::Map::T3_ATTACK, Cursor::Map::T4_ATTACK, }; - std::array cursorSail = { Cursor::Map::T1_SAIL, Cursor::Map::T2_SAIL, Cursor::Map::T3_SAIL, Cursor::Map::T4_SAIL, }; - std::array cursorDisembark = { Cursor::Map::T1_DISEMBARK, Cursor::Map::T2_DISEMBARK, Cursor::Map::T3_DISEMBARK, Cursor::Map::T4_DISEMBARK, }; - std::array cursorExchange = { Cursor::Map::T1_EXCHANGE, Cursor::Map::T2_EXCHANGE, Cursor::Map::T3_EXCHANGE, Cursor::Map::T4_EXCHANGE, }; - std::array cursorVisit = { Cursor::Map::T1_VISIT, Cursor::Map::T2_VISIT, Cursor::Map::T3_VISIT, Cursor::Map::T4_VISIT, }; - std::array cursorSailVisit = { Cursor::Map::T1_SAIL_VISIT, Cursor::Map::T2_SAIL_VISIT, Cursor::Map::T3_SAIL_VISIT, Cursor::Map::T4_SAIL_VISIT, }; - - const CGPathNode * pathNode = LOCPLINT->cb->getPathsInfo(hero)->getPathInfo(mapPos); - assert(pathNode); - - if(LOCPLINT->altPressed() && pathNode->reachable()) //overwrite status bar text with movement info - { - ShowMoveDetailsInStatusbar(*hero, *pathNode); - } - - int turns = pathNode->turns; - vstd::amin(turns, 3); - switch(pathNode->action) - { - case CGPathNode::NORMAL: - case CGPathNode::TELEPORT_NORMAL: - if(pathNode->layer == EPathfindingLayer::LAND) - CCS->curh->set(cursorMove[turns]); - else - CCS->curh->set(cursorSailVisit[turns]); - break; - - case CGPathNode::VISIT: - case CGPathNode::BLOCKING_VISIT: - case CGPathNode::TELEPORT_BLOCKING_VISIT: - if(objAtTile && objAtTile->ID == Obj::HERO) - { - if(selection == objAtTile) - CCS->curh->set(Cursor::Map::HERO); - else - CCS->curh->set(cursorExchange[turns]); - } - else if(pathNode->layer == EPathfindingLayer::LAND) - CCS->curh->set(cursorVisit[turns]); - else - CCS->curh->set(cursorSailVisit[turns]); - break; - - case CGPathNode::BATTLE: - case CGPathNode::TELEPORT_BATTLE: - CCS->curh->set(cursorAttack[turns]); - break; - - case CGPathNode::EMBARK: - CCS->curh->set(cursorSail[turns]); - break; - - case CGPathNode::DISEMBARK: - CCS->curh->set(cursorDisembark[turns]); - break; - - default: - if(objAtTile && objRelations != PlayerRelations::ENEMIES) - { - if(objAtTile->ID == Obj::TOWN) - CCS->curh->set(Cursor::Map::TOWN); - else if(objAtTile->ID == Obj::HERO && objRelations == PlayerRelations::SAME_PLAYER) - CCS->curh->set(Cursor::Map::HERO); - else - CCS->curh->set(Cursor::Map::POINTER); - } - else - CCS->curh->set(Cursor::Map::POINTER); - break; - } - } - - if(ourInaccessibleShipyard(objAtTile)) - { - CCS->curh->set(Cursor::Map::T1_SAIL); - } -} - -void CAdvMapInt::ShowMoveDetailsInStatusbar(const CGHeroInstance & hero, const CGPathNode & pathNode) -{ - const int maxMovementPointsAtStartOfLastTurn = pathNode.turns > 0 ? hero.maxMovePoints(pathNode.layer == EPathfindingLayer::LAND) : hero.movement; - const int movementPointsLastTurnCost = maxMovementPointsAtStartOfLastTurn - pathNode.moveRemains; - const int remainingPointsAfterMove = pathNode.turns == 0 ? pathNode.moveRemains : 0; - - std::string result = VLC->generaltexth->translate("vcmi.adventureMap", pathNode.turns > 0 ? "moveCostDetails" : "moveCostDetailsNoTurns"); - - boost::replace_first(result, "%TURNS", std::to_string(pathNode.turns)); - boost::replace_first(result, "%POINTS", std::to_string(movementPointsLastTurnCost)); - boost::replace_first(result, "%REMAINING", std::to_string(remainingPointsAfterMove)); - - statusbar->write(result); -} - -void CAdvMapInt::tileRClicked(const int3 &mapPos) -{ - if(mode != EAdvMapMode::NORMAL) - return; - if(spellBeingCasted) - { - leaveCastingMode(); - return; - } - if(!LOCPLINT->cb->isVisible(mapPos)) - { - CRClickPopup::createAndPush(VLC->generaltexth->allTexts[61]); //Uncharted Territory - return; - } - - const CGObjectInstance * obj = getActiveObject(mapPos); - if(!obj) - { - // Bare or undiscovered terrain - const TerrainTile * tile = LOCPLINT->cb->getTile(mapPos); - if (tile) - { - std::string hlp; - CGI->mh->getTerrainDescr(mapPos, hlp, true); - CRClickPopup::createAndPush(hlp); - } - return; - } - - CRClickPopup::createAndPush(obj, GH.getCursorPosition(), ETextAlignment::CENTER); -} - -void CAdvMapInt::enterCastingMode(const CSpell * sp) -{ - assert(sp->id == SpellID::SCUTTLE_BOAT || sp->id == SpellID::DIMENSION_DOOR); - spellBeingCasted = sp; - - deactivate(); - terrain.activate(); - GH.fakeMouseMove(); -} - -void CAdvMapInt::leaveCastingMode(bool cast, int3 dest) -{ - assert(spellBeingCasted); - SpellID id = spellBeingCasted->id; - spellBeingCasted = nullptr; - terrain.deactivate(); - activate(); - - if(cast) - LOCPLINT->cb->castSpell(curHero(), id, dest); - else - LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[731]); //Spell cancelled -} - -const CGHeroInstance * CAdvMapInt::curHero() const -{ - if(selection && selection->ID == Obj::HERO) - return static_cast(selection); - else - return nullptr; -} - -const CGTownInstance * CAdvMapInt::curTown() const -{ - if(selection && selection->ID == Obj::TOWN) - return static_cast(selection); - else - return nullptr; -} - -const IShipyard * CAdvMapInt::ourInaccessibleShipyard(const CGObjectInstance *obj) const -{ - const IShipyard *ret = IShipyard::castFrom(obj); - - if(!ret || - obj->tempOwner != player || - (CCS->curh->get() != Cursor::Map::T1_SAIL && CCS->curh->get() != Cursor::Map::POINTER)) - return nullptr; - - return ret; -} - -void CAdvMapInt::aiTurnStarted() -{ - if(settings["session"]["spectate"].Bool()) - return; - - adjustActiveness(true); - CCS->musich->playMusicFromSet("enemy-turn", true, false); - adventureInt->minimap.setAIRadar(true); - adventureInt->infoBar.startEnemyTurn(LOCPLINT->cb->getCurrentPlayer()); - adventureInt->infoBar.showAll(screen);//force refresh on inactive object -} - -void CAdvMapInt::adjustActiveness(bool aiTurnStart) -{ - bool wasActive = isActive(); - - if(wasActive) - deactivate(); - adventureInt->duringAITurn = aiTurnStart; - if(wasActive) - activate(); -} - -void CAdvMapInt::quickCombatLock() -{ - if(!duringAITurn) - deactivate(); -} - -void CAdvMapInt::quickCombatUnlock() -{ - if(!duringAITurn) - activate(); -} - -void CAdvMapInt::changeMode(EAdvMapMode newMode, float newScale) -{ - if (mode != newMode) - { - mode = newMode; - - switch (mode) - { - case EAdvMapMode::NORMAL: - panelMain->activate(); - panelWorldView->deactivate(); - activeMapPanel = panelMain; - - townList.activate(); - heroList.activate(); - infoBar.activate(); - - worldViewOptions.clear(); - - break; - case EAdvMapMode::WORLD_VIEW: - panelMain->deactivate(); - panelWorldView->activate(); - - activeMapPanel = panelWorldView; - - townList.deactivate(); - heroList.deactivate(); - infoBar.showSelection(); // to prevent new day animation interfering world view mode - infoBar.deactivate(); - - break; - } - worldViewScale = newScale; - redraw(); - } - else if (worldViewScale != newScale) // still in world view mode, but the scale changed - { - worldViewScale = newScale; - redraw(); - } -} - CAdventureOptions::CAdventureOptions() : CWindowObject(PLAYER_COLORED, "ADVOPTS") { @@ -2001,21 +125,3 @@ void CAdventureOptions::showScenarioInfo() } } -CAdvMapInt::WorldViewOptions::WorldViewOptions() -{ - clear(); -} - -void CAdvMapInt::WorldViewOptions::clear() -{ - showAllTerrain = false; - - iconPositions.clear(); -} - -void CAdvMapInt::WorldViewOptions::adjustDrawingInfo(MapDrawingInfo& info) -{ - info.showAllTerrain = showAllTerrain; - - info.additionalIcons = &iconPositions; -} diff --git a/client/adventureMap/CAdventureOptions.h b/client/adventureMap/CAdventureOptions.h index 6b1ae0ddc..b3513650b 100644 --- a/client/adventureMap/CAdventureOptions.h +++ b/client/adventureMap/CAdventureOptions.h @@ -36,13 +36,6 @@ class CFadeAnimation; struct MapDrawingInfo; -/*****************************/ - -enum class EAdvMapMode -{ - NORMAL, - WORLD_VIEW -}; /// Adventure options dialog where you can view the world, dig, play the replay of the last turn,... class CAdventureOptions : public CWindowObject @@ -59,218 +52,3 @@ public: static void showScenarioInfo(); }; -/// Holds information about which tiles of the terrain are shown/not shown at the screen -class CTerrainRect : public CIntObject -{ - SDL_Surface * fadeSurface; - EMapAnimRedrawStatus lastRedrawStatus; - std::shared_ptr fadeAnim; - - int3 swipeInitialMapPos; - int3 swipeInitialRealPos; - bool isSwiping; - static constexpr float SwipeTouchSlop = 16.0f; - - void handleHover(const SDL_MouseMotionEvent & sEvent); - void handleSwipeMove(const SDL_MouseMotionEvent & sEvent); - /// handles start/finish of swipe (press/release of corresponding button); returns true if state change was handled - bool handleSwipeStateChange(bool btnPressed); -public: - int tilesw, tilesh; //width and height of terrain to blit in tiles - int3 curHoveredTile; - int moveX, moveY; //shift between actual position of screen and the one we wil blit; ranges from -31 to 31 (in pixels) - CGPath * currentPath; - - CTerrainRect(); - virtual ~CTerrainRect(); - void deactivate() override; - void clickLeft(tribool down, bool previousState) override; - void clickRight(tribool down, bool previousState) override; - void clickMiddle(tribool down, bool previousState) override; - void hover(bool on) override; - void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; - void show(SDL_Surface * to) override; - void showAll(SDL_Surface * to) override; - void showAnim(SDL_Surface * to); - void showPath(const Rect &extRect, SDL_Surface * to); - int3 whichTileIsIt(const int x, const int y); //x,y are cursor position - int3 whichTileIsIt(); //uses current cursor pos - /// @returns number of visible tiles on screen respecting current map scaling - int3 tileCountOnScreen(); - /// animates view by caching current surface and crossfading it with normal screen - void fadeFromCurrentView(); - bool needsAnimUpdate(); -}; - -/// Resources bar which shows information about how many gold, crystals,... you have -/// Current date is displayed too -class CResDataBar : public CIntObject -{ -public: - std::shared_ptr background; - - std::vector > txtpos; - std::string datetext; - - void clickRight(tribool down, bool previousState) override; - CResDataBar(); - CResDataBar(const std::string &defname, int x, int y, int offx, int offy, int resdist, int datedist); - ~CResDataBar(); - - void draw(SDL_Surface * to); - void show(SDL_Surface * to) override; - void showAll(SDL_Surface * to) override; -}; - -/// That's a huge class which handles general adventure map actions and -/// shows the right menu(questlog, spellbook, end turn,..) from where you -/// can get to the towns and heroes. -class CAdvMapInt : public CIntObject -{ - //Return object that must be active at this tile (=clickable) - const CGObjectInstance *getActiveObject(const int3 &tile); - -public: - CAdvMapInt(); - - int3 position; //top left corner of visible map part - PlayerColor player; - - bool duringAITurn; - - enum{LEFT=1, RIGHT=2, UP=4, DOWN=8}; - ui8 scrollingDir; //uses enum: LEFT RIGHT, UP, DOWN - bool scrollingState; - bool swipeEnabled; - bool swipeMovementRequested; - int3 swipeTargetPosition; - - enum{NA, INGAME, WAITING} state; - - bool updateScreen; - ui8 anim, animValHitCount; //animation frame - ui8 heroAnim, heroAnimValHitCount; //animation frame - - EAdvMapMode mode; - float worldViewScale; - - struct WorldViewOptions - { - bool showAllTerrain; //for expert viewEarth - - std::vector iconPositions; - - WorldViewOptions(); - - void clear(); - - void adjustDrawingInfo(MapDrawingInfo & info); - }; - - WorldViewOptions worldViewOptions; - - std::shared_ptr bg; - std::shared_ptr bgWorldView; - std::vector> gems; - CMinimap minimap; - std::shared_ptr statusbar; - - std::shared_ptr kingOverview; - std::shared_ptr underground; - std::shared_ptr questlog; - std::shared_ptr sleepWake; - std::shared_ptr moveHero; - std::shared_ptr spellbook; - std::shared_ptr advOptions; - std::shared_ptr sysOptions; - std::shared_ptr nextHero; - std::shared_ptr endTurn; - - std::shared_ptr worldViewUnderground; - - CTerrainRect terrain; //visible terrain - CResDataBar resdatabar; - CHeroList heroList; - CTownList townList; - CInfoBar infoBar; - - std::shared_ptr panelMain; // panel that holds all right-side buttons in normal view - std::shared_ptr panelWorldView; // panel that holds all buttons and other ui in world view - std::shared_ptr activeMapPanel; // currently active panel (either main or world view, depending on current mode) - - std::shared_ptr worldViewIcons;// images for world view overlay - - const CSpell *spellBeingCasted; //nullptr if none - - const CArmedInstance *selection; //currently selected town/hero - - //functions bound to buttons - void fshowOverview(); - void fworldViewBack(); - void fworldViewScale1x(); - void fworldViewScale2x(); - void fworldViewScale4x(); - void fswitchLevel(); - void fshowQuestlog(); - void fsleepWake(); - void fmoveHero(); - void fshowSpellbok(); - void fadventureOPtions(); - void fsystemOptions(); - void fnextHero(); - void fendTurn(); - - void activate() override; - void deactivate() override; - - void show(SDL_Surface * to) override; //redraws terrain - void showAll(SDL_Surface * to) override; //shows and activates adv. map interface - - void select(const CArmedInstance *sel, bool centerView = true); - void selectionChanged(); - void centerOn(int3 on, bool fade = false); - void centerOn(const CGObjectInstance *obj, bool fade = false); - int3 verifyPos(int3 ver); - void handleRightClick(std::string text, tribool down); - void keyPressed(const SDL_KeyboardEvent & key) override; - void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; - bool isActive(); - - bool isHeroSleeping(const CGHeroInstance *hero); - void setHeroSleeping(const CGHeroInstance *hero, bool sleep); - int getNextHeroIndex(int startIndex); //for Next Hero button - cycles awake heroes with movement only - - void setPlayer(PlayerColor Player); - void startHotSeatWait(PlayerColor Player); - void startTurn(); - void endingTurn(); - void aiTurnStarted(); - - void adjustActiveness(bool aiTurnStart); //should be called every time at AI/human turn transition; blocks GUI during AI turn - void quickCombatLock(); //should be called when quick battle started - void quickCombatUnlock(); - void tileLClicked(const int3 &mapPos); - void tileHovered(const int3 &mapPos); - void tileRClicked(const int3 &mapPos); - void enterCastingMode(const CSpell * sp); - void leaveCastingMode(bool cast = false, int3 dest = int3(-1, -1, -1)); - const CGHeroInstance * curHero() const; - const CGTownInstance * curTown() const; - const IShipyard * ourInaccessibleShipyard(const CGObjectInstance *obj) const; //checks if obj is our ashipyard and cursor is 0,0 -> returns shipyard or nullptr else - //button updates - void updateSleepWake(const CGHeroInstance *h); - void updateMoveHero(const CGHeroInstance *h, tribool hasPath = boost::logic::indeterminate); - void updateSpellbook(const CGHeroInstance *h); - void updateNextHero(const CGHeroInstance *h); - - /// changes current adventure map mode; used to switch between default view and world view; scale is ignored if EAdvMapMode == NORMAL - void changeMode(EAdvMapMode newMode, float newScale = 0.36f); - - void handleMapScrollingUpdate(); - void handleSwipeUpdate(); - -private: - void ShowMoveDetailsInStatusbar(const CGHeroInstance & hero, const CGPathNode & pathNode); -}; - -extern std::shared_ptr adventureInt; diff --git a/client/adventureMap/CAdvmapInterface.cpp b/client/adventureMap/CAdvmapInterface.cpp index d0529f744..6b5ea8185 100644 --- a/client/adventureMap/CAdvmapInterface.cpp +++ b/client/adventureMap/CAdvmapInterface.cpp @@ -89,467 +89,6 @@ static void setScrollingCursor(ui8 direction) CCS->curh->set(Cursor::Map::SCROLL_SOUTH); } -CTerrainRect::CTerrainRect() - : fadeSurface(nullptr), - lastRedrawStatus(EMapAnimRedrawStatus::OK), - fadeAnim(std::make_shared()), - curHoveredTile(-1,-1,-1), - currentPath(nullptr) -{ - tilesw=(ADVOPT.advmapW+31)/32; - tilesh=(ADVOPT.advmapH+31)/32; - pos.x=ADVOPT.advmapX; - pos.y=ADVOPT.advmapY; - pos.w=ADVOPT.advmapW; - pos.h=ADVOPT.advmapH; - moveX = moveY = 0; - addUsedEvents(LCLICK | RCLICK | MCLICK | HOVER | MOVE); -} - -CTerrainRect::~CTerrainRect() -{ - if(fadeSurface) - SDL_FreeSurface(fadeSurface); -} - -void CTerrainRect::deactivate() -{ - CIntObject::deactivate(); - curHoveredTile = int3(-1,-1,-1); //we lost info about hovered tile when disabling -} - -void CTerrainRect::clickLeft(tribool down, bool previousState) -{ - if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) - return; - if(indeterminate(down)) - return; - -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - if(adventureInt->swipeEnabled) - { - if(handleSwipeStateChange((bool)down == true)) - { - return; // if swipe is enabled, we don't process "down" events and wait for "up" (to make sure this wasn't a swiping gesture) - } - } - else - { -#endif - if(down == false) - return; -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - } -#endif - int3 mp = whichTileIsIt(); - if(mp.x < 0 || mp.y < 0 || mp.x >= LOCPLINT->cb->getMapSize().x || mp.y >= LOCPLINT->cb->getMapSize().y) - return; - - adventureInt->tileLClicked(mp); -} - -void CTerrainRect::clickRight(tribool down, bool previousState) -{ -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - if(adventureInt->swipeEnabled && isSwiping) - return; -#endif - if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) - return; - int3 mp = whichTileIsIt(); - - if(CGI->mh->map->isInTheMap(mp) && down) - adventureInt->tileRClicked(mp); -} - -void CTerrainRect::clickMiddle(tribool down, bool previousState) -{ - handleSwipeStateChange((bool)down == true); -} - -void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent) -{ - handleHover(sEvent); - - if(!adventureInt->swipeEnabled) - return; - - handleSwipeMove(sEvent); -} - -void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent) -{ -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - if(sEvent.state == 0 || GH.multifinger) // any "button" is enough on mobile -#else - if((sEvent.state & SDL_BUTTON_MMASK) == 0) // swipe only works with middle mouse on other platforms -#endif - { - return; - } - - if(!isSwiping) - { - // try to distinguish if this touch was meant to be a swipe or just fat-fingering press - if(abs(sEvent.x - swipeInitialRealPos.x) > SwipeTouchSlop || - abs(sEvent.y - swipeInitialRealPos.y) > SwipeTouchSlop) - { - isSwiping = true; - } - } - - if(isSwiping) - { - adventureInt->swipeTargetPosition.x = - swipeInitialMapPos.x + static_cast(swipeInitialRealPos.x - sEvent.x) / 32; - adventureInt->swipeTargetPosition.y = - swipeInitialMapPos.y + static_cast(swipeInitialRealPos.y - sEvent.y) / 32; - adventureInt->swipeMovementRequested = true; - } -} - -bool CTerrainRect::handleSwipeStateChange(bool btnPressed) -{ - if(btnPressed) - { - swipeInitialRealPos = int3(GH.getCursorPosition().x, GH.getCursorPosition().y, 0); - swipeInitialMapPos = int3(adventureInt->position); - return true; - } - else if(isSwiping) // only accept this touch if it wasn't a swipe - { - isSwiping = false; - return true; - } - return false; -} - -void CTerrainRect::handleHover(const SDL_MouseMotionEvent &sEvent) -{ - int3 tHovered = whichTileIsIt(sEvent.x, sEvent.y); - int3 pom = adventureInt->verifyPos(tHovered); - - if(tHovered != pom) //tile outside the map - { - CCS->curh->set(Cursor::Map::POINTER); - return; - } - - if (pom != curHoveredTile) - { - curHoveredTile = pom; - adventureInt->tileHovered(pom); - } -} - -void CTerrainRect::hover(bool on) -{ - if (!on) - { - adventureInt->statusbar->clear(); - CCS->curh->set(Cursor::Map::POINTER); - } - //Hoverable::hover(on); -} -void CTerrainRect::showPath(const Rect & extRect, SDL_Surface * to) -{ - const static int pns[9][9] = { - {16, 17, 18, 7, -1, 19, 6, 5, -1}, - { 8, 9, 18, 7, -1, 19, 6, -1, 20}, - { 8, 1, 10, 7, -1, 19, -1, 21, 20}, - {24, 17, 18, 15, -1, -1, 6, 5, 4}, - {-1, -1, -1, -1, -1, -1, -1, -1, -1}, - { 8, 1, 2, -1, -1, 11, 22, 21, 20}, - {24, 17, -1, 23, -1, 3, 14, 5, 4}, - {24, -1, 2, 23, -1, 3, 22, 13, 4}, - {-1, 1, 2, 23, -1, 3, 22, 21, 12} - }; //table of magic values TODO meaning, change variable name - - for (int i = 0; i < -1 + (int)currentPath->nodes.size(); ++i) - { - const int3 &curPos = currentPath->nodes[i].coord, &nextPos = currentPath->nodes[i+1].coord; - if(curPos.z != adventureInt->position.z) - continue; - - int pn=-1;//number of picture - if (i==0) //last tile - { - int x = 32*(curPos.x-adventureInt->position.x)+CGI->mh->offsetX + pos.x, - y = 32*(curPos.y-adventureInt->position.y)+CGI->mh->offsetY + pos.y; - if (x<0 || y<0 || x>pos.w || y>pos.h) - continue; - pn=0; - } - else - { - const int3 &prevPos = currentPath->nodes[i-1].coord; - std::vector & cv = currentPath->nodes; - - /* Vector directions - * 0 1 2 - * \ | / - * 3 - 4 - 5 - * / | \ - * 6 7 8 - *For example: - * | - * |__\ - * / - * is id1=7, id2=5 (pns[7][5]) - */ - bool pathContinuous = curPos.areNeighbours(nextPos) && curPos.areNeighbours(prevPos); - if(pathContinuous && cv[i].action != CGPathNode::EMBARK && cv[i].action != CGPathNode::DISEMBARK) - { - int id1=(curPos.x-nextPos.x+1)+3*(curPos.y-nextPos.y+1); //Direction of entering vector - int id2=(cv[i-1].coord.x-curPos.x+1)+3*(cv[i-1].coord.y-curPos.y+1); //Direction of exiting vector - pn=pns[id1][id2]; - } - else //path discontinuity or sea/land transition (eg. when moving through Subterranean Gate or Boat) - { - pn = 0; - } - } - if (currentPath->nodes[i].turns) - pn+=25; - if (pn>=0) - { - const auto arrow = graphics->heroMoveArrows->getImage(pn); - - int x = 32*(curPos.x-adventureInt->position.x)+CGI->mh->offsetX + pos.x, - y = 32*(curPos.y-adventureInt->position.y)+CGI->mh->offsetY + pos.y; - if (x< -32 || y< -32 || x>pos.w || y>pos.h) - continue; - int hvx = (x + arrow->width()) - (pos.x + pos.w), - hvy = (y + arrow->height()) - (pos.y + pos.h); - - Rect prevClip; - CSDL_Ext::getClipRect(to, prevClip); - CSDL_Ext::setClipRect(to, extRect); //preventing blitting outside of that rect - - if(ADVOPT.smoothMove) //version for smooth hero move, with pos shifts - { - if (hvx<0 && hvy<0) - { - arrow->draw(to, x + moveX, y + moveY); - } - else if(hvx<0) - { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width(), 0, 0); - arrow->draw(to, x + moveX, y + moveY, &srcRect); - } - else if (hvy<0) - { - Rect srcRect = genRect(arrow->height(), arrow->width() - hvx, 0, 0); - arrow->draw(to, x + moveX, y + moveY, &srcRect); - } - else - { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); - arrow->draw(to, x + moveX, y + moveY, &srcRect); - } - } - else //standard version - { - if (hvx<0 && hvy<0) - { - arrow->draw(to, x, y); - } - else if(hvx<0) - { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width(), 0, 0); - arrow->draw(to, x, y, &srcRect); - } - else if (hvy<0) - { - Rect srcRect = genRect(arrow->height(), arrow->width() - hvx, 0, 0); - arrow->draw(to, x, y, &srcRect); - } - else - { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); - arrow->draw(to, x, y, &srcRect); - } - } - CSDL_Ext::setClipRect(to, prevClip); - - } - } //for (int i=0;inodes.size()-1;i++) -} - -void CTerrainRect::show(SDL_Surface * to) -{ - if (adventureInt->mode == EAdvMapMode::NORMAL) - { - MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), pos); - info.otherheroAnim = true; - info.anim = adventureInt->anim; - info.heroAnim = adventureInt->heroAnim; - if (ADVOPT.smoothMove) - info.movement = int3(moveX, moveY, 0); - - lastRedrawStatus = CGI->mh->drawTerrainRectNew(to, &info); - if (fadeAnim->isFading()) - { - Rect r(pos); - fadeAnim->update(); - fadeAnim->draw(to, r.topLeft()); - } - - if (currentPath/* && adventureInt->position.z==currentPath->startPos().z*/) //drawing path - { - showPath(pos, to); - } - } -} - -void CTerrainRect::showAll(SDL_Surface * to) -{ - // world view map is static and doesn't need redraw every frame - if (adventureInt->mode == EAdvMapMode::WORLD_VIEW) - { - MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), pos, adventureInt->worldViewIcons); - info.scaled = true; - info.scale = adventureInt->worldViewScale; - adventureInt->worldViewOptions.adjustDrawingInfo(info); - CGI->mh->drawTerrainRectNew(to, &info); - } -} - -void CTerrainRect::showAnim(SDL_Surface * to) -{ - if (fadeAnim->isFading()) - show(to); - else if (lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED) - show(to); // currently the same; maybe we should pass some flag to map handler so it redraws ONLY tiles that need redraw instead of full -} - -int3 CTerrainRect::whichTileIsIt(const int x, const int y) -{ - int3 ret; - ret.x = adventureInt->position.x + ((x-CGI->mh->offsetX-pos.x)/32); - ret.y = adventureInt->position.y + ((y-CGI->mh->offsetY-pos.y)/32); - ret.z = adventureInt->position.z; - return ret; -} - -int3 CTerrainRect::whichTileIsIt() -{ - return whichTileIsIt(GH.getCursorPosition().x, GH.getCursorPosition().y); -} - -int3 CTerrainRect::tileCountOnScreen() -{ - switch (adventureInt->mode) - { - default: - logGlobal->error("Unknown map mode %d", (int)adventureInt->mode); - return int3(); - case EAdvMapMode::NORMAL: - return int3(tilesw, tilesh, 1); - case EAdvMapMode::WORLD_VIEW: - return int3((si32)(tilesw / adventureInt->worldViewScale), (si32)(tilesh / adventureInt->worldViewScale), 1); - } -} - -void CTerrainRect::fadeFromCurrentView() -{ - if (!ADVOPT.screenFading) - return; - if (adventureInt->mode == EAdvMapMode::WORLD_VIEW) - return; - - if (!fadeSurface) - fadeSurface = CSDL_Ext::newSurface(pos.w, pos.h); - CSDL_Ext::blitSurface(screen, fadeSurface, Point(0,0)); - fadeAnim->init(CFadeAnimation::EMode::OUT, fadeSurface); -} - -bool CTerrainRect::needsAnimUpdate() -{ - return fadeAnim->isFading() || lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED; -} - -void CResDataBar::clickRight(tribool down, bool previousState) -{ -} - -CResDataBar::CResDataBar(const std::string & defname, int x, int y, int offx, int offy, int resdist, int datedist) -{ - pos.x += x; - pos.y += y; - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared(defname, 0, 0); - background->colorize(LOCPLINT->playerID); - - pos.w = background->pos.w; - pos.h = background->pos.h; - - txtpos.resize(8); - for (int i = 0; i < 8 ; i++) - { - txtpos[i].first = pos.x + offx + resdist*i; - txtpos[i].second = pos.y + offy; - } - txtpos[7].first = txtpos[6].first + datedist; - datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] - + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s"; - addUsedEvents(RCLICK); -} - -CResDataBar::CResDataBar() -{ - pos.x += ADVOPT.resdatabarX; - pos.y += ADVOPT.resdatabarY; - - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared(ADVOPT.resdatabarG, 0, 0); - background->colorize(LOCPLINT->playerID); - - pos.w = background->pos.w; - pos.h = background->pos.h; - - txtpos.resize(8); - for (int i = 0; i < 8 ; i++) - { - txtpos[i].first = pos.x + ADVOPT.resOffsetX + ADVOPT.resDist*i; - txtpos[i].second = pos.y + ADVOPT.resOffsetY; - } - txtpos[7].first = txtpos[6].first + ADVOPT.resDateDist; - datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] - + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s"; -} - -CResDataBar::~CResDataBar() = default; - -void CResDataBar::draw(SDL_Surface * to) -{ - //TODO: all this should be labels, but they require proper text update on change - for (auto i=Res::WOOD; i<=Res::GOLD; vstd::advance(i, 1)) - { - std::string text = boost::lexical_cast(LOCPLINT->cb->getResourceAmount(i)); - - graphics->fonts[FONT_SMALL]->renderTextLeft(to, text, Colors::WHITE, Point(txtpos[i].first,txtpos[i].second)); - } - std::vector temp; - - temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::MONTH))); - temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::WEEK))); - temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK))); - - graphics->fonts[FONT_SMALL]->renderTextLeft(to, processStr(datetext,temp), Colors::WHITE, Point(txtpos[7].first,txtpos[7].second)); -} - -void CResDataBar::show(SDL_Surface * to) -{ - -} - -void CResDataBar::showAll(SDL_Surface * to) -{ - CIntObject::showAll(to); - draw(to); -} - CAdvMapInt::CAdvMapInt(): mode(EAdvMapMode::NORMAL), worldViewScale(0.0f), //actual init later in changeMode @@ -1965,42 +1504,6 @@ void CAdvMapInt::changeMode(EAdvMapMode newMode, float newScale) } } -CAdventureOptions::CAdventureOptions() - : CWindowObject(PLAYER_COLORED, "ADVOPTS") -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - - viewWorld = std::make_shared(Point(24, 23), "ADVVIEW.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_v); - viewWorld->addCallback(std::bind(&CPlayerInterface::viewWorldMap, LOCPLINT)); - - exit = std::make_shared(Point(204, 313), "IOK6432.DEF", CButton::tooltip(), std::bind(&CAdventureOptions::close, this), SDLK_RETURN); - exit->assignedKeys.insert(SDLK_ESCAPE); - - scenInfo = std::make_shared(Point(24, 198), "ADVINFO.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_i); - scenInfo->addCallback(CAdventureOptions::showScenarioInfo); - - puzzle = std::make_shared(Point(24, 81), "ADVPUZ.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_p); - puzzle->addCallback(std::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT)); - - dig = std::make_shared(Point(24, 139), "ADVDIG.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_d); - if(const CGHeroInstance *h = adventureInt->curHero()) - dig->addCallback(std::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h)); - else - dig->block(true); -} - -void CAdventureOptions::showScenarioInfo() -{ - if(LOCPLINT->cb->getStartInfo()->campState) - { - GH.pushIntT(); - } - else - { - GH.pushIntT(); - } -} - CAdvMapInt::WorldViewOptions::WorldViewOptions() { clear(); @@ -2019,3 +1522,4 @@ void CAdvMapInt::WorldViewOptions::adjustDrawingInfo(MapDrawingInfo& info) info.additionalIcons = &iconPositions; } + diff --git a/client/adventureMap/CAdvmapInterface.h b/client/adventureMap/CAdvmapInterface.h index 6b1ae0ddc..a009c2833 100644 --- a/client/adventureMap/CAdvmapInterface.h +++ b/client/adventureMap/CAdvmapInterface.h @@ -44,84 +44,6 @@ enum class EAdvMapMode WORLD_VIEW }; -/// Adventure options dialog where you can view the world, dig, play the replay of the last turn,... -class CAdventureOptions : public CWindowObject -{ -public: - std::shared_ptr exit; - std::shared_ptr viewWorld; - std::shared_ptr puzzle; - std::shared_ptr dig; - std::shared_ptr scenInfo; - /*std::shared_ptr replay*/ - - CAdventureOptions(); - static void showScenarioInfo(); -}; - -/// Holds information about which tiles of the terrain are shown/not shown at the screen -class CTerrainRect : public CIntObject -{ - SDL_Surface * fadeSurface; - EMapAnimRedrawStatus lastRedrawStatus; - std::shared_ptr fadeAnim; - - int3 swipeInitialMapPos; - int3 swipeInitialRealPos; - bool isSwiping; - static constexpr float SwipeTouchSlop = 16.0f; - - void handleHover(const SDL_MouseMotionEvent & sEvent); - void handleSwipeMove(const SDL_MouseMotionEvent & sEvent); - /// handles start/finish of swipe (press/release of corresponding button); returns true if state change was handled - bool handleSwipeStateChange(bool btnPressed); -public: - int tilesw, tilesh; //width and height of terrain to blit in tiles - int3 curHoveredTile; - int moveX, moveY; //shift between actual position of screen and the one we wil blit; ranges from -31 to 31 (in pixels) - CGPath * currentPath; - - CTerrainRect(); - virtual ~CTerrainRect(); - void deactivate() override; - void clickLeft(tribool down, bool previousState) override; - void clickRight(tribool down, bool previousState) override; - void clickMiddle(tribool down, bool previousState) override; - void hover(bool on) override; - void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; - void show(SDL_Surface * to) override; - void showAll(SDL_Surface * to) override; - void showAnim(SDL_Surface * to); - void showPath(const Rect &extRect, SDL_Surface * to); - int3 whichTileIsIt(const int x, const int y); //x,y are cursor position - int3 whichTileIsIt(); //uses current cursor pos - /// @returns number of visible tiles on screen respecting current map scaling - int3 tileCountOnScreen(); - /// animates view by caching current surface and crossfading it with normal screen - void fadeFromCurrentView(); - bool needsAnimUpdate(); -}; - -/// Resources bar which shows information about how many gold, crystals,... you have -/// Current date is displayed too -class CResDataBar : public CIntObject -{ -public: - std::shared_ptr background; - - std::vector > txtpos; - std::string datetext; - - void clickRight(tribool down, bool previousState) override; - CResDataBar(); - CResDataBar(const std::string &defname, int x, int y, int offx, int offy, int resdist, int datedist); - ~CResDataBar(); - - void draw(SDL_Surface * to); - void show(SDL_Surface * to) override; - void showAll(SDL_Surface * to) override; -}; - /// That's a huge class which handles general adventure map actions and /// shows the right menu(questlog, spellbook, end turn,..) from where you /// can get to the towns and heroes. diff --git a/client/adventureMap/CResDataBar.cpp b/client/adventureMap/CResDataBar.cpp index d0529f744..2385d5f1c 100644 --- a/client/adventureMap/CResDataBar.cpp +++ b/client/adventureMap/CResDataBar.cpp @@ -89,386 +89,6 @@ static void setScrollingCursor(ui8 direction) CCS->curh->set(Cursor::Map::SCROLL_SOUTH); } -CTerrainRect::CTerrainRect() - : fadeSurface(nullptr), - lastRedrawStatus(EMapAnimRedrawStatus::OK), - fadeAnim(std::make_shared()), - curHoveredTile(-1,-1,-1), - currentPath(nullptr) -{ - tilesw=(ADVOPT.advmapW+31)/32; - tilesh=(ADVOPT.advmapH+31)/32; - pos.x=ADVOPT.advmapX; - pos.y=ADVOPT.advmapY; - pos.w=ADVOPT.advmapW; - pos.h=ADVOPT.advmapH; - moveX = moveY = 0; - addUsedEvents(LCLICK | RCLICK | MCLICK | HOVER | MOVE); -} - -CTerrainRect::~CTerrainRect() -{ - if(fadeSurface) - SDL_FreeSurface(fadeSurface); -} - -void CTerrainRect::deactivate() -{ - CIntObject::deactivate(); - curHoveredTile = int3(-1,-1,-1); //we lost info about hovered tile when disabling -} - -void CTerrainRect::clickLeft(tribool down, bool previousState) -{ - if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) - return; - if(indeterminate(down)) - return; - -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - if(adventureInt->swipeEnabled) - { - if(handleSwipeStateChange((bool)down == true)) - { - return; // if swipe is enabled, we don't process "down" events and wait for "up" (to make sure this wasn't a swiping gesture) - } - } - else - { -#endif - if(down == false) - return; -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - } -#endif - int3 mp = whichTileIsIt(); - if(mp.x < 0 || mp.y < 0 || mp.x >= LOCPLINT->cb->getMapSize().x || mp.y >= LOCPLINT->cb->getMapSize().y) - return; - - adventureInt->tileLClicked(mp); -} - -void CTerrainRect::clickRight(tribool down, bool previousState) -{ -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - if(adventureInt->swipeEnabled && isSwiping) - return; -#endif - if(adventureInt->mode == EAdvMapMode::WORLD_VIEW) - return; - int3 mp = whichTileIsIt(); - - if(CGI->mh->map->isInTheMap(mp) && down) - adventureInt->tileRClicked(mp); -} - -void CTerrainRect::clickMiddle(tribool down, bool previousState) -{ - handleSwipeStateChange((bool)down == true); -} - -void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent) -{ - handleHover(sEvent); - - if(!adventureInt->swipeEnabled) - return; - - handleSwipeMove(sEvent); -} - -void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent) -{ -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - if(sEvent.state == 0 || GH.multifinger) // any "button" is enough on mobile -#else - if((sEvent.state & SDL_BUTTON_MMASK) == 0) // swipe only works with middle mouse on other platforms -#endif - { - return; - } - - if(!isSwiping) - { - // try to distinguish if this touch was meant to be a swipe or just fat-fingering press - if(abs(sEvent.x - swipeInitialRealPos.x) > SwipeTouchSlop || - abs(sEvent.y - swipeInitialRealPos.y) > SwipeTouchSlop) - { - isSwiping = true; - } - } - - if(isSwiping) - { - adventureInt->swipeTargetPosition.x = - swipeInitialMapPos.x + static_cast(swipeInitialRealPos.x - sEvent.x) / 32; - adventureInt->swipeTargetPosition.y = - swipeInitialMapPos.y + static_cast(swipeInitialRealPos.y - sEvent.y) / 32; - adventureInt->swipeMovementRequested = true; - } -} - -bool CTerrainRect::handleSwipeStateChange(bool btnPressed) -{ - if(btnPressed) - { - swipeInitialRealPos = int3(GH.getCursorPosition().x, GH.getCursorPosition().y, 0); - swipeInitialMapPos = int3(adventureInt->position); - return true; - } - else if(isSwiping) // only accept this touch if it wasn't a swipe - { - isSwiping = false; - return true; - } - return false; -} - -void CTerrainRect::handleHover(const SDL_MouseMotionEvent &sEvent) -{ - int3 tHovered = whichTileIsIt(sEvent.x, sEvent.y); - int3 pom = adventureInt->verifyPos(tHovered); - - if(tHovered != pom) //tile outside the map - { - CCS->curh->set(Cursor::Map::POINTER); - return; - } - - if (pom != curHoveredTile) - { - curHoveredTile = pom; - adventureInt->tileHovered(pom); - } -} - -void CTerrainRect::hover(bool on) -{ - if (!on) - { - adventureInt->statusbar->clear(); - CCS->curh->set(Cursor::Map::POINTER); - } - //Hoverable::hover(on); -} -void CTerrainRect::showPath(const Rect & extRect, SDL_Surface * to) -{ - const static int pns[9][9] = { - {16, 17, 18, 7, -1, 19, 6, 5, -1}, - { 8, 9, 18, 7, -1, 19, 6, -1, 20}, - { 8, 1, 10, 7, -1, 19, -1, 21, 20}, - {24, 17, 18, 15, -1, -1, 6, 5, 4}, - {-1, -1, -1, -1, -1, -1, -1, -1, -1}, - { 8, 1, 2, -1, -1, 11, 22, 21, 20}, - {24, 17, -1, 23, -1, 3, 14, 5, 4}, - {24, -1, 2, 23, -1, 3, 22, 13, 4}, - {-1, 1, 2, 23, -1, 3, 22, 21, 12} - }; //table of magic values TODO meaning, change variable name - - for (int i = 0; i < -1 + (int)currentPath->nodes.size(); ++i) - { - const int3 &curPos = currentPath->nodes[i].coord, &nextPos = currentPath->nodes[i+1].coord; - if(curPos.z != adventureInt->position.z) - continue; - - int pn=-1;//number of picture - if (i==0) //last tile - { - int x = 32*(curPos.x-adventureInt->position.x)+CGI->mh->offsetX + pos.x, - y = 32*(curPos.y-adventureInt->position.y)+CGI->mh->offsetY + pos.y; - if (x<0 || y<0 || x>pos.w || y>pos.h) - continue; - pn=0; - } - else - { - const int3 &prevPos = currentPath->nodes[i-1].coord; - std::vector & cv = currentPath->nodes; - - /* Vector directions - * 0 1 2 - * \ | / - * 3 - 4 - 5 - * / | \ - * 6 7 8 - *For example: - * | - * |__\ - * / - * is id1=7, id2=5 (pns[7][5]) - */ - bool pathContinuous = curPos.areNeighbours(nextPos) && curPos.areNeighbours(prevPos); - if(pathContinuous && cv[i].action != CGPathNode::EMBARK && cv[i].action != CGPathNode::DISEMBARK) - { - int id1=(curPos.x-nextPos.x+1)+3*(curPos.y-nextPos.y+1); //Direction of entering vector - int id2=(cv[i-1].coord.x-curPos.x+1)+3*(cv[i-1].coord.y-curPos.y+1); //Direction of exiting vector - pn=pns[id1][id2]; - } - else //path discontinuity or sea/land transition (eg. when moving through Subterranean Gate or Boat) - { - pn = 0; - } - } - if (currentPath->nodes[i].turns) - pn+=25; - if (pn>=0) - { - const auto arrow = graphics->heroMoveArrows->getImage(pn); - - int x = 32*(curPos.x-adventureInt->position.x)+CGI->mh->offsetX + pos.x, - y = 32*(curPos.y-adventureInt->position.y)+CGI->mh->offsetY + pos.y; - if (x< -32 || y< -32 || x>pos.w || y>pos.h) - continue; - int hvx = (x + arrow->width()) - (pos.x + pos.w), - hvy = (y + arrow->height()) - (pos.y + pos.h); - - Rect prevClip; - CSDL_Ext::getClipRect(to, prevClip); - CSDL_Ext::setClipRect(to, extRect); //preventing blitting outside of that rect - - if(ADVOPT.smoothMove) //version for smooth hero move, with pos shifts - { - if (hvx<0 && hvy<0) - { - arrow->draw(to, x + moveX, y + moveY); - } - else if(hvx<0) - { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width(), 0, 0); - arrow->draw(to, x + moveX, y + moveY, &srcRect); - } - else if (hvy<0) - { - Rect srcRect = genRect(arrow->height(), arrow->width() - hvx, 0, 0); - arrow->draw(to, x + moveX, y + moveY, &srcRect); - } - else - { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); - arrow->draw(to, x + moveX, y + moveY, &srcRect); - } - } - else //standard version - { - if (hvx<0 && hvy<0) - { - arrow->draw(to, x, y); - } - else if(hvx<0) - { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width(), 0, 0); - arrow->draw(to, x, y, &srcRect); - } - else if (hvy<0) - { - Rect srcRect = genRect(arrow->height(), arrow->width() - hvx, 0, 0); - arrow->draw(to, x, y, &srcRect); - } - else - { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); - arrow->draw(to, x, y, &srcRect); - } - } - CSDL_Ext::setClipRect(to, prevClip); - - } - } //for (int i=0;inodes.size()-1;i++) -} - -void CTerrainRect::show(SDL_Surface * to) -{ - if (adventureInt->mode == EAdvMapMode::NORMAL) - { - MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), pos); - info.otherheroAnim = true; - info.anim = adventureInt->anim; - info.heroAnim = adventureInt->heroAnim; - if (ADVOPT.smoothMove) - info.movement = int3(moveX, moveY, 0); - - lastRedrawStatus = CGI->mh->drawTerrainRectNew(to, &info); - if (fadeAnim->isFading()) - { - Rect r(pos); - fadeAnim->update(); - fadeAnim->draw(to, r.topLeft()); - } - - if (currentPath/* && adventureInt->position.z==currentPath->startPos().z*/) //drawing path - { - showPath(pos, to); - } - } -} - -void CTerrainRect::showAll(SDL_Surface * to) -{ - // world view map is static and doesn't need redraw every frame - if (adventureInt->mode == EAdvMapMode::WORLD_VIEW) - { - MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), pos, adventureInt->worldViewIcons); - info.scaled = true; - info.scale = adventureInt->worldViewScale; - adventureInt->worldViewOptions.adjustDrawingInfo(info); - CGI->mh->drawTerrainRectNew(to, &info); - } -} - -void CTerrainRect::showAnim(SDL_Surface * to) -{ - if (fadeAnim->isFading()) - show(to); - else if (lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED) - show(to); // currently the same; maybe we should pass some flag to map handler so it redraws ONLY tiles that need redraw instead of full -} - -int3 CTerrainRect::whichTileIsIt(const int x, const int y) -{ - int3 ret; - ret.x = adventureInt->position.x + ((x-CGI->mh->offsetX-pos.x)/32); - ret.y = adventureInt->position.y + ((y-CGI->mh->offsetY-pos.y)/32); - ret.z = adventureInt->position.z; - return ret; -} - -int3 CTerrainRect::whichTileIsIt() -{ - return whichTileIsIt(GH.getCursorPosition().x, GH.getCursorPosition().y); -} - -int3 CTerrainRect::tileCountOnScreen() -{ - switch (adventureInt->mode) - { - default: - logGlobal->error("Unknown map mode %d", (int)adventureInt->mode); - return int3(); - case EAdvMapMode::NORMAL: - return int3(tilesw, tilesh, 1); - case EAdvMapMode::WORLD_VIEW: - return int3((si32)(tilesw / adventureInt->worldViewScale), (si32)(tilesh / adventureInt->worldViewScale), 1); - } -} - -void CTerrainRect::fadeFromCurrentView() -{ - if (!ADVOPT.screenFading) - return; - if (adventureInt->mode == EAdvMapMode::WORLD_VIEW) - return; - - if (!fadeSurface) - fadeSurface = CSDL_Ext::newSurface(pos.w, pos.h); - CSDL_Ext::blitSurface(screen, fadeSurface, Point(0,0)); - fadeAnim->init(CFadeAnimation::EMode::OUT, fadeSurface); -} - -bool CTerrainRect::needsAnimUpdate() -{ - return fadeAnim->isFading() || lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED; -} - void CResDataBar::clickRight(tribool down, bool previousState) { } @@ -550,1472 +170,3 @@ void CResDataBar::showAll(SDL_Surface * to) draw(to); } -CAdvMapInt::CAdvMapInt(): - mode(EAdvMapMode::NORMAL), - worldViewScale(0.0f), //actual init later in changeMode - minimap(Rect(ADVOPT.minimapX, ADVOPT.minimapY, ADVOPT.minimapW, ADVOPT.minimapH)), - statusbar(CGStatusBar::create(ADVOPT.statusbarX,ADVOPT.statusbarY,ADVOPT.statusbarG)), - heroList(ADVOPT.hlistSize, Point(ADVOPT.hlistX, ADVOPT.hlistY), ADVOPT.hlistAU, ADVOPT.hlistAD), - townList(ADVOPT.tlistSize, Point(ADVOPT.tlistX, ADVOPT.tlistY), ADVOPT.tlistAU, ADVOPT.tlistAD), - infoBar(Rect(ADVOPT.infoboxX, ADVOPT.infoboxY, 192, 192)), state(NA), - spellBeingCasted(nullptr), position(int3(0, 0, 0)), selection(nullptr), - updateScreen(false), anim(0), animValHitCount(0), heroAnim(0), heroAnimValHitCount(0), - activeMapPanel(nullptr), duringAITurn(false), scrollingDir(0), scrollingState(false), - swipeEnabled(settings["general"]["swipe"].Bool()), swipeMovementRequested(false), - swipeTargetPosition(int3(-1, -1, -1)) -{ - pos.x = pos.y = 0; - pos.w = screen->w; - pos.h = screen->h; - strongInterest = true; // handle all mouse move events to prevent dead mouse move space in fullscreen mode - townList.onSelect = std::bind(&CAdvMapInt::selectionChanged,this); - bg = IImage::createFromFile(ADVOPT.mainGraphic); - if(!ADVOPT.worldViewGraphic.empty()) - { - bgWorldView = IImage::createFromFile(ADVOPT.worldViewGraphic); - } - else - { - bgWorldView = nullptr; - logGlobal->warn("ADVOPT.worldViewGraphic is empty => bitmap not loaded"); - } - if (!bgWorldView) - { - logGlobal->warn("bgWorldView not defined in resolution config; fallback to VWorld.bmp"); - bgWorldView = IImage::createFromFile("VWorld.bmp"); - } - - worldViewIcons = std::make_shared("VwSymbol");//todo: customize with ADVOPT - worldViewIcons->preload(); - - for(int g = 0; g < ADVOPT.gemG.size(); ++g) - { - gems.push_back(std::make_shared(ADVOPT.gemG[g], 0, 0, ADVOPT.gemX[g], ADVOPT.gemY[g])); - } - - auto makeButton = [&](int textID, std::function callback, config::ButtonInfo info, int key) -> std::shared_ptr - { - auto button = std::make_shared(Point(info.x, info.y), info.defName, CGI->generaltexth->zelp[textID], callback, key, info.playerColoured); - for(auto image : info.additionalDefs) - button->addImage(image); - return button; - }; - - kingOverview = makeButton(293, std::bind(&CAdvMapInt::fshowOverview,this), ADVOPT.kingOverview, SDLK_k); - underground = makeButton(294, std::bind(&CAdvMapInt::fswitchLevel,this), ADVOPT.underground, SDLK_u); - questlog = makeButton(295, std::bind(&CAdvMapInt::fshowQuestlog,this), ADVOPT.questlog, SDLK_q); - sleepWake = makeButton(296, std::bind(&CAdvMapInt::fsleepWake,this), ADVOPT.sleepWake, SDLK_w); - moveHero = makeButton(297, std::bind(&CAdvMapInt::fmoveHero,this), ADVOPT.moveHero, SDLK_m); - spellbook = makeButton(298, std::bind(&CAdvMapInt::fshowSpellbok,this), ADVOPT.spellbook, SDLK_c); - advOptions = makeButton(299, std::bind(&CAdvMapInt::fadventureOPtions,this), ADVOPT.advOptions, SDLK_a); - sysOptions = makeButton(300, std::bind(&CAdvMapInt::fsystemOptions,this), ADVOPT.sysOptions, SDLK_o); - nextHero = makeButton(301, std::bind(&CAdvMapInt::fnextHero,this), ADVOPT.nextHero, SDLK_h); - endTurn = makeButton(302, std::bind(&CAdvMapInt::fendTurn,this), ADVOPT.endTurn, SDLK_e); - - int panelSpaceBottom = screen->h - resdatabar.pos.h - 4; - - panelMain = std::make_shared(nullptr, Point(0, 0)); - // TODO correct drawing position - panelWorldView = std::make_shared(worldViewIcons, bgWorldView, Point(heroList.pos.x - 2, 195), panelSpaceBottom, LOCPLINT->playerID); - - panelMain->addChildColorableButton(kingOverview); - panelMain->addChildColorableButton(underground); - panelMain->addChildColorableButton(questlog); - panelMain->addChildColorableButton(sleepWake); - panelMain->addChildColorableButton(moveHero); - panelMain->addChildColorableButton(spellbook); - panelMain->addChildColorableButton(advOptions); - panelMain->addChildColorableButton(sysOptions); - panelMain->addChildColorableButton(nextHero); - panelMain->addChildColorableButton(endTurn); - - - // TODO move configs to resolutions.json, similarly to previous buttons - config::ButtonInfo worldViewBackConfig = config::ButtonInfo(); - worldViewBackConfig.defName = "IOK6432.DEF"; - worldViewBackConfig.x = screen->w - 73; - worldViewBackConfig.y = 343 + 195; - worldViewBackConfig.playerColoured = false; - panelWorldView->addChildToPanel( - makeButton(288, std::bind(&CAdvMapInt::fworldViewBack,this), worldViewBackConfig, SDLK_ESCAPE), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewPuzzleConfig = config::ButtonInfo(); - worldViewPuzzleConfig.defName = "VWPUZ.DEF"; - worldViewPuzzleConfig.x = screen->w - 188; - worldViewPuzzleConfig.y = 343 + 195; - worldViewPuzzleConfig.playerColoured = false; - panelWorldView->addChildToPanel( // no help text for this one - std::make_shared(Point(worldViewPuzzleConfig.x, worldViewPuzzleConfig.y), worldViewPuzzleConfig.defName, std::pair(), - std::bind(&CPlayerInterface::showPuzzleMap,LOCPLINT), SDLK_p, worldViewPuzzleConfig.playerColoured), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewScale1xConfig = config::ButtonInfo(); - worldViewScale1xConfig.defName = "VWMAG1.DEF"; - worldViewScale1xConfig.x = screen->w - 191; - worldViewScale1xConfig.y = 23 + 195; - worldViewScale1xConfig.playerColoured = false; - panelWorldView->addChildToPanel( // help text is wrong for this button - makeButton(291, std::bind(&CAdvMapInt::fworldViewScale1x,this), worldViewScale1xConfig, SDLK_1), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewScale2xConfig = config::ButtonInfo(); - worldViewScale2xConfig.defName = "VWMAG2.DEF"; - worldViewScale2xConfig.x = screen->w - 191 + 63; - worldViewScale2xConfig.y = 23 + 195; - worldViewScale2xConfig.playerColoured = false; - panelWorldView->addChildToPanel( // help text is wrong for this button - makeButton(291, std::bind(&CAdvMapInt::fworldViewScale2x,this), worldViewScale2xConfig, SDLK_2), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewScale4xConfig = config::ButtonInfo(); - worldViewScale4xConfig.defName = "VWMAG4.DEF"; - worldViewScale4xConfig.x = screen->w - 191 + 126; - worldViewScale4xConfig.y = 23 + 195; - worldViewScale4xConfig.playerColoured = false; - panelWorldView->addChildToPanel( // help text is wrong for this button - makeButton(291, std::bind(&CAdvMapInt::fworldViewScale4x,this), worldViewScale4xConfig, SDLK_4), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewUndergroundConfig = config::ButtonInfo(); - worldViewUndergroundConfig.defName = "IAM010.DEF"; - worldViewUndergroundConfig.additionalDefs.push_back("IAM003.DEF"); - worldViewUndergroundConfig.x = screen->w - 115; - worldViewUndergroundConfig.y = 343 + 195; - worldViewUndergroundConfig.playerColoured = true; - worldViewUnderground = makeButton(294, std::bind(&CAdvMapInt::fswitchLevel,this), worldViewUndergroundConfig, SDLK_u); - panelWorldView->addChildColorableButton(worldViewUnderground); - - setPlayer(LOCPLINT->playerID); - - int iconColorMultiplier = player.getNum() * 19; - int wvLeft = heroList.pos.x - 2; // TODO correct drawing position - //int wvTop = 195; - for (int i = 0; i < 5; ++i) - { - panelWorldView->addChildIcon(std::pair(i, Point(5, 58 + i * 20)), iconColorMultiplier); - panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 263 + i * 20, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, - Colors::WHITE, CGI->generaltexth->allTexts[612 + i])); - } - for (int i = 0; i < 7; ++i) - { - panelWorldView->addChildIcon(std::pair(i + 5, Point(5, 182 + i * 20)), iconColorMultiplier); - panelWorldView->addChildIcon(std::pair(i + 12, Point(160, 182 + i * 20)), iconColorMultiplier); - panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 387 + i * 20, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, - Colors::WHITE, CGI->generaltexth->allTexts[619 + i])); - } - panelWorldView->addChildToPanel(std::make_shared(wvLeft + 5, 367, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, - Colors::WHITE, CGI->generaltexth->allTexts[617])); - panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 367, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, - Colors::WHITE, CGI->generaltexth->allTexts[618])); - - activeMapPanel = panelMain; - - changeMode(EAdvMapMode::NORMAL); - - underground->block(!CGI->mh->map->twoLevel); - questlog->block(!CGI->mh->map->quests.size()); - worldViewUnderground->block(!CGI->mh->map->twoLevel); - - addUsedEvents(MOVE); -} - -void CAdvMapInt::fshowOverview() -{ - GH.pushIntT(); -} - -void CAdvMapInt::fworldViewBack() -{ - changeMode(EAdvMapMode::NORMAL); - CGI->mh->discardWorldViewCache(); - - auto hero = curHero(); - if (hero) - centerOn(hero); -} - -void CAdvMapInt::fworldViewScale1x() -{ - // TODO set corresponding scale button to "selected" mode - changeMode(EAdvMapMode::WORLD_VIEW, 0.22f); -} - -void CAdvMapInt::fworldViewScale2x() -{ - changeMode(EAdvMapMode::WORLD_VIEW, 0.36f); -} - -void CAdvMapInt::fworldViewScale4x() -{ - changeMode(EAdvMapMode::WORLD_VIEW, 0.5f); -} - -void CAdvMapInt::fswitchLevel() -{ - // with support for future multi-level maps :) - int maxLevels = CGI->mh->map->levels(); - if (maxLevels < 2) - return; - - position.z = (position.z + 1) % maxLevels; - - underground->setIndex(position.z, true); - underground->redraw(); - - worldViewUnderground->setIndex(position.z, true); - worldViewUnderground->redraw(); - - updateScreen = true; - minimap.setLevel(position.z); - - if (mode == EAdvMapMode::WORLD_VIEW) - terrain.redraw(); -} -void CAdvMapInt::fshowQuestlog() -{ - LOCPLINT->showQuestLog(); -} -void CAdvMapInt::fsleepWake() -{ - const CGHeroInstance *h = curHero(); - if (!h) - return; - bool newSleep = !isHeroSleeping(h); - setHeroSleeping(h, newSleep); - updateSleepWake(h); - if (newSleep) - { - fnextHero(); - - //moveHero.block(true); - //uncomment to enable original HoMM3 behaviour: - //move button is disabled for hero going to sleep, even though it's enabled when you reselect him - } -} - -void CAdvMapInt::fmoveHero() -{ - const CGHeroInstance *h = curHero(); - if (!h || !terrain.currentPath || !CGI->mh->canStartHeroMovement()) - return; - - LOCPLINT->moveHero(h, *terrain.currentPath); -} - -void CAdvMapInt::fshowSpellbok() -{ - if (!curHero()) //checking necessary values - return; - - centerOn(selection); - - GH.pushIntT(curHero(), LOCPLINT, false); -} - -void CAdvMapInt::fadventureOPtions() -{ - GH.pushIntT(); -} - -void CAdvMapInt::fsystemOptions() -{ - GH.pushIntT(); -} - -void CAdvMapInt::fnextHero() -{ - auto hero = dynamic_cast(selection); - int next = getNextHeroIndex(vstd::find_pos(LOCPLINT->wanderingHeroes, hero)); - if (next < 0) - return; - select(LOCPLINT->wanderingHeroes[next], true); -} - -void CAdvMapInt::fendTurn() -{ - if(!LOCPLINT->makingTurn) - return; - - if(settings["adventure"]["heroReminder"].Bool()) - { - for(auto hero : LOCPLINT->wanderingHeroes) - { - if(!isHeroSleeping(hero) && hero->movement > 0) - { - // Only show hero reminder if conditions met: - // - There still movement points - // - Hero don't have a path or there not points for first step on path - auto path = LOCPLINT->getAndVerifyPath(hero); - if(!path || path->nodes.size() < 2 || !path->nodes[path->nodes.size()-2].turns) - { - LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[55], std::bind(&CAdvMapInt::endingTurn, this), nullptr); - return; - } - } - } - } - endingTurn(); -} - -void CAdvMapInt::updateSleepWake(const CGHeroInstance *h) -{ - sleepWake->block(!h); - if (!h) - return; - bool state = isHeroSleeping(h); - sleepWake->setIndex(state ? 1 : 0, true); - sleepWake->assignedKeys.clear(); - sleepWake->assignedKeys.insert(state ? SDLK_w : SDLK_z); -} - -void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath) -{ - if(!h) - { - moveHero->block(true); - return; - } - //default value is for everywhere but CPlayerInterface::moveHero, because paths are not updated from there immediately - if(boost::logic::indeterminate(hasPath)) - hasPath = LOCPLINT->paths[h].nodes.size() ? true : false; - - moveHero->block(!(bool)hasPath || (h->movement == 0)); -} - -void CAdvMapInt::updateSpellbook(const CGHeroInstance *h) -{ - spellbook->block(!h); -} - -int CAdvMapInt::getNextHeroIndex(int startIndex) -{ - if (LOCPLINT->wanderingHeroes.size() == 0) - return -1; - if (startIndex < 0) - startIndex = 0; - int i = startIndex; - do - { - i++; - if (i >= LOCPLINT->wanderingHeroes.size()) - i = 0; - } - while (((LOCPLINT->wanderingHeroes[i]->movement == 0) || isHeroSleeping(LOCPLINT->wanderingHeroes[i])) && (i != startIndex)); - - if ((LOCPLINT->wanderingHeroes[i]->movement != 0) && !isHeroSleeping(LOCPLINT->wanderingHeroes[i])) - return i; - else - return -1; -} - -void CAdvMapInt::updateNextHero(const CGHeroInstance *h) -{ - int start = vstd::find_pos(LOCPLINT->wanderingHeroes, h); - int next = getNextHeroIndex(start); - if (next < 0) - { - nextHero->block(true); - return; - } - const CGHeroInstance *nextH = LOCPLINT->wanderingHeroes[next]; - bool noActiveHeroes = (next == start) && ((nextH->movement == 0) || isHeroSleeping(nextH)); - nextHero->block(noActiveHeroes); -} - -void CAdvMapInt::activate() -{ - CIntObject::activate(); - if (!(active & KEYBOARD)) - CIntObject::activate(KEYBOARD); - - screenBuf = screen; - GH.statusbar = statusbar; - - if(LOCPLINT) - { - LOCPLINT->cingconsole->activate(); - LOCPLINT->cingconsole->pos = this->pos; - } - - if(!duringAITurn) - { - activeMapPanel->activate(); - if (mode == EAdvMapMode::NORMAL) - { - heroList.activate(); - townList.activate(); - infoBar.activate(); - } - minimap.activate(); - terrain.activate(); - statusbar->activate(); - - GH.fakeMouseMove(); //to restore the cursor - } -} - -void CAdvMapInt::deactivate() -{ - CIntObject::deactivate(); - - if(!duringAITurn) - { - scrollingDir = 0; - - CCS->curh->set(Cursor::Map::POINTER); - activeMapPanel->deactivate(); - if (mode == EAdvMapMode::NORMAL) - { - heroList.deactivate(); - townList.deactivate(); - infoBar.deactivate(); - } - minimap.deactivate(); - terrain.deactivate(); - statusbar->deactivate(); - } -} - -void CAdvMapInt::showAll(SDL_Surface * to) -{ - bg->draw(to, 0, 0); - - if(state != INGAME) - return; - - switch (mode) - { - case EAdvMapMode::NORMAL: - - heroList.showAll(to); - townList.showAll(to); - infoBar.showAll(to); - break; - case EAdvMapMode::WORLD_VIEW: - - terrain.showAll(to); - break; - } - activeMapPanel->showAll(to); - - updateScreen = true; - minimap.showAll(to); - show(to); - - - resdatabar.showAll(to); - - statusbar->show(to); - - LOCPLINT->cingconsole->show(to); -} - -bool CAdvMapInt::isHeroSleeping(const CGHeroInstance *hero) -{ - if (!hero) - return false; - - return vstd::contains(LOCPLINT->sleepingHeroes, hero); -} - -void CAdvMapInt::setHeroSleeping(const CGHeroInstance *hero, bool sleep) -{ - if (sleep) - LOCPLINT->sleepingHeroes.push_back(hero); //FIXME: should we check for existence? - else - LOCPLINT->sleepingHeroes -= hero; - updateNextHero(nullptr); -} - -void CAdvMapInt::show(SDL_Surface * to) -{ - if(state != INGAME) - return; - - ++animValHitCount; //for animations - - if(animValHitCount % 2 == 0) - { - ++heroAnim; - } - if(animValHitCount >= 8) - { - CGI->mh->updateWater(); - animValHitCount = 0; - ++anim; - updateScreen = true; - } - - if(swipeEnabled) - { - handleSwipeUpdate(); - } -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) // on mobile, map-moving mode is exclusive (TODO technically it might work with both enabled; to be checked) - else -#endif - { - handleMapScrollingUpdate(); - } - - for(int i = 0; i < 4; i++) - { - if(settings["session"]["spectate"].Bool()) - gems[i]->setFrame(PlayerColor(1).getNum()); - else - gems[i]->setFrame(LOCPLINT->playerID.getNum()); - } - if(updateScreen) - { - int3 betterPos = LOCPLINT->repairScreenPos(position); - if (betterPos != position) - { - logGlobal->warn("Incorrect position for adventure map!"); - position = betterPos; - } - - terrain.show(to); - for(int i = 0; i < 4; i++) - gems[i]->showAll(to); - updateScreen=false; - LOCPLINT->cingconsole->show(to); - } - else if (terrain.needsAnimUpdate()) - { - terrain.showAnim(to); - for(int i = 0; i < 4; i++) - gems[i]->showAll(to); - } - - infoBar.show(to); - statusbar->showAll(to); -} - -void CAdvMapInt::handleMapScrollingUpdate() -{ - int scrollSpeed = static_cast(settings["adventure"]["scrollSpeed"].Float()); - //if advmap needs updating AND (no dialog is shown OR ctrl is pressed) - if((animValHitCount % (4 / scrollSpeed)) == 0 - && ((GH.topInt().get() == this) || isCtrlKeyDown())) - { - if((scrollingDir & LEFT) && (position.x > -CGI->mh->frameW)) - position.x--; - - if((scrollingDir & RIGHT) && (position.x < CGI->mh->map->width - CGI->mh->tilesW + CGI->mh->frameW)) - position.x++; - - if((scrollingDir & UP) && (position.y > -CGI->mh->frameH)) - position.y--; - - if((scrollingDir & DOWN) && (position.y < CGI->mh->map->height - CGI->mh->tilesH + CGI->mh->frameH)) - position.y++; - - if(scrollingDir) - { - setScrollingCursor(scrollingDir); - scrollingState = true; - updateScreen = true; - minimap.redraw(); - if(mode == EAdvMapMode::WORLD_VIEW) - terrain.redraw(); - } - else if(scrollingState) - { - CCS->curh->set(Cursor::Map::POINTER); - scrollingState = false; - } - } -} - -void CAdvMapInt::handleSwipeUpdate() -{ - if(swipeMovementRequested) - { - auto fixedPos = LOCPLINT->repairScreenPos(swipeTargetPosition); - position.x = fixedPos.x; - position.y = fixedPos.y; - CCS->curh->set(Cursor::Map::POINTER); - updateScreen = true; - minimap.redraw(); - swipeMovementRequested = false; - } -} - -void CAdvMapInt::selectionChanged() -{ - const CGTownInstance *to = LOCPLINT->towns[townList.getSelectedIndex()]; - if (selection != to) - select(to); -} - -void CAdvMapInt::centerOn(int3 on, bool fade) -{ - bool switchedLevels = on.z != position.z; - - if (fade) - { - terrain.fadeFromCurrentView(); - } - - switch (mode) - { - default: - case EAdvMapMode::NORMAL: - on.x -= CGI->mh->frameW; // is this intentional? frame size doesn't really have to correspond to camera size... - on.y -= CGI->mh->frameH; - break; - case EAdvMapMode::WORLD_VIEW: - on.x -= static_cast(CGI->mh->tilesW / 2 / worldViewScale); - on.y -= static_cast(CGI->mh->tilesH / 2 / worldViewScale); - break; - } - - - on = LOCPLINT->repairScreenPos(on); - - position = on; - updateScreen=true; - underground->setIndex(on.z,true); //change underground switch button image - underground->redraw(); - worldViewUnderground->setIndex(on.z, true); - worldViewUnderground->redraw(); - if (switchedLevels) - minimap.setLevel(position.z); - minimap.redraw(); - - if (mode == EAdvMapMode::WORLD_VIEW) - terrain.redraw(); -} - -void CAdvMapInt::centerOn(const CGObjectInstance * obj, bool fade) -{ - centerOn(obj->getSightCenter(), fade); -} - -void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) -{ - - if (mode == EAdvMapMode::WORLD_VIEW) - return; - - ui8 Dir = 0; - SDL_Keycode k = key.keysym.sym; - const CGHeroInstance *h = curHero(); //selected hero - const CGTownInstance *t = curTown(); //selected town - - switch(k) - { - case SDLK_g: - if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) - return; - - { - //find first town with tavern - auto itr = range::find_if(LOCPLINT->towns, [](const CGTownInstance * town) - { - return town->hasBuilt(BuildingID::TAVERN); - }); - - if(itr != LOCPLINT->towns.end()) - LOCPLINT->showThievesGuildWindow(*itr); - else - LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithTavern")); - } - return; - case SDLK_i: - if(isActive()) - CAdventureOptions::showScenarioInfo(); - return; - case SDLK_l: - if(isActive()) - LOCPLINT->proposeLoadingGame(); - return; - case SDLK_s: - if(isActive() && key.type == SDL_KEYUP) - GH.pushIntT(); - return; - case SDLK_d: - { - if(h && isActive() && LOCPLINT->makingTurn && key.state == SDL_PRESSED) - LOCPLINT->tryDiggging(h); - return; - } - case SDLK_p: - if(isActive()) - LOCPLINT->showPuzzleMap(); - return; - case SDLK_v: - if(isActive()) - LOCPLINT->viewWorldMap(); - return; - case SDLK_r: - if(isActive() && LOCPLINT->ctrlPressed()) - { - LOCPLINT->showYesNoDialog(CGI->generaltexth->translate("vcmi.adventureMap.confirmRestartGame"), - [](){ LOCPLINT->sendCustomEvent(EUserEvent::RESTART_GAME); }, nullptr); - } - return; - case SDLK_SPACE: //space - try to revisit current object with selected hero - { - if(!isActive()) - return; - if(h && key.state == SDL_PRESSED) - { - auto unlockPim = vstd::makeUnlockGuard(*CPlayerInterface::pim); - //TODO!!!!!!! possible freeze, when GS mutex is locked and network thread can't apply package - //this thread leaves scope and tries to lock pim while holding gs, - //network thread tries to lock gs (appluy cl) while holding pim - //this thread should first lock pim, however gs locking/unlocking is done inside cb - LOCPLINT->cb->moveHero(h,h->pos); - } - } - return; - case SDLK_RETURN: - { - if(!isActive() || !selection || key.state != SDL_PRESSED) - return; - if(h) - LOCPLINT->openHeroWindow(h); - else if(t) - LOCPLINT->openTownWindow(t); - return; - } - case SDLK_ESCAPE: - { - if(isActive() || GH.topInt().get() != this || !spellBeingCasted || key.state != SDL_PRESSED) - return; - - leaveCastingMode(); - return; - } - case SDLK_t: - { - //act on key down if marketplace windows is not already opened - if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) - return; - - if(LOCPLINT->ctrlPressed()) //CTRL + T => open marketplace - { - //check if we have any marketplace - const CGTownInstance *townWithMarket = nullptr; - for(const CGTownInstance *t : LOCPLINT->cb->getTownsInfo()) - { - if(t->hasBuilt(BuildingID::MARKETPLACE)) - { - townWithMarket = t; - break; - } - } - - if(townWithMarket) //if any town has marketplace, open window - GH.pushIntT(townWithMarket); - else //if not - complain - LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithMarket")); - } - else if(isActive()) //no ctrl, advmapint is on the top => switch to town - { - townList.selectNext(); - } - return; - } - default: - { - static const int3 directions[] = { int3(-1, +1, 0), int3(0, +1, 0), int3(+1, +1, 0), - int3(-1, 0, 0), int3(0, 0, 0), int3(+1, 0, 0), - int3(-1, -1, 0), int3(0, -1, 0), int3(+1, -1, 0) }; - - //numpad arrow - if(CGuiHandler::isArrowKey(k)) - k = CGuiHandler::arrowToNum(k); - - k -= SDLK_KP_1; - - if(k < 0 || k > 8) - return; - - if (!CGI->mh->canStartHeroMovement()) - return; - - int3 dir = directions[k]; - - if(!isActive() || LOCPLINT->ctrlPressed())//ctrl makes arrow move screen, not hero - { - Dir = (dir.x<0 ? LEFT : 0) | - (dir.x>0 ? RIGHT : 0) | - (dir.y<0 ? UP : 0) | - (dir.y>0 ? DOWN : 0) ; - break; - } - - if(!h || key.state != SDL_PRESSED) - break; - - if(k == 4) - { - centerOn(h); - return; - } - - CGPath &path = LOCPLINT->paths[h]; - terrain.currentPath = &path; - int3 dst = h->visitablePos() + dir; - if(dst != verifyPos(dst) || !LOCPLINT->cb->getPathsInfo(h)->getPath(path, dst)) - { - terrain.currentPath = nullptr; - return; - } - - if (path.nodes.size() > 2) - updateMoveHero(h); - else - if(!path.nodes[0].turns) - LOCPLINT->moveHero(h, path); - } - - return; - } - if(Dir && key.state == SDL_PRESSED //arrow is pressed - && LOCPLINT->ctrlPressed() - ) - scrollingDir |= Dir; - else - scrollingDir &= ~Dir; -} -void CAdvMapInt::handleRightClick(std::string text, tribool down) -{ - if(down) - { - CRClickPopup::createAndPush(text); - } -} -int3 CAdvMapInt::verifyPos(int3 ver) -{ - if (ver.x<0) - ver.x=0; - if (ver.y<0) - ver.y=0; - if (ver.z<0) - ver.z=0; - if (ver.x>=CGI->mh->sizes.x) - ver.x=CGI->mh->sizes.x-1; - if (ver.y>=CGI->mh->sizes.y) - ver.y=CGI->mh->sizes.y-1; - if (ver.z>=CGI->mh->sizes.z) - ver.z=CGI->mh->sizes.z-1; - return ver; -} - -void CAdvMapInt::select(const CArmedInstance *sel, bool centerView) -{ - assert(sel); - LOCPLINT->setSelection(sel); - selection = sel; - if (LOCPLINT->battleInt == nullptr && LOCPLINT->makingTurn) - { - auto pos = sel->visitablePos(); - auto tile = LOCPLINT->cb->getTile(pos); - if(tile) - CCS->musich->playMusicFromSet("terrain", tile->terType->getJsonKey(), true, false); - } - if(centerView) - centerOn(sel); - - terrain.currentPath = nullptr; - if(sel->ID==Obj::TOWN) - { - auto town = dynamic_cast(sel); - - infoBar.showTownSelection(town); - townList.select(town); - heroList.select(nullptr); - - updateSleepWake(nullptr); - updateMoveHero(nullptr); - updateSpellbook(nullptr); - } - else //hero selected - { - auto hero = dynamic_cast(sel); - - infoBar.showHeroSelection(hero); - heroList.select(hero); - townList.select(nullptr); - - terrain.currentPath = LOCPLINT->getAndVerifyPath(hero); - - updateSleepWake(hero); - updateMoveHero(hero); - updateSpellbook(hero); - } - townList.redraw(); - heroList.redraw(); -} - -void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent ) -{ -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - if(swipeEnabled) - return; -#endif - // adventure map scrolling with mouse - // currently disabled in world view mode (as it is in OH3), but should work correctly if mode check is removed - // don't scroll if there is no window in focus - these events don't seem to correspond to the actual mouse movement - if(!isCtrlKeyDown() && isActive() && sEvent.windowID != 0 && mode == EAdvMapMode::NORMAL) - { - if(sEvent.x<15) - { - scrollingDir |= LEFT; - } - else - { - scrollingDir &= ~LEFT; - } - if(sEvent.x>screen->w-15) - { - scrollingDir |= RIGHT; - } - else - { - scrollingDir &= ~RIGHT; - } - if(sEvent.y<15) - { - scrollingDir |= UP; - } - else - { - scrollingDir &= ~UP; - } - if(sEvent.y>screen->h-15) - { - scrollingDir |= DOWN; - } - else - { - scrollingDir &= ~DOWN; - } - } -} - -bool CAdvMapInt::isActive() -{ - return active & ~CIntObject::KEYBOARD; -} - -void CAdvMapInt::startHotSeatWait(PlayerColor Player) -{ - state = WAITING; -} - -void CAdvMapInt::setPlayer(PlayerColor Player) -{ - player = Player; - bg->playerColored(player); - - panelMain->setPlayerColor(player); - panelWorldView->setPlayerColor(player); - panelWorldView->recolorIcons(player, player.getNum() * 19); - resdatabar.background->colorize(player); -} - -void CAdvMapInt::startTurn() -{ - state = INGAME; - if(LOCPLINT->cb->getCurrentPlayer() == LOCPLINT->playerID - || settings["session"]["spectate"].Bool()) - { - adjustActiveness(false); - minimap.setAIRadar(false); - } -} - -void CAdvMapInt::endingTurn() -{ - if(settings["session"]["spectate"].Bool()) - return; - - LOCPLINT->makingTurn = false; - LOCPLINT->cb->endTurn(); - CCS->soundh->ambientStopAllChannels(); -} - -const CGObjectInstance* CAdvMapInt::getActiveObject(const int3 &mapPos) -{ - std::vector < const CGObjectInstance * > bobjs = LOCPLINT->cb->getBlockingObjs(mapPos); //blocking objects at tile - - if (bobjs.empty()) - return nullptr; - - return *boost::range::max_element(bobjs, &CMapHandler::compareObjectBlitOrder); -/* - if (bobjs.back()->ID == Obj::HERO) - return bobjs.back(); - else - return bobjs.front();*/ -} - -void CAdvMapInt::tileLClicked(const int3 &mapPos) -{ - if(mode != EAdvMapMode::NORMAL) - return; - if(!LOCPLINT->cb->isVisible(mapPos) || !LOCPLINT->makingTurn) - return; - - const TerrainTile *tile = LOCPLINT->cb->getTile(mapPos); - - const CGObjectInstance *topBlocking = getActiveObject(mapPos); - - int3 selPos = selection->getSightCenter(); - if(spellBeingCasted && isInScreenRange(selPos, mapPos)) - { - const TerrainTile *heroTile = LOCPLINT->cb->getTile(selPos); - - switch(spellBeingCasted->id) - { - case SpellID::SCUTTLE_BOAT: //Scuttle Boat - if(topBlocking && topBlocking->ID == Obj::BOAT) - leaveCastingMode(true, mapPos); - break; - case SpellID::DIMENSION_DOOR: - if(!tile || tile->isClear(heroTile)) - leaveCastingMode(true, mapPos); - break; - } - return; - } - //check if we can select this object - bool canSelect = topBlocking && topBlocking->ID == Obj::HERO && topBlocking->tempOwner == LOCPLINT->playerID; - canSelect |= topBlocking && topBlocking->ID == Obj::TOWN && LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, topBlocking->tempOwner); - - bool isHero = false; - if(selection->ID != Obj::HERO) //hero is not selected (presumably town) - { - assert(!terrain.currentPath); //path can be active only when hero is selected - if(selection == topBlocking) //selected town clicked - LOCPLINT->openTownWindow(static_cast(topBlocking)); - else if(canSelect) - select(static_cast(topBlocking), false); - } - else if(const CGHeroInstance * currentHero = curHero()) //hero is selected - { - isHero = true; - - const CGPathNode *pn = LOCPLINT->cb->getPathsInfo(currentHero)->getPathInfo(mapPos); - if(currentHero == topBlocking) //clicked selected hero - { - LOCPLINT->openHeroWindow(currentHero); - return; - } - else if(canSelect && pn->turns == 255 ) //selectable object at inaccessible tile - { - select(static_cast(topBlocking), false); - return; - } - else //still here? we need to move hero if we clicked end of already selected path or calculate a new path otherwise - { - if(terrain.currentPath && terrain.currentPath->endPos() == mapPos)//we'll be moving - { - if(CGI->mh->canStartHeroMovement()) - LOCPLINT->moveHero(currentHero, *terrain.currentPath); - return; - } - else //remove old path and find a new one if we clicked on accessible tile - { - CGPath &path = LOCPLINT->paths[currentHero]; - CGPath newpath; - bool gotPath = LOCPLINT->cb->getPathsInfo(currentHero)->getPath(newpath, mapPos); //try getting path, erase if failed - if(gotPath && newpath.nodes.size()) - path = newpath; - - if(path.nodes.size()) - terrain.currentPath = &path; - else - LOCPLINT->eraseCurrentPathOf(currentHero); - - updateMoveHero(currentHero); - } - } - } //end of hero is selected "case" - else - { - throw std::runtime_error("Nothing is selected..."); - } - - const auto shipyard = ourInaccessibleShipyard(topBlocking); - if(isHero && shipyard != nullptr) - { - LOCPLINT->showShipyardDialogOrProblemPopup(shipyard); - } -} - -void CAdvMapInt::tileHovered(const int3 &mapPos) -{ - if(mode != EAdvMapMode::NORMAL //disable in world view - || !selection) //may occur just at the start of game (fake move before full intiialization) - return; - if(!LOCPLINT->cb->isVisible(mapPos)) - { - CCS->curh->set(Cursor::Map::POINTER); - statusbar->clear(); - return; - } - auto objRelations = PlayerRelations::ALLIES; - const CGObjectInstance *objAtTile = getActiveObject(mapPos); - if(objAtTile) - { - objRelations = LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, objAtTile->tempOwner); - std::string text = curHero() ? objAtTile->getHoverText(curHero()) : objAtTile->getHoverText(LOCPLINT->playerID); - boost::replace_all(text,"\n"," "); - statusbar->write(text); - } - else - { - std::string hlp; - CGI->mh->getTerrainDescr(mapPos, hlp, false); - statusbar->write(hlp); - } - - if(spellBeingCasted) - { - switch(spellBeingCasted->id) - { - case SpellID::SCUTTLE_BOAT: - if(objAtTile && objAtTile->ID == Obj::BOAT) - CCS->curh->set(Cursor::Map::SCUTTLE_BOAT); - else - CCS->curh->set(Cursor::Map::POINTER); - return; - case SpellID::DIMENSION_DOOR: - { - const TerrainTile * t = LOCPLINT->cb->getTile(mapPos, false); - int3 hpos = selection->getSightCenter(); - if((!t || t->isClear(LOCPLINT->cb->getTile(hpos))) && isInScreenRange(hpos, mapPos)) - CCS->curh->set(Cursor::Map::TELEPORT); - else - CCS->curh->set(Cursor::Map::POINTER); - return; - } - } - } - - if(selection->ID == Obj::TOWN) - { - if(objAtTile) - { - if(objAtTile->ID == Obj::TOWN && objRelations != PlayerRelations::ENEMIES) - CCS->curh->set(Cursor::Map::TOWN); - else if(objAtTile->ID == Obj::HERO && objRelations == PlayerRelations::SAME_PLAYER) - CCS->curh->set(Cursor::Map::HERO); - else - CCS->curh->set(Cursor::Map::POINTER); - } - else - CCS->curh->set(Cursor::Map::POINTER); - } - else if(const CGHeroInstance * hero = curHero()) - { - std::array cursorMove = { Cursor::Map::T1_MOVE, Cursor::Map::T2_MOVE, Cursor::Map::T3_MOVE, Cursor::Map::T4_MOVE, }; - std::array cursorAttack = { Cursor::Map::T1_ATTACK, Cursor::Map::T2_ATTACK, Cursor::Map::T3_ATTACK, Cursor::Map::T4_ATTACK, }; - std::array cursorSail = { Cursor::Map::T1_SAIL, Cursor::Map::T2_SAIL, Cursor::Map::T3_SAIL, Cursor::Map::T4_SAIL, }; - std::array cursorDisembark = { Cursor::Map::T1_DISEMBARK, Cursor::Map::T2_DISEMBARK, Cursor::Map::T3_DISEMBARK, Cursor::Map::T4_DISEMBARK, }; - std::array cursorExchange = { Cursor::Map::T1_EXCHANGE, Cursor::Map::T2_EXCHANGE, Cursor::Map::T3_EXCHANGE, Cursor::Map::T4_EXCHANGE, }; - std::array cursorVisit = { Cursor::Map::T1_VISIT, Cursor::Map::T2_VISIT, Cursor::Map::T3_VISIT, Cursor::Map::T4_VISIT, }; - std::array cursorSailVisit = { Cursor::Map::T1_SAIL_VISIT, Cursor::Map::T2_SAIL_VISIT, Cursor::Map::T3_SAIL_VISIT, Cursor::Map::T4_SAIL_VISIT, }; - - const CGPathNode * pathNode = LOCPLINT->cb->getPathsInfo(hero)->getPathInfo(mapPos); - assert(pathNode); - - if(LOCPLINT->altPressed() && pathNode->reachable()) //overwrite status bar text with movement info - { - ShowMoveDetailsInStatusbar(*hero, *pathNode); - } - - int turns = pathNode->turns; - vstd::amin(turns, 3); - switch(pathNode->action) - { - case CGPathNode::NORMAL: - case CGPathNode::TELEPORT_NORMAL: - if(pathNode->layer == EPathfindingLayer::LAND) - CCS->curh->set(cursorMove[turns]); - else - CCS->curh->set(cursorSailVisit[turns]); - break; - - case CGPathNode::VISIT: - case CGPathNode::BLOCKING_VISIT: - case CGPathNode::TELEPORT_BLOCKING_VISIT: - if(objAtTile && objAtTile->ID == Obj::HERO) - { - if(selection == objAtTile) - CCS->curh->set(Cursor::Map::HERO); - else - CCS->curh->set(cursorExchange[turns]); - } - else if(pathNode->layer == EPathfindingLayer::LAND) - CCS->curh->set(cursorVisit[turns]); - else - CCS->curh->set(cursorSailVisit[turns]); - break; - - case CGPathNode::BATTLE: - case CGPathNode::TELEPORT_BATTLE: - CCS->curh->set(cursorAttack[turns]); - break; - - case CGPathNode::EMBARK: - CCS->curh->set(cursorSail[turns]); - break; - - case CGPathNode::DISEMBARK: - CCS->curh->set(cursorDisembark[turns]); - break; - - default: - if(objAtTile && objRelations != PlayerRelations::ENEMIES) - { - if(objAtTile->ID == Obj::TOWN) - CCS->curh->set(Cursor::Map::TOWN); - else if(objAtTile->ID == Obj::HERO && objRelations == PlayerRelations::SAME_PLAYER) - CCS->curh->set(Cursor::Map::HERO); - else - CCS->curh->set(Cursor::Map::POINTER); - } - else - CCS->curh->set(Cursor::Map::POINTER); - break; - } - } - - if(ourInaccessibleShipyard(objAtTile)) - { - CCS->curh->set(Cursor::Map::T1_SAIL); - } -} - -void CAdvMapInt::ShowMoveDetailsInStatusbar(const CGHeroInstance & hero, const CGPathNode & pathNode) -{ - const int maxMovementPointsAtStartOfLastTurn = pathNode.turns > 0 ? hero.maxMovePoints(pathNode.layer == EPathfindingLayer::LAND) : hero.movement; - const int movementPointsLastTurnCost = maxMovementPointsAtStartOfLastTurn - pathNode.moveRemains; - const int remainingPointsAfterMove = pathNode.turns == 0 ? pathNode.moveRemains : 0; - - std::string result = VLC->generaltexth->translate("vcmi.adventureMap", pathNode.turns > 0 ? "moveCostDetails" : "moveCostDetailsNoTurns"); - - boost::replace_first(result, "%TURNS", std::to_string(pathNode.turns)); - boost::replace_first(result, "%POINTS", std::to_string(movementPointsLastTurnCost)); - boost::replace_first(result, "%REMAINING", std::to_string(remainingPointsAfterMove)); - - statusbar->write(result); -} - -void CAdvMapInt::tileRClicked(const int3 &mapPos) -{ - if(mode != EAdvMapMode::NORMAL) - return; - if(spellBeingCasted) - { - leaveCastingMode(); - return; - } - if(!LOCPLINT->cb->isVisible(mapPos)) - { - CRClickPopup::createAndPush(VLC->generaltexth->allTexts[61]); //Uncharted Territory - return; - } - - const CGObjectInstance * obj = getActiveObject(mapPos); - if(!obj) - { - // Bare or undiscovered terrain - const TerrainTile * tile = LOCPLINT->cb->getTile(mapPos); - if (tile) - { - std::string hlp; - CGI->mh->getTerrainDescr(mapPos, hlp, true); - CRClickPopup::createAndPush(hlp); - } - return; - } - - CRClickPopup::createAndPush(obj, GH.getCursorPosition(), ETextAlignment::CENTER); -} - -void CAdvMapInt::enterCastingMode(const CSpell * sp) -{ - assert(sp->id == SpellID::SCUTTLE_BOAT || sp->id == SpellID::DIMENSION_DOOR); - spellBeingCasted = sp; - - deactivate(); - terrain.activate(); - GH.fakeMouseMove(); -} - -void CAdvMapInt::leaveCastingMode(bool cast, int3 dest) -{ - assert(spellBeingCasted); - SpellID id = spellBeingCasted->id; - spellBeingCasted = nullptr; - terrain.deactivate(); - activate(); - - if(cast) - LOCPLINT->cb->castSpell(curHero(), id, dest); - else - LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[731]); //Spell cancelled -} - -const CGHeroInstance * CAdvMapInt::curHero() const -{ - if(selection && selection->ID == Obj::HERO) - return static_cast(selection); - else - return nullptr; -} - -const CGTownInstance * CAdvMapInt::curTown() const -{ - if(selection && selection->ID == Obj::TOWN) - return static_cast(selection); - else - return nullptr; -} - -const IShipyard * CAdvMapInt::ourInaccessibleShipyard(const CGObjectInstance *obj) const -{ - const IShipyard *ret = IShipyard::castFrom(obj); - - if(!ret || - obj->tempOwner != player || - (CCS->curh->get() != Cursor::Map::T1_SAIL && CCS->curh->get() != Cursor::Map::POINTER)) - return nullptr; - - return ret; -} - -void CAdvMapInt::aiTurnStarted() -{ - if(settings["session"]["spectate"].Bool()) - return; - - adjustActiveness(true); - CCS->musich->playMusicFromSet("enemy-turn", true, false); - adventureInt->minimap.setAIRadar(true); - adventureInt->infoBar.startEnemyTurn(LOCPLINT->cb->getCurrentPlayer()); - adventureInt->infoBar.showAll(screen);//force refresh on inactive object -} - -void CAdvMapInt::adjustActiveness(bool aiTurnStart) -{ - bool wasActive = isActive(); - - if(wasActive) - deactivate(); - adventureInt->duringAITurn = aiTurnStart; - if(wasActive) - activate(); -} - -void CAdvMapInt::quickCombatLock() -{ - if(!duringAITurn) - deactivate(); -} - -void CAdvMapInt::quickCombatUnlock() -{ - if(!duringAITurn) - activate(); -} - -void CAdvMapInt::changeMode(EAdvMapMode newMode, float newScale) -{ - if (mode != newMode) - { - mode = newMode; - - switch (mode) - { - case EAdvMapMode::NORMAL: - panelMain->activate(); - panelWorldView->deactivate(); - activeMapPanel = panelMain; - - townList.activate(); - heroList.activate(); - infoBar.activate(); - - worldViewOptions.clear(); - - break; - case EAdvMapMode::WORLD_VIEW: - panelMain->deactivate(); - panelWorldView->activate(); - - activeMapPanel = panelWorldView; - - townList.deactivate(); - heroList.deactivate(); - infoBar.showSelection(); // to prevent new day animation interfering world view mode - infoBar.deactivate(); - - break; - } - worldViewScale = newScale; - redraw(); - } - else if (worldViewScale != newScale) // still in world view mode, but the scale changed - { - worldViewScale = newScale; - redraw(); - } -} - -CAdventureOptions::CAdventureOptions() - : CWindowObject(PLAYER_COLORED, "ADVOPTS") -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - - viewWorld = std::make_shared(Point(24, 23), "ADVVIEW.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_v); - viewWorld->addCallback(std::bind(&CPlayerInterface::viewWorldMap, LOCPLINT)); - - exit = std::make_shared(Point(204, 313), "IOK6432.DEF", CButton::tooltip(), std::bind(&CAdventureOptions::close, this), SDLK_RETURN); - exit->assignedKeys.insert(SDLK_ESCAPE); - - scenInfo = std::make_shared(Point(24, 198), "ADVINFO.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_i); - scenInfo->addCallback(CAdventureOptions::showScenarioInfo); - - puzzle = std::make_shared(Point(24, 81), "ADVPUZ.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_p); - puzzle->addCallback(std::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT)); - - dig = std::make_shared(Point(24, 139), "ADVDIG.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_d); - if(const CGHeroInstance *h = adventureInt->curHero()) - dig->addCallback(std::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h)); - else - dig->block(true); -} - -void CAdventureOptions::showScenarioInfo() -{ - if(LOCPLINT->cb->getStartInfo()->campState) - { - GH.pushIntT(); - } - else - { - GH.pushIntT(); - } -} - -CAdvMapInt::WorldViewOptions::WorldViewOptions() -{ - clear(); -} - -void CAdvMapInt::WorldViewOptions::clear() -{ - showAllTerrain = false; - - iconPositions.clear(); -} - -void CAdvMapInt::WorldViewOptions::adjustDrawingInfo(MapDrawingInfo& info) -{ - info.showAllTerrain = showAllTerrain; - - info.additionalIcons = &iconPositions; -} diff --git a/client/adventureMap/CResDataBar.h b/client/adventureMap/CResDataBar.h index 6b1ae0ddc..f1e871383 100644 --- a/client/adventureMap/CResDataBar.h +++ b/client/adventureMap/CResDataBar.h @@ -36,72 +36,6 @@ class CFadeAnimation; struct MapDrawingInfo; -/*****************************/ - -enum class EAdvMapMode -{ - NORMAL, - WORLD_VIEW -}; - -/// Adventure options dialog where you can view the world, dig, play the replay of the last turn,... -class CAdventureOptions : public CWindowObject -{ -public: - std::shared_ptr exit; - std::shared_ptr viewWorld; - std::shared_ptr puzzle; - std::shared_ptr dig; - std::shared_ptr scenInfo; - /*std::shared_ptr replay*/ - - CAdventureOptions(); - static void showScenarioInfo(); -}; - -/// Holds information about which tiles of the terrain are shown/not shown at the screen -class CTerrainRect : public CIntObject -{ - SDL_Surface * fadeSurface; - EMapAnimRedrawStatus lastRedrawStatus; - std::shared_ptr fadeAnim; - - int3 swipeInitialMapPos; - int3 swipeInitialRealPos; - bool isSwiping; - static constexpr float SwipeTouchSlop = 16.0f; - - void handleHover(const SDL_MouseMotionEvent & sEvent); - void handleSwipeMove(const SDL_MouseMotionEvent & sEvent); - /// handles start/finish of swipe (press/release of corresponding button); returns true if state change was handled - bool handleSwipeStateChange(bool btnPressed); -public: - int tilesw, tilesh; //width and height of terrain to blit in tiles - int3 curHoveredTile; - int moveX, moveY; //shift between actual position of screen and the one we wil blit; ranges from -31 to 31 (in pixels) - CGPath * currentPath; - - CTerrainRect(); - virtual ~CTerrainRect(); - void deactivate() override; - void clickLeft(tribool down, bool previousState) override; - void clickRight(tribool down, bool previousState) override; - void clickMiddle(tribool down, bool previousState) override; - void hover(bool on) override; - void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; - void show(SDL_Surface * to) override; - void showAll(SDL_Surface * to) override; - void showAnim(SDL_Surface * to); - void showPath(const Rect &extRect, SDL_Surface * to); - int3 whichTileIsIt(const int x, const int y); //x,y are cursor position - int3 whichTileIsIt(); //uses current cursor pos - /// @returns number of visible tiles on screen respecting current map scaling - int3 tileCountOnScreen(); - /// animates view by caching current surface and crossfading it with normal screen - void fadeFromCurrentView(); - bool needsAnimUpdate(); -}; - /// Resources bar which shows information about how many gold, crystals,... you have /// Current date is displayed too class CResDataBar : public CIntObject @@ -122,155 +56,3 @@ public: void showAll(SDL_Surface * to) override; }; -/// That's a huge class which handles general adventure map actions and -/// shows the right menu(questlog, spellbook, end turn,..) from where you -/// can get to the towns and heroes. -class CAdvMapInt : public CIntObject -{ - //Return object that must be active at this tile (=clickable) - const CGObjectInstance *getActiveObject(const int3 &tile); - -public: - CAdvMapInt(); - - int3 position; //top left corner of visible map part - PlayerColor player; - - bool duringAITurn; - - enum{LEFT=1, RIGHT=2, UP=4, DOWN=8}; - ui8 scrollingDir; //uses enum: LEFT RIGHT, UP, DOWN - bool scrollingState; - bool swipeEnabled; - bool swipeMovementRequested; - int3 swipeTargetPosition; - - enum{NA, INGAME, WAITING} state; - - bool updateScreen; - ui8 anim, animValHitCount; //animation frame - ui8 heroAnim, heroAnimValHitCount; //animation frame - - EAdvMapMode mode; - float worldViewScale; - - struct WorldViewOptions - { - bool showAllTerrain; //for expert viewEarth - - std::vector iconPositions; - - WorldViewOptions(); - - void clear(); - - void adjustDrawingInfo(MapDrawingInfo & info); - }; - - WorldViewOptions worldViewOptions; - - std::shared_ptr bg; - std::shared_ptr bgWorldView; - std::vector> gems; - CMinimap minimap; - std::shared_ptr statusbar; - - std::shared_ptr kingOverview; - std::shared_ptr underground; - std::shared_ptr questlog; - std::shared_ptr sleepWake; - std::shared_ptr moveHero; - std::shared_ptr spellbook; - std::shared_ptr advOptions; - std::shared_ptr sysOptions; - std::shared_ptr nextHero; - std::shared_ptr endTurn; - - std::shared_ptr worldViewUnderground; - - CTerrainRect terrain; //visible terrain - CResDataBar resdatabar; - CHeroList heroList; - CTownList townList; - CInfoBar infoBar; - - std::shared_ptr panelMain; // panel that holds all right-side buttons in normal view - std::shared_ptr panelWorldView; // panel that holds all buttons and other ui in world view - std::shared_ptr activeMapPanel; // currently active panel (either main or world view, depending on current mode) - - std::shared_ptr worldViewIcons;// images for world view overlay - - const CSpell *spellBeingCasted; //nullptr if none - - const CArmedInstance *selection; //currently selected town/hero - - //functions bound to buttons - void fshowOverview(); - void fworldViewBack(); - void fworldViewScale1x(); - void fworldViewScale2x(); - void fworldViewScale4x(); - void fswitchLevel(); - void fshowQuestlog(); - void fsleepWake(); - void fmoveHero(); - void fshowSpellbok(); - void fadventureOPtions(); - void fsystemOptions(); - void fnextHero(); - void fendTurn(); - - void activate() override; - void deactivate() override; - - void show(SDL_Surface * to) override; //redraws terrain - void showAll(SDL_Surface * to) override; //shows and activates adv. map interface - - void select(const CArmedInstance *sel, bool centerView = true); - void selectionChanged(); - void centerOn(int3 on, bool fade = false); - void centerOn(const CGObjectInstance *obj, bool fade = false); - int3 verifyPos(int3 ver); - void handleRightClick(std::string text, tribool down); - void keyPressed(const SDL_KeyboardEvent & key) override; - void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; - bool isActive(); - - bool isHeroSleeping(const CGHeroInstance *hero); - void setHeroSleeping(const CGHeroInstance *hero, bool sleep); - int getNextHeroIndex(int startIndex); //for Next Hero button - cycles awake heroes with movement only - - void setPlayer(PlayerColor Player); - void startHotSeatWait(PlayerColor Player); - void startTurn(); - void endingTurn(); - void aiTurnStarted(); - - void adjustActiveness(bool aiTurnStart); //should be called every time at AI/human turn transition; blocks GUI during AI turn - void quickCombatLock(); //should be called when quick battle started - void quickCombatUnlock(); - void tileLClicked(const int3 &mapPos); - void tileHovered(const int3 &mapPos); - void tileRClicked(const int3 &mapPos); - void enterCastingMode(const CSpell * sp); - void leaveCastingMode(bool cast = false, int3 dest = int3(-1, -1, -1)); - const CGHeroInstance * curHero() const; - const CGTownInstance * curTown() const; - const IShipyard * ourInaccessibleShipyard(const CGObjectInstance *obj) const; //checks if obj is our ashipyard and cursor is 0,0 -> returns shipyard or nullptr else - //button updates - void updateSleepWake(const CGHeroInstance *h); - void updateMoveHero(const CGHeroInstance *h, tribool hasPath = boost::logic::indeterminate); - void updateSpellbook(const CGHeroInstance *h); - void updateNextHero(const CGHeroInstance *h); - - /// changes current adventure map mode; used to switch between default view and world view; scale is ignored if EAdvMapMode == NORMAL - void changeMode(EAdvMapMode newMode, float newScale = 0.36f); - - void handleMapScrollingUpdate(); - void handleSwipeUpdate(); - -private: - void ShowMoveDetailsInStatusbar(const CGHeroInstance & hero, const CGPathNode & pathNode); -}; - -extern std::shared_ptr adventureInt; diff --git a/client/adventureMap/CTerrainRect.cpp b/client/adventureMap/CTerrainRect.cpp index d0529f744..8fde76286 100644 --- a/client/adventureMap/CTerrainRect.cpp +++ b/client/adventureMap/CTerrainRect.cpp @@ -469,1553 +469,3 @@ bool CTerrainRect::needsAnimUpdate() return fadeAnim->isFading() || lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED; } -void CResDataBar::clickRight(tribool down, bool previousState) -{ -} - -CResDataBar::CResDataBar(const std::string & defname, int x, int y, int offx, int offy, int resdist, int datedist) -{ - pos.x += x; - pos.y += y; - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared(defname, 0, 0); - background->colorize(LOCPLINT->playerID); - - pos.w = background->pos.w; - pos.h = background->pos.h; - - txtpos.resize(8); - for (int i = 0; i < 8 ; i++) - { - txtpos[i].first = pos.x + offx + resdist*i; - txtpos[i].second = pos.y + offy; - } - txtpos[7].first = txtpos[6].first + datedist; - datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] - + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s"; - addUsedEvents(RCLICK); -} - -CResDataBar::CResDataBar() -{ - pos.x += ADVOPT.resdatabarX; - pos.y += ADVOPT.resdatabarY; - - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - background = std::make_shared(ADVOPT.resdatabarG, 0, 0); - background->colorize(LOCPLINT->playerID); - - pos.w = background->pos.w; - pos.h = background->pos.h; - - txtpos.resize(8); - for (int i = 0; i < 8 ; i++) - { - txtpos[i].first = pos.x + ADVOPT.resOffsetX + ADVOPT.resDist*i; - txtpos[i].second = pos.y + ADVOPT.resOffsetY; - } - txtpos[7].first = txtpos[6].first + ADVOPT.resDateDist; - datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63] - + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s"; -} - -CResDataBar::~CResDataBar() = default; - -void CResDataBar::draw(SDL_Surface * to) -{ - //TODO: all this should be labels, but they require proper text update on change - for (auto i=Res::WOOD; i<=Res::GOLD; vstd::advance(i, 1)) - { - std::string text = boost::lexical_cast(LOCPLINT->cb->getResourceAmount(i)); - - graphics->fonts[FONT_SMALL]->renderTextLeft(to, text, Colors::WHITE, Point(txtpos[i].first,txtpos[i].second)); - } - std::vector temp; - - temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::MONTH))); - temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::WEEK))); - temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK))); - - graphics->fonts[FONT_SMALL]->renderTextLeft(to, processStr(datetext,temp), Colors::WHITE, Point(txtpos[7].first,txtpos[7].second)); -} - -void CResDataBar::show(SDL_Surface * to) -{ - -} - -void CResDataBar::showAll(SDL_Surface * to) -{ - CIntObject::showAll(to); - draw(to); -} - -CAdvMapInt::CAdvMapInt(): - mode(EAdvMapMode::NORMAL), - worldViewScale(0.0f), //actual init later in changeMode - minimap(Rect(ADVOPT.minimapX, ADVOPT.minimapY, ADVOPT.minimapW, ADVOPT.minimapH)), - statusbar(CGStatusBar::create(ADVOPT.statusbarX,ADVOPT.statusbarY,ADVOPT.statusbarG)), - heroList(ADVOPT.hlistSize, Point(ADVOPT.hlistX, ADVOPT.hlistY), ADVOPT.hlistAU, ADVOPT.hlistAD), - townList(ADVOPT.tlistSize, Point(ADVOPT.tlistX, ADVOPT.tlistY), ADVOPT.tlistAU, ADVOPT.tlistAD), - infoBar(Rect(ADVOPT.infoboxX, ADVOPT.infoboxY, 192, 192)), state(NA), - spellBeingCasted(nullptr), position(int3(0, 0, 0)), selection(nullptr), - updateScreen(false), anim(0), animValHitCount(0), heroAnim(0), heroAnimValHitCount(0), - activeMapPanel(nullptr), duringAITurn(false), scrollingDir(0), scrollingState(false), - swipeEnabled(settings["general"]["swipe"].Bool()), swipeMovementRequested(false), - swipeTargetPosition(int3(-1, -1, -1)) -{ - pos.x = pos.y = 0; - pos.w = screen->w; - pos.h = screen->h; - strongInterest = true; // handle all mouse move events to prevent dead mouse move space in fullscreen mode - townList.onSelect = std::bind(&CAdvMapInt::selectionChanged,this); - bg = IImage::createFromFile(ADVOPT.mainGraphic); - if(!ADVOPT.worldViewGraphic.empty()) - { - bgWorldView = IImage::createFromFile(ADVOPT.worldViewGraphic); - } - else - { - bgWorldView = nullptr; - logGlobal->warn("ADVOPT.worldViewGraphic is empty => bitmap not loaded"); - } - if (!bgWorldView) - { - logGlobal->warn("bgWorldView not defined in resolution config; fallback to VWorld.bmp"); - bgWorldView = IImage::createFromFile("VWorld.bmp"); - } - - worldViewIcons = std::make_shared("VwSymbol");//todo: customize with ADVOPT - worldViewIcons->preload(); - - for(int g = 0; g < ADVOPT.gemG.size(); ++g) - { - gems.push_back(std::make_shared(ADVOPT.gemG[g], 0, 0, ADVOPT.gemX[g], ADVOPT.gemY[g])); - } - - auto makeButton = [&](int textID, std::function callback, config::ButtonInfo info, int key) -> std::shared_ptr - { - auto button = std::make_shared(Point(info.x, info.y), info.defName, CGI->generaltexth->zelp[textID], callback, key, info.playerColoured); - for(auto image : info.additionalDefs) - button->addImage(image); - return button; - }; - - kingOverview = makeButton(293, std::bind(&CAdvMapInt::fshowOverview,this), ADVOPT.kingOverview, SDLK_k); - underground = makeButton(294, std::bind(&CAdvMapInt::fswitchLevel,this), ADVOPT.underground, SDLK_u); - questlog = makeButton(295, std::bind(&CAdvMapInt::fshowQuestlog,this), ADVOPT.questlog, SDLK_q); - sleepWake = makeButton(296, std::bind(&CAdvMapInt::fsleepWake,this), ADVOPT.sleepWake, SDLK_w); - moveHero = makeButton(297, std::bind(&CAdvMapInt::fmoveHero,this), ADVOPT.moveHero, SDLK_m); - spellbook = makeButton(298, std::bind(&CAdvMapInt::fshowSpellbok,this), ADVOPT.spellbook, SDLK_c); - advOptions = makeButton(299, std::bind(&CAdvMapInt::fadventureOPtions,this), ADVOPT.advOptions, SDLK_a); - sysOptions = makeButton(300, std::bind(&CAdvMapInt::fsystemOptions,this), ADVOPT.sysOptions, SDLK_o); - nextHero = makeButton(301, std::bind(&CAdvMapInt::fnextHero,this), ADVOPT.nextHero, SDLK_h); - endTurn = makeButton(302, std::bind(&CAdvMapInt::fendTurn,this), ADVOPT.endTurn, SDLK_e); - - int panelSpaceBottom = screen->h - resdatabar.pos.h - 4; - - panelMain = std::make_shared(nullptr, Point(0, 0)); - // TODO correct drawing position - panelWorldView = std::make_shared(worldViewIcons, bgWorldView, Point(heroList.pos.x - 2, 195), panelSpaceBottom, LOCPLINT->playerID); - - panelMain->addChildColorableButton(kingOverview); - panelMain->addChildColorableButton(underground); - panelMain->addChildColorableButton(questlog); - panelMain->addChildColorableButton(sleepWake); - panelMain->addChildColorableButton(moveHero); - panelMain->addChildColorableButton(spellbook); - panelMain->addChildColorableButton(advOptions); - panelMain->addChildColorableButton(sysOptions); - panelMain->addChildColorableButton(nextHero); - panelMain->addChildColorableButton(endTurn); - - - // TODO move configs to resolutions.json, similarly to previous buttons - config::ButtonInfo worldViewBackConfig = config::ButtonInfo(); - worldViewBackConfig.defName = "IOK6432.DEF"; - worldViewBackConfig.x = screen->w - 73; - worldViewBackConfig.y = 343 + 195; - worldViewBackConfig.playerColoured = false; - panelWorldView->addChildToPanel( - makeButton(288, std::bind(&CAdvMapInt::fworldViewBack,this), worldViewBackConfig, SDLK_ESCAPE), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewPuzzleConfig = config::ButtonInfo(); - worldViewPuzzleConfig.defName = "VWPUZ.DEF"; - worldViewPuzzleConfig.x = screen->w - 188; - worldViewPuzzleConfig.y = 343 + 195; - worldViewPuzzleConfig.playerColoured = false; - panelWorldView->addChildToPanel( // no help text for this one - std::make_shared(Point(worldViewPuzzleConfig.x, worldViewPuzzleConfig.y), worldViewPuzzleConfig.defName, std::pair(), - std::bind(&CPlayerInterface::showPuzzleMap,LOCPLINT), SDLK_p, worldViewPuzzleConfig.playerColoured), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewScale1xConfig = config::ButtonInfo(); - worldViewScale1xConfig.defName = "VWMAG1.DEF"; - worldViewScale1xConfig.x = screen->w - 191; - worldViewScale1xConfig.y = 23 + 195; - worldViewScale1xConfig.playerColoured = false; - panelWorldView->addChildToPanel( // help text is wrong for this button - makeButton(291, std::bind(&CAdvMapInt::fworldViewScale1x,this), worldViewScale1xConfig, SDLK_1), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewScale2xConfig = config::ButtonInfo(); - worldViewScale2xConfig.defName = "VWMAG2.DEF"; - worldViewScale2xConfig.x = screen->w - 191 + 63; - worldViewScale2xConfig.y = 23 + 195; - worldViewScale2xConfig.playerColoured = false; - panelWorldView->addChildToPanel( // help text is wrong for this button - makeButton(291, std::bind(&CAdvMapInt::fworldViewScale2x,this), worldViewScale2xConfig, SDLK_2), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewScale4xConfig = config::ButtonInfo(); - worldViewScale4xConfig.defName = "VWMAG4.DEF"; - worldViewScale4xConfig.x = screen->w - 191 + 126; - worldViewScale4xConfig.y = 23 + 195; - worldViewScale4xConfig.playerColoured = false; - panelWorldView->addChildToPanel( // help text is wrong for this button - makeButton(291, std::bind(&CAdvMapInt::fworldViewScale4x,this), worldViewScale4xConfig, SDLK_4), ACTIVATE | DEACTIVATE); - - config::ButtonInfo worldViewUndergroundConfig = config::ButtonInfo(); - worldViewUndergroundConfig.defName = "IAM010.DEF"; - worldViewUndergroundConfig.additionalDefs.push_back("IAM003.DEF"); - worldViewUndergroundConfig.x = screen->w - 115; - worldViewUndergroundConfig.y = 343 + 195; - worldViewUndergroundConfig.playerColoured = true; - worldViewUnderground = makeButton(294, std::bind(&CAdvMapInt::fswitchLevel,this), worldViewUndergroundConfig, SDLK_u); - panelWorldView->addChildColorableButton(worldViewUnderground); - - setPlayer(LOCPLINT->playerID); - - int iconColorMultiplier = player.getNum() * 19; - int wvLeft = heroList.pos.x - 2; // TODO correct drawing position - //int wvTop = 195; - for (int i = 0; i < 5; ++i) - { - panelWorldView->addChildIcon(std::pair(i, Point(5, 58 + i * 20)), iconColorMultiplier); - panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 263 + i * 20, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, - Colors::WHITE, CGI->generaltexth->allTexts[612 + i])); - } - for (int i = 0; i < 7; ++i) - { - panelWorldView->addChildIcon(std::pair(i + 5, Point(5, 182 + i * 20)), iconColorMultiplier); - panelWorldView->addChildIcon(std::pair(i + 12, Point(160, 182 + i * 20)), iconColorMultiplier); - panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 387 + i * 20, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, - Colors::WHITE, CGI->generaltexth->allTexts[619 + i])); - } - panelWorldView->addChildToPanel(std::make_shared(wvLeft + 5, 367, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, - Colors::WHITE, CGI->generaltexth->allTexts[617])); - panelWorldView->addChildToPanel(std::make_shared(wvLeft + 45, 367, EFonts::FONT_SMALL, ETextAlignment::TOPLEFT, - Colors::WHITE, CGI->generaltexth->allTexts[618])); - - activeMapPanel = panelMain; - - changeMode(EAdvMapMode::NORMAL); - - underground->block(!CGI->mh->map->twoLevel); - questlog->block(!CGI->mh->map->quests.size()); - worldViewUnderground->block(!CGI->mh->map->twoLevel); - - addUsedEvents(MOVE); -} - -void CAdvMapInt::fshowOverview() -{ - GH.pushIntT(); -} - -void CAdvMapInt::fworldViewBack() -{ - changeMode(EAdvMapMode::NORMAL); - CGI->mh->discardWorldViewCache(); - - auto hero = curHero(); - if (hero) - centerOn(hero); -} - -void CAdvMapInt::fworldViewScale1x() -{ - // TODO set corresponding scale button to "selected" mode - changeMode(EAdvMapMode::WORLD_VIEW, 0.22f); -} - -void CAdvMapInt::fworldViewScale2x() -{ - changeMode(EAdvMapMode::WORLD_VIEW, 0.36f); -} - -void CAdvMapInt::fworldViewScale4x() -{ - changeMode(EAdvMapMode::WORLD_VIEW, 0.5f); -} - -void CAdvMapInt::fswitchLevel() -{ - // with support for future multi-level maps :) - int maxLevels = CGI->mh->map->levels(); - if (maxLevels < 2) - return; - - position.z = (position.z + 1) % maxLevels; - - underground->setIndex(position.z, true); - underground->redraw(); - - worldViewUnderground->setIndex(position.z, true); - worldViewUnderground->redraw(); - - updateScreen = true; - minimap.setLevel(position.z); - - if (mode == EAdvMapMode::WORLD_VIEW) - terrain.redraw(); -} -void CAdvMapInt::fshowQuestlog() -{ - LOCPLINT->showQuestLog(); -} -void CAdvMapInt::fsleepWake() -{ - const CGHeroInstance *h = curHero(); - if (!h) - return; - bool newSleep = !isHeroSleeping(h); - setHeroSleeping(h, newSleep); - updateSleepWake(h); - if (newSleep) - { - fnextHero(); - - //moveHero.block(true); - //uncomment to enable original HoMM3 behaviour: - //move button is disabled for hero going to sleep, even though it's enabled when you reselect him - } -} - -void CAdvMapInt::fmoveHero() -{ - const CGHeroInstance *h = curHero(); - if (!h || !terrain.currentPath || !CGI->mh->canStartHeroMovement()) - return; - - LOCPLINT->moveHero(h, *terrain.currentPath); -} - -void CAdvMapInt::fshowSpellbok() -{ - if (!curHero()) //checking necessary values - return; - - centerOn(selection); - - GH.pushIntT(curHero(), LOCPLINT, false); -} - -void CAdvMapInt::fadventureOPtions() -{ - GH.pushIntT(); -} - -void CAdvMapInt::fsystemOptions() -{ - GH.pushIntT(); -} - -void CAdvMapInt::fnextHero() -{ - auto hero = dynamic_cast(selection); - int next = getNextHeroIndex(vstd::find_pos(LOCPLINT->wanderingHeroes, hero)); - if (next < 0) - return; - select(LOCPLINT->wanderingHeroes[next], true); -} - -void CAdvMapInt::fendTurn() -{ - if(!LOCPLINT->makingTurn) - return; - - if(settings["adventure"]["heroReminder"].Bool()) - { - for(auto hero : LOCPLINT->wanderingHeroes) - { - if(!isHeroSleeping(hero) && hero->movement > 0) - { - // Only show hero reminder if conditions met: - // - There still movement points - // - Hero don't have a path or there not points for first step on path - auto path = LOCPLINT->getAndVerifyPath(hero); - if(!path || path->nodes.size() < 2 || !path->nodes[path->nodes.size()-2].turns) - { - LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[55], std::bind(&CAdvMapInt::endingTurn, this), nullptr); - return; - } - } - } - } - endingTurn(); -} - -void CAdvMapInt::updateSleepWake(const CGHeroInstance *h) -{ - sleepWake->block(!h); - if (!h) - return; - bool state = isHeroSleeping(h); - sleepWake->setIndex(state ? 1 : 0, true); - sleepWake->assignedKeys.clear(); - sleepWake->assignedKeys.insert(state ? SDLK_w : SDLK_z); -} - -void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath) -{ - if(!h) - { - moveHero->block(true); - return; - } - //default value is for everywhere but CPlayerInterface::moveHero, because paths are not updated from there immediately - if(boost::logic::indeterminate(hasPath)) - hasPath = LOCPLINT->paths[h].nodes.size() ? true : false; - - moveHero->block(!(bool)hasPath || (h->movement == 0)); -} - -void CAdvMapInt::updateSpellbook(const CGHeroInstance *h) -{ - spellbook->block(!h); -} - -int CAdvMapInt::getNextHeroIndex(int startIndex) -{ - if (LOCPLINT->wanderingHeroes.size() == 0) - return -1; - if (startIndex < 0) - startIndex = 0; - int i = startIndex; - do - { - i++; - if (i >= LOCPLINT->wanderingHeroes.size()) - i = 0; - } - while (((LOCPLINT->wanderingHeroes[i]->movement == 0) || isHeroSleeping(LOCPLINT->wanderingHeroes[i])) && (i != startIndex)); - - if ((LOCPLINT->wanderingHeroes[i]->movement != 0) && !isHeroSleeping(LOCPLINT->wanderingHeroes[i])) - return i; - else - return -1; -} - -void CAdvMapInt::updateNextHero(const CGHeroInstance *h) -{ - int start = vstd::find_pos(LOCPLINT->wanderingHeroes, h); - int next = getNextHeroIndex(start); - if (next < 0) - { - nextHero->block(true); - return; - } - const CGHeroInstance *nextH = LOCPLINT->wanderingHeroes[next]; - bool noActiveHeroes = (next == start) && ((nextH->movement == 0) || isHeroSleeping(nextH)); - nextHero->block(noActiveHeroes); -} - -void CAdvMapInt::activate() -{ - CIntObject::activate(); - if (!(active & KEYBOARD)) - CIntObject::activate(KEYBOARD); - - screenBuf = screen; - GH.statusbar = statusbar; - - if(LOCPLINT) - { - LOCPLINT->cingconsole->activate(); - LOCPLINT->cingconsole->pos = this->pos; - } - - if(!duringAITurn) - { - activeMapPanel->activate(); - if (mode == EAdvMapMode::NORMAL) - { - heroList.activate(); - townList.activate(); - infoBar.activate(); - } - minimap.activate(); - terrain.activate(); - statusbar->activate(); - - GH.fakeMouseMove(); //to restore the cursor - } -} - -void CAdvMapInt::deactivate() -{ - CIntObject::deactivate(); - - if(!duringAITurn) - { - scrollingDir = 0; - - CCS->curh->set(Cursor::Map::POINTER); - activeMapPanel->deactivate(); - if (mode == EAdvMapMode::NORMAL) - { - heroList.deactivate(); - townList.deactivate(); - infoBar.deactivate(); - } - minimap.deactivate(); - terrain.deactivate(); - statusbar->deactivate(); - } -} - -void CAdvMapInt::showAll(SDL_Surface * to) -{ - bg->draw(to, 0, 0); - - if(state != INGAME) - return; - - switch (mode) - { - case EAdvMapMode::NORMAL: - - heroList.showAll(to); - townList.showAll(to); - infoBar.showAll(to); - break; - case EAdvMapMode::WORLD_VIEW: - - terrain.showAll(to); - break; - } - activeMapPanel->showAll(to); - - updateScreen = true; - minimap.showAll(to); - show(to); - - - resdatabar.showAll(to); - - statusbar->show(to); - - LOCPLINT->cingconsole->show(to); -} - -bool CAdvMapInt::isHeroSleeping(const CGHeroInstance *hero) -{ - if (!hero) - return false; - - return vstd::contains(LOCPLINT->sleepingHeroes, hero); -} - -void CAdvMapInt::setHeroSleeping(const CGHeroInstance *hero, bool sleep) -{ - if (sleep) - LOCPLINT->sleepingHeroes.push_back(hero); //FIXME: should we check for existence? - else - LOCPLINT->sleepingHeroes -= hero; - updateNextHero(nullptr); -} - -void CAdvMapInt::show(SDL_Surface * to) -{ - if(state != INGAME) - return; - - ++animValHitCount; //for animations - - if(animValHitCount % 2 == 0) - { - ++heroAnim; - } - if(animValHitCount >= 8) - { - CGI->mh->updateWater(); - animValHitCount = 0; - ++anim; - updateScreen = true; - } - - if(swipeEnabled) - { - handleSwipeUpdate(); - } -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) // on mobile, map-moving mode is exclusive (TODO technically it might work with both enabled; to be checked) - else -#endif - { - handleMapScrollingUpdate(); - } - - for(int i = 0; i < 4; i++) - { - if(settings["session"]["spectate"].Bool()) - gems[i]->setFrame(PlayerColor(1).getNum()); - else - gems[i]->setFrame(LOCPLINT->playerID.getNum()); - } - if(updateScreen) - { - int3 betterPos = LOCPLINT->repairScreenPos(position); - if (betterPos != position) - { - logGlobal->warn("Incorrect position for adventure map!"); - position = betterPos; - } - - terrain.show(to); - for(int i = 0; i < 4; i++) - gems[i]->showAll(to); - updateScreen=false; - LOCPLINT->cingconsole->show(to); - } - else if (terrain.needsAnimUpdate()) - { - terrain.showAnim(to); - for(int i = 0; i < 4; i++) - gems[i]->showAll(to); - } - - infoBar.show(to); - statusbar->showAll(to); -} - -void CAdvMapInt::handleMapScrollingUpdate() -{ - int scrollSpeed = static_cast(settings["adventure"]["scrollSpeed"].Float()); - //if advmap needs updating AND (no dialog is shown OR ctrl is pressed) - if((animValHitCount % (4 / scrollSpeed)) == 0 - && ((GH.topInt().get() == this) || isCtrlKeyDown())) - { - if((scrollingDir & LEFT) && (position.x > -CGI->mh->frameW)) - position.x--; - - if((scrollingDir & RIGHT) && (position.x < CGI->mh->map->width - CGI->mh->tilesW + CGI->mh->frameW)) - position.x++; - - if((scrollingDir & UP) && (position.y > -CGI->mh->frameH)) - position.y--; - - if((scrollingDir & DOWN) && (position.y < CGI->mh->map->height - CGI->mh->tilesH + CGI->mh->frameH)) - position.y++; - - if(scrollingDir) - { - setScrollingCursor(scrollingDir); - scrollingState = true; - updateScreen = true; - minimap.redraw(); - if(mode == EAdvMapMode::WORLD_VIEW) - terrain.redraw(); - } - else if(scrollingState) - { - CCS->curh->set(Cursor::Map::POINTER); - scrollingState = false; - } - } -} - -void CAdvMapInt::handleSwipeUpdate() -{ - if(swipeMovementRequested) - { - auto fixedPos = LOCPLINT->repairScreenPos(swipeTargetPosition); - position.x = fixedPos.x; - position.y = fixedPos.y; - CCS->curh->set(Cursor::Map::POINTER); - updateScreen = true; - minimap.redraw(); - swipeMovementRequested = false; - } -} - -void CAdvMapInt::selectionChanged() -{ - const CGTownInstance *to = LOCPLINT->towns[townList.getSelectedIndex()]; - if (selection != to) - select(to); -} - -void CAdvMapInt::centerOn(int3 on, bool fade) -{ - bool switchedLevels = on.z != position.z; - - if (fade) - { - terrain.fadeFromCurrentView(); - } - - switch (mode) - { - default: - case EAdvMapMode::NORMAL: - on.x -= CGI->mh->frameW; // is this intentional? frame size doesn't really have to correspond to camera size... - on.y -= CGI->mh->frameH; - break; - case EAdvMapMode::WORLD_VIEW: - on.x -= static_cast(CGI->mh->tilesW / 2 / worldViewScale); - on.y -= static_cast(CGI->mh->tilesH / 2 / worldViewScale); - break; - } - - - on = LOCPLINT->repairScreenPos(on); - - position = on; - updateScreen=true; - underground->setIndex(on.z,true); //change underground switch button image - underground->redraw(); - worldViewUnderground->setIndex(on.z, true); - worldViewUnderground->redraw(); - if (switchedLevels) - minimap.setLevel(position.z); - minimap.redraw(); - - if (mode == EAdvMapMode::WORLD_VIEW) - terrain.redraw(); -} - -void CAdvMapInt::centerOn(const CGObjectInstance * obj, bool fade) -{ - centerOn(obj->getSightCenter(), fade); -} - -void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) -{ - - if (mode == EAdvMapMode::WORLD_VIEW) - return; - - ui8 Dir = 0; - SDL_Keycode k = key.keysym.sym; - const CGHeroInstance *h = curHero(); //selected hero - const CGTownInstance *t = curTown(); //selected town - - switch(k) - { - case SDLK_g: - if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) - return; - - { - //find first town with tavern - auto itr = range::find_if(LOCPLINT->towns, [](const CGTownInstance * town) - { - return town->hasBuilt(BuildingID::TAVERN); - }); - - if(itr != LOCPLINT->towns.end()) - LOCPLINT->showThievesGuildWindow(*itr); - else - LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithTavern")); - } - return; - case SDLK_i: - if(isActive()) - CAdventureOptions::showScenarioInfo(); - return; - case SDLK_l: - if(isActive()) - LOCPLINT->proposeLoadingGame(); - return; - case SDLK_s: - if(isActive() && key.type == SDL_KEYUP) - GH.pushIntT(); - return; - case SDLK_d: - { - if(h && isActive() && LOCPLINT->makingTurn && key.state == SDL_PRESSED) - LOCPLINT->tryDiggging(h); - return; - } - case SDLK_p: - if(isActive()) - LOCPLINT->showPuzzleMap(); - return; - case SDLK_v: - if(isActive()) - LOCPLINT->viewWorldMap(); - return; - case SDLK_r: - if(isActive() && LOCPLINT->ctrlPressed()) - { - LOCPLINT->showYesNoDialog(CGI->generaltexth->translate("vcmi.adventureMap.confirmRestartGame"), - [](){ LOCPLINT->sendCustomEvent(EUserEvent::RESTART_GAME); }, nullptr); - } - return; - case SDLK_SPACE: //space - try to revisit current object with selected hero - { - if(!isActive()) - return; - if(h && key.state == SDL_PRESSED) - { - auto unlockPim = vstd::makeUnlockGuard(*CPlayerInterface::pim); - //TODO!!!!!!! possible freeze, when GS mutex is locked and network thread can't apply package - //this thread leaves scope and tries to lock pim while holding gs, - //network thread tries to lock gs (appluy cl) while holding pim - //this thread should first lock pim, however gs locking/unlocking is done inside cb - LOCPLINT->cb->moveHero(h,h->pos); - } - } - return; - case SDLK_RETURN: - { - if(!isActive() || !selection || key.state != SDL_PRESSED) - return; - if(h) - LOCPLINT->openHeroWindow(h); - else if(t) - LOCPLINT->openTownWindow(t); - return; - } - case SDLK_ESCAPE: - { - if(isActive() || GH.topInt().get() != this || !spellBeingCasted || key.state != SDL_PRESSED) - return; - - leaveCastingMode(); - return; - } - case SDLK_t: - { - //act on key down if marketplace windows is not already opened - if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS) - return; - - if(LOCPLINT->ctrlPressed()) //CTRL + T => open marketplace - { - //check if we have any marketplace - const CGTownInstance *townWithMarket = nullptr; - for(const CGTownInstance *t : LOCPLINT->cb->getTownsInfo()) - { - if(t->hasBuilt(BuildingID::MARKETPLACE)) - { - townWithMarket = t; - break; - } - } - - if(townWithMarket) //if any town has marketplace, open window - GH.pushIntT(townWithMarket); - else //if not - complain - LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithMarket")); - } - else if(isActive()) //no ctrl, advmapint is on the top => switch to town - { - townList.selectNext(); - } - return; - } - default: - { - static const int3 directions[] = { int3(-1, +1, 0), int3(0, +1, 0), int3(+1, +1, 0), - int3(-1, 0, 0), int3(0, 0, 0), int3(+1, 0, 0), - int3(-1, -1, 0), int3(0, -1, 0), int3(+1, -1, 0) }; - - //numpad arrow - if(CGuiHandler::isArrowKey(k)) - k = CGuiHandler::arrowToNum(k); - - k -= SDLK_KP_1; - - if(k < 0 || k > 8) - return; - - if (!CGI->mh->canStartHeroMovement()) - return; - - int3 dir = directions[k]; - - if(!isActive() || LOCPLINT->ctrlPressed())//ctrl makes arrow move screen, not hero - { - Dir = (dir.x<0 ? LEFT : 0) | - (dir.x>0 ? RIGHT : 0) | - (dir.y<0 ? UP : 0) | - (dir.y>0 ? DOWN : 0) ; - break; - } - - if(!h || key.state != SDL_PRESSED) - break; - - if(k == 4) - { - centerOn(h); - return; - } - - CGPath &path = LOCPLINT->paths[h]; - terrain.currentPath = &path; - int3 dst = h->visitablePos() + dir; - if(dst != verifyPos(dst) || !LOCPLINT->cb->getPathsInfo(h)->getPath(path, dst)) - { - terrain.currentPath = nullptr; - return; - } - - if (path.nodes.size() > 2) - updateMoveHero(h); - else - if(!path.nodes[0].turns) - LOCPLINT->moveHero(h, path); - } - - return; - } - if(Dir && key.state == SDL_PRESSED //arrow is pressed - && LOCPLINT->ctrlPressed() - ) - scrollingDir |= Dir; - else - scrollingDir &= ~Dir; -} -void CAdvMapInt::handleRightClick(std::string text, tribool down) -{ - if(down) - { - CRClickPopup::createAndPush(text); - } -} -int3 CAdvMapInt::verifyPos(int3 ver) -{ - if (ver.x<0) - ver.x=0; - if (ver.y<0) - ver.y=0; - if (ver.z<0) - ver.z=0; - if (ver.x>=CGI->mh->sizes.x) - ver.x=CGI->mh->sizes.x-1; - if (ver.y>=CGI->mh->sizes.y) - ver.y=CGI->mh->sizes.y-1; - if (ver.z>=CGI->mh->sizes.z) - ver.z=CGI->mh->sizes.z-1; - return ver; -} - -void CAdvMapInt::select(const CArmedInstance *sel, bool centerView) -{ - assert(sel); - LOCPLINT->setSelection(sel); - selection = sel; - if (LOCPLINT->battleInt == nullptr && LOCPLINT->makingTurn) - { - auto pos = sel->visitablePos(); - auto tile = LOCPLINT->cb->getTile(pos); - if(tile) - CCS->musich->playMusicFromSet("terrain", tile->terType->getJsonKey(), true, false); - } - if(centerView) - centerOn(sel); - - terrain.currentPath = nullptr; - if(sel->ID==Obj::TOWN) - { - auto town = dynamic_cast(sel); - - infoBar.showTownSelection(town); - townList.select(town); - heroList.select(nullptr); - - updateSleepWake(nullptr); - updateMoveHero(nullptr); - updateSpellbook(nullptr); - } - else //hero selected - { - auto hero = dynamic_cast(sel); - - infoBar.showHeroSelection(hero); - heroList.select(hero); - townList.select(nullptr); - - terrain.currentPath = LOCPLINT->getAndVerifyPath(hero); - - updateSleepWake(hero); - updateMoveHero(hero); - updateSpellbook(hero); - } - townList.redraw(); - heroList.redraw(); -} - -void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent ) -{ -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - if(swipeEnabled) - return; -#endif - // adventure map scrolling with mouse - // currently disabled in world view mode (as it is in OH3), but should work correctly if mode check is removed - // don't scroll if there is no window in focus - these events don't seem to correspond to the actual mouse movement - if(!isCtrlKeyDown() && isActive() && sEvent.windowID != 0 && mode == EAdvMapMode::NORMAL) - { - if(sEvent.x<15) - { - scrollingDir |= LEFT; - } - else - { - scrollingDir &= ~LEFT; - } - if(sEvent.x>screen->w-15) - { - scrollingDir |= RIGHT; - } - else - { - scrollingDir &= ~RIGHT; - } - if(sEvent.y<15) - { - scrollingDir |= UP; - } - else - { - scrollingDir &= ~UP; - } - if(sEvent.y>screen->h-15) - { - scrollingDir |= DOWN; - } - else - { - scrollingDir &= ~DOWN; - } - } -} - -bool CAdvMapInt::isActive() -{ - return active & ~CIntObject::KEYBOARD; -} - -void CAdvMapInt::startHotSeatWait(PlayerColor Player) -{ - state = WAITING; -} - -void CAdvMapInt::setPlayer(PlayerColor Player) -{ - player = Player; - bg->playerColored(player); - - panelMain->setPlayerColor(player); - panelWorldView->setPlayerColor(player); - panelWorldView->recolorIcons(player, player.getNum() * 19); - resdatabar.background->colorize(player); -} - -void CAdvMapInt::startTurn() -{ - state = INGAME; - if(LOCPLINT->cb->getCurrentPlayer() == LOCPLINT->playerID - || settings["session"]["spectate"].Bool()) - { - adjustActiveness(false); - minimap.setAIRadar(false); - } -} - -void CAdvMapInt::endingTurn() -{ - if(settings["session"]["spectate"].Bool()) - return; - - LOCPLINT->makingTurn = false; - LOCPLINT->cb->endTurn(); - CCS->soundh->ambientStopAllChannels(); -} - -const CGObjectInstance* CAdvMapInt::getActiveObject(const int3 &mapPos) -{ - std::vector < const CGObjectInstance * > bobjs = LOCPLINT->cb->getBlockingObjs(mapPos); //blocking objects at tile - - if (bobjs.empty()) - return nullptr; - - return *boost::range::max_element(bobjs, &CMapHandler::compareObjectBlitOrder); -/* - if (bobjs.back()->ID == Obj::HERO) - return bobjs.back(); - else - return bobjs.front();*/ -} - -void CAdvMapInt::tileLClicked(const int3 &mapPos) -{ - if(mode != EAdvMapMode::NORMAL) - return; - if(!LOCPLINT->cb->isVisible(mapPos) || !LOCPLINT->makingTurn) - return; - - const TerrainTile *tile = LOCPLINT->cb->getTile(mapPos); - - const CGObjectInstance *topBlocking = getActiveObject(mapPos); - - int3 selPos = selection->getSightCenter(); - if(spellBeingCasted && isInScreenRange(selPos, mapPos)) - { - const TerrainTile *heroTile = LOCPLINT->cb->getTile(selPos); - - switch(spellBeingCasted->id) - { - case SpellID::SCUTTLE_BOAT: //Scuttle Boat - if(topBlocking && topBlocking->ID == Obj::BOAT) - leaveCastingMode(true, mapPos); - break; - case SpellID::DIMENSION_DOOR: - if(!tile || tile->isClear(heroTile)) - leaveCastingMode(true, mapPos); - break; - } - return; - } - //check if we can select this object - bool canSelect = topBlocking && topBlocking->ID == Obj::HERO && topBlocking->tempOwner == LOCPLINT->playerID; - canSelect |= topBlocking && topBlocking->ID == Obj::TOWN && LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, topBlocking->tempOwner); - - bool isHero = false; - if(selection->ID != Obj::HERO) //hero is not selected (presumably town) - { - assert(!terrain.currentPath); //path can be active only when hero is selected - if(selection == topBlocking) //selected town clicked - LOCPLINT->openTownWindow(static_cast(topBlocking)); - else if(canSelect) - select(static_cast(topBlocking), false); - } - else if(const CGHeroInstance * currentHero = curHero()) //hero is selected - { - isHero = true; - - const CGPathNode *pn = LOCPLINT->cb->getPathsInfo(currentHero)->getPathInfo(mapPos); - if(currentHero == topBlocking) //clicked selected hero - { - LOCPLINT->openHeroWindow(currentHero); - return; - } - else if(canSelect && pn->turns == 255 ) //selectable object at inaccessible tile - { - select(static_cast(topBlocking), false); - return; - } - else //still here? we need to move hero if we clicked end of already selected path or calculate a new path otherwise - { - if(terrain.currentPath && terrain.currentPath->endPos() == mapPos)//we'll be moving - { - if(CGI->mh->canStartHeroMovement()) - LOCPLINT->moveHero(currentHero, *terrain.currentPath); - return; - } - else //remove old path and find a new one if we clicked on accessible tile - { - CGPath &path = LOCPLINT->paths[currentHero]; - CGPath newpath; - bool gotPath = LOCPLINT->cb->getPathsInfo(currentHero)->getPath(newpath, mapPos); //try getting path, erase if failed - if(gotPath && newpath.nodes.size()) - path = newpath; - - if(path.nodes.size()) - terrain.currentPath = &path; - else - LOCPLINT->eraseCurrentPathOf(currentHero); - - updateMoveHero(currentHero); - } - } - } //end of hero is selected "case" - else - { - throw std::runtime_error("Nothing is selected..."); - } - - const auto shipyard = ourInaccessibleShipyard(topBlocking); - if(isHero && shipyard != nullptr) - { - LOCPLINT->showShipyardDialogOrProblemPopup(shipyard); - } -} - -void CAdvMapInt::tileHovered(const int3 &mapPos) -{ - if(mode != EAdvMapMode::NORMAL //disable in world view - || !selection) //may occur just at the start of game (fake move before full intiialization) - return; - if(!LOCPLINT->cb->isVisible(mapPos)) - { - CCS->curh->set(Cursor::Map::POINTER); - statusbar->clear(); - return; - } - auto objRelations = PlayerRelations::ALLIES; - const CGObjectInstance *objAtTile = getActiveObject(mapPos); - if(objAtTile) - { - objRelations = LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, objAtTile->tempOwner); - std::string text = curHero() ? objAtTile->getHoverText(curHero()) : objAtTile->getHoverText(LOCPLINT->playerID); - boost::replace_all(text,"\n"," "); - statusbar->write(text); - } - else - { - std::string hlp; - CGI->mh->getTerrainDescr(mapPos, hlp, false); - statusbar->write(hlp); - } - - if(spellBeingCasted) - { - switch(spellBeingCasted->id) - { - case SpellID::SCUTTLE_BOAT: - if(objAtTile && objAtTile->ID == Obj::BOAT) - CCS->curh->set(Cursor::Map::SCUTTLE_BOAT); - else - CCS->curh->set(Cursor::Map::POINTER); - return; - case SpellID::DIMENSION_DOOR: - { - const TerrainTile * t = LOCPLINT->cb->getTile(mapPos, false); - int3 hpos = selection->getSightCenter(); - if((!t || t->isClear(LOCPLINT->cb->getTile(hpos))) && isInScreenRange(hpos, mapPos)) - CCS->curh->set(Cursor::Map::TELEPORT); - else - CCS->curh->set(Cursor::Map::POINTER); - return; - } - } - } - - if(selection->ID == Obj::TOWN) - { - if(objAtTile) - { - if(objAtTile->ID == Obj::TOWN && objRelations != PlayerRelations::ENEMIES) - CCS->curh->set(Cursor::Map::TOWN); - else if(objAtTile->ID == Obj::HERO && objRelations == PlayerRelations::SAME_PLAYER) - CCS->curh->set(Cursor::Map::HERO); - else - CCS->curh->set(Cursor::Map::POINTER); - } - else - CCS->curh->set(Cursor::Map::POINTER); - } - else if(const CGHeroInstance * hero = curHero()) - { - std::array cursorMove = { Cursor::Map::T1_MOVE, Cursor::Map::T2_MOVE, Cursor::Map::T3_MOVE, Cursor::Map::T4_MOVE, }; - std::array cursorAttack = { Cursor::Map::T1_ATTACK, Cursor::Map::T2_ATTACK, Cursor::Map::T3_ATTACK, Cursor::Map::T4_ATTACK, }; - std::array cursorSail = { Cursor::Map::T1_SAIL, Cursor::Map::T2_SAIL, Cursor::Map::T3_SAIL, Cursor::Map::T4_SAIL, }; - std::array cursorDisembark = { Cursor::Map::T1_DISEMBARK, Cursor::Map::T2_DISEMBARK, Cursor::Map::T3_DISEMBARK, Cursor::Map::T4_DISEMBARK, }; - std::array cursorExchange = { Cursor::Map::T1_EXCHANGE, Cursor::Map::T2_EXCHANGE, Cursor::Map::T3_EXCHANGE, Cursor::Map::T4_EXCHANGE, }; - std::array cursorVisit = { Cursor::Map::T1_VISIT, Cursor::Map::T2_VISIT, Cursor::Map::T3_VISIT, Cursor::Map::T4_VISIT, }; - std::array cursorSailVisit = { Cursor::Map::T1_SAIL_VISIT, Cursor::Map::T2_SAIL_VISIT, Cursor::Map::T3_SAIL_VISIT, Cursor::Map::T4_SAIL_VISIT, }; - - const CGPathNode * pathNode = LOCPLINT->cb->getPathsInfo(hero)->getPathInfo(mapPos); - assert(pathNode); - - if(LOCPLINT->altPressed() && pathNode->reachable()) //overwrite status bar text with movement info - { - ShowMoveDetailsInStatusbar(*hero, *pathNode); - } - - int turns = pathNode->turns; - vstd::amin(turns, 3); - switch(pathNode->action) - { - case CGPathNode::NORMAL: - case CGPathNode::TELEPORT_NORMAL: - if(pathNode->layer == EPathfindingLayer::LAND) - CCS->curh->set(cursorMove[turns]); - else - CCS->curh->set(cursorSailVisit[turns]); - break; - - case CGPathNode::VISIT: - case CGPathNode::BLOCKING_VISIT: - case CGPathNode::TELEPORT_BLOCKING_VISIT: - if(objAtTile && objAtTile->ID == Obj::HERO) - { - if(selection == objAtTile) - CCS->curh->set(Cursor::Map::HERO); - else - CCS->curh->set(cursorExchange[turns]); - } - else if(pathNode->layer == EPathfindingLayer::LAND) - CCS->curh->set(cursorVisit[turns]); - else - CCS->curh->set(cursorSailVisit[turns]); - break; - - case CGPathNode::BATTLE: - case CGPathNode::TELEPORT_BATTLE: - CCS->curh->set(cursorAttack[turns]); - break; - - case CGPathNode::EMBARK: - CCS->curh->set(cursorSail[turns]); - break; - - case CGPathNode::DISEMBARK: - CCS->curh->set(cursorDisembark[turns]); - break; - - default: - if(objAtTile && objRelations != PlayerRelations::ENEMIES) - { - if(objAtTile->ID == Obj::TOWN) - CCS->curh->set(Cursor::Map::TOWN); - else if(objAtTile->ID == Obj::HERO && objRelations == PlayerRelations::SAME_PLAYER) - CCS->curh->set(Cursor::Map::HERO); - else - CCS->curh->set(Cursor::Map::POINTER); - } - else - CCS->curh->set(Cursor::Map::POINTER); - break; - } - } - - if(ourInaccessibleShipyard(objAtTile)) - { - CCS->curh->set(Cursor::Map::T1_SAIL); - } -} - -void CAdvMapInt::ShowMoveDetailsInStatusbar(const CGHeroInstance & hero, const CGPathNode & pathNode) -{ - const int maxMovementPointsAtStartOfLastTurn = pathNode.turns > 0 ? hero.maxMovePoints(pathNode.layer == EPathfindingLayer::LAND) : hero.movement; - const int movementPointsLastTurnCost = maxMovementPointsAtStartOfLastTurn - pathNode.moveRemains; - const int remainingPointsAfterMove = pathNode.turns == 0 ? pathNode.moveRemains : 0; - - std::string result = VLC->generaltexth->translate("vcmi.adventureMap", pathNode.turns > 0 ? "moveCostDetails" : "moveCostDetailsNoTurns"); - - boost::replace_first(result, "%TURNS", std::to_string(pathNode.turns)); - boost::replace_first(result, "%POINTS", std::to_string(movementPointsLastTurnCost)); - boost::replace_first(result, "%REMAINING", std::to_string(remainingPointsAfterMove)); - - statusbar->write(result); -} - -void CAdvMapInt::tileRClicked(const int3 &mapPos) -{ - if(mode != EAdvMapMode::NORMAL) - return; - if(spellBeingCasted) - { - leaveCastingMode(); - return; - } - if(!LOCPLINT->cb->isVisible(mapPos)) - { - CRClickPopup::createAndPush(VLC->generaltexth->allTexts[61]); //Uncharted Territory - return; - } - - const CGObjectInstance * obj = getActiveObject(mapPos); - if(!obj) - { - // Bare or undiscovered terrain - const TerrainTile * tile = LOCPLINT->cb->getTile(mapPos); - if (tile) - { - std::string hlp; - CGI->mh->getTerrainDescr(mapPos, hlp, true); - CRClickPopup::createAndPush(hlp); - } - return; - } - - CRClickPopup::createAndPush(obj, GH.getCursorPosition(), ETextAlignment::CENTER); -} - -void CAdvMapInt::enterCastingMode(const CSpell * sp) -{ - assert(sp->id == SpellID::SCUTTLE_BOAT || sp->id == SpellID::DIMENSION_DOOR); - spellBeingCasted = sp; - - deactivate(); - terrain.activate(); - GH.fakeMouseMove(); -} - -void CAdvMapInt::leaveCastingMode(bool cast, int3 dest) -{ - assert(spellBeingCasted); - SpellID id = spellBeingCasted->id; - spellBeingCasted = nullptr; - terrain.deactivate(); - activate(); - - if(cast) - LOCPLINT->cb->castSpell(curHero(), id, dest); - else - LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[731]); //Spell cancelled -} - -const CGHeroInstance * CAdvMapInt::curHero() const -{ - if(selection && selection->ID == Obj::HERO) - return static_cast(selection); - else - return nullptr; -} - -const CGTownInstance * CAdvMapInt::curTown() const -{ - if(selection && selection->ID == Obj::TOWN) - return static_cast(selection); - else - return nullptr; -} - -const IShipyard * CAdvMapInt::ourInaccessibleShipyard(const CGObjectInstance *obj) const -{ - const IShipyard *ret = IShipyard::castFrom(obj); - - if(!ret || - obj->tempOwner != player || - (CCS->curh->get() != Cursor::Map::T1_SAIL && CCS->curh->get() != Cursor::Map::POINTER)) - return nullptr; - - return ret; -} - -void CAdvMapInt::aiTurnStarted() -{ - if(settings["session"]["spectate"].Bool()) - return; - - adjustActiveness(true); - CCS->musich->playMusicFromSet("enemy-turn", true, false); - adventureInt->minimap.setAIRadar(true); - adventureInt->infoBar.startEnemyTurn(LOCPLINT->cb->getCurrentPlayer()); - adventureInt->infoBar.showAll(screen);//force refresh on inactive object -} - -void CAdvMapInt::adjustActiveness(bool aiTurnStart) -{ - bool wasActive = isActive(); - - if(wasActive) - deactivate(); - adventureInt->duringAITurn = aiTurnStart; - if(wasActive) - activate(); -} - -void CAdvMapInt::quickCombatLock() -{ - if(!duringAITurn) - deactivate(); -} - -void CAdvMapInt::quickCombatUnlock() -{ - if(!duringAITurn) - activate(); -} - -void CAdvMapInt::changeMode(EAdvMapMode newMode, float newScale) -{ - if (mode != newMode) - { - mode = newMode; - - switch (mode) - { - case EAdvMapMode::NORMAL: - panelMain->activate(); - panelWorldView->deactivate(); - activeMapPanel = panelMain; - - townList.activate(); - heroList.activate(); - infoBar.activate(); - - worldViewOptions.clear(); - - break; - case EAdvMapMode::WORLD_VIEW: - panelMain->deactivate(); - panelWorldView->activate(); - - activeMapPanel = panelWorldView; - - townList.deactivate(); - heroList.deactivate(); - infoBar.showSelection(); // to prevent new day animation interfering world view mode - infoBar.deactivate(); - - break; - } - worldViewScale = newScale; - redraw(); - } - else if (worldViewScale != newScale) // still in world view mode, but the scale changed - { - worldViewScale = newScale; - redraw(); - } -} - -CAdventureOptions::CAdventureOptions() - : CWindowObject(PLAYER_COLORED, "ADVOPTS") -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - - viewWorld = std::make_shared(Point(24, 23), "ADVVIEW.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_v); - viewWorld->addCallback(std::bind(&CPlayerInterface::viewWorldMap, LOCPLINT)); - - exit = std::make_shared(Point(204, 313), "IOK6432.DEF", CButton::tooltip(), std::bind(&CAdventureOptions::close, this), SDLK_RETURN); - exit->assignedKeys.insert(SDLK_ESCAPE); - - scenInfo = std::make_shared(Point(24, 198), "ADVINFO.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_i); - scenInfo->addCallback(CAdventureOptions::showScenarioInfo); - - puzzle = std::make_shared(Point(24, 81), "ADVPUZ.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_p); - puzzle->addCallback(std::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT)); - - dig = std::make_shared(Point(24, 139), "ADVDIG.DEF", CButton::tooltip(), [&](){ close(); }, SDLK_d); - if(const CGHeroInstance *h = adventureInt->curHero()) - dig->addCallback(std::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h)); - else - dig->block(true); -} - -void CAdventureOptions::showScenarioInfo() -{ - if(LOCPLINT->cb->getStartInfo()->campState) - { - GH.pushIntT(); - } - else - { - GH.pushIntT(); - } -} - -CAdvMapInt::WorldViewOptions::WorldViewOptions() -{ - clear(); -} - -void CAdvMapInt::WorldViewOptions::clear() -{ - showAllTerrain = false; - - iconPositions.clear(); -} - -void CAdvMapInt::WorldViewOptions::adjustDrawingInfo(MapDrawingInfo& info) -{ - info.showAllTerrain = showAllTerrain; - - info.additionalIcons = &iconPositions; -} diff --git a/client/adventureMap/CTerrainRect.h b/client/adventureMap/CTerrainRect.h index 6b1ae0ddc..006b03aeb 100644 --- a/client/adventureMap/CTerrainRect.h +++ b/client/adventureMap/CTerrainRect.h @@ -36,29 +36,6 @@ class CFadeAnimation; struct MapDrawingInfo; -/*****************************/ - -enum class EAdvMapMode -{ - NORMAL, - WORLD_VIEW -}; - -/// Adventure options dialog where you can view the world, dig, play the replay of the last turn,... -class CAdventureOptions : public CWindowObject -{ -public: - std::shared_ptr exit; - std::shared_ptr viewWorld; - std::shared_ptr puzzle; - std::shared_ptr dig; - std::shared_ptr scenInfo; - /*std::shared_ptr replay*/ - - CAdventureOptions(); - static void showScenarioInfo(); -}; - /// Holds information about which tiles of the terrain are shown/not shown at the screen class CTerrainRect : public CIntObject { @@ -102,175 +79,3 @@ public: bool needsAnimUpdate(); }; -/// Resources bar which shows information about how many gold, crystals,... you have -/// Current date is displayed too -class CResDataBar : public CIntObject -{ -public: - std::shared_ptr background; - - std::vector > txtpos; - std::string datetext; - - void clickRight(tribool down, bool previousState) override; - CResDataBar(); - CResDataBar(const std::string &defname, int x, int y, int offx, int offy, int resdist, int datedist); - ~CResDataBar(); - - void draw(SDL_Surface * to); - void show(SDL_Surface * to) override; - void showAll(SDL_Surface * to) override; -}; - -/// That's a huge class which handles general adventure map actions and -/// shows the right menu(questlog, spellbook, end turn,..) from where you -/// can get to the towns and heroes. -class CAdvMapInt : public CIntObject -{ - //Return object that must be active at this tile (=clickable) - const CGObjectInstance *getActiveObject(const int3 &tile); - -public: - CAdvMapInt(); - - int3 position; //top left corner of visible map part - PlayerColor player; - - bool duringAITurn; - - enum{LEFT=1, RIGHT=2, UP=4, DOWN=8}; - ui8 scrollingDir; //uses enum: LEFT RIGHT, UP, DOWN - bool scrollingState; - bool swipeEnabled; - bool swipeMovementRequested; - int3 swipeTargetPosition; - - enum{NA, INGAME, WAITING} state; - - bool updateScreen; - ui8 anim, animValHitCount; //animation frame - ui8 heroAnim, heroAnimValHitCount; //animation frame - - EAdvMapMode mode; - float worldViewScale; - - struct WorldViewOptions - { - bool showAllTerrain; //for expert viewEarth - - std::vector iconPositions; - - WorldViewOptions(); - - void clear(); - - void adjustDrawingInfo(MapDrawingInfo & info); - }; - - WorldViewOptions worldViewOptions; - - std::shared_ptr bg; - std::shared_ptr bgWorldView; - std::vector> gems; - CMinimap minimap; - std::shared_ptr statusbar; - - std::shared_ptr kingOverview; - std::shared_ptr underground; - std::shared_ptr questlog; - std::shared_ptr sleepWake; - std::shared_ptr moveHero; - std::shared_ptr spellbook; - std::shared_ptr advOptions; - std::shared_ptr sysOptions; - std::shared_ptr nextHero; - std::shared_ptr endTurn; - - std::shared_ptr worldViewUnderground; - - CTerrainRect terrain; //visible terrain - CResDataBar resdatabar; - CHeroList heroList; - CTownList townList; - CInfoBar infoBar; - - std::shared_ptr panelMain; // panel that holds all right-side buttons in normal view - std::shared_ptr panelWorldView; // panel that holds all buttons and other ui in world view - std::shared_ptr activeMapPanel; // currently active panel (either main or world view, depending on current mode) - - std::shared_ptr worldViewIcons;// images for world view overlay - - const CSpell *spellBeingCasted; //nullptr if none - - const CArmedInstance *selection; //currently selected town/hero - - //functions bound to buttons - void fshowOverview(); - void fworldViewBack(); - void fworldViewScale1x(); - void fworldViewScale2x(); - void fworldViewScale4x(); - void fswitchLevel(); - void fshowQuestlog(); - void fsleepWake(); - void fmoveHero(); - void fshowSpellbok(); - void fadventureOPtions(); - void fsystemOptions(); - void fnextHero(); - void fendTurn(); - - void activate() override; - void deactivate() override; - - void show(SDL_Surface * to) override; //redraws terrain - void showAll(SDL_Surface * to) override; //shows and activates adv. map interface - - void select(const CArmedInstance *sel, bool centerView = true); - void selectionChanged(); - void centerOn(int3 on, bool fade = false); - void centerOn(const CGObjectInstance *obj, bool fade = false); - int3 verifyPos(int3 ver); - void handleRightClick(std::string text, tribool down); - void keyPressed(const SDL_KeyboardEvent & key) override; - void mouseMoved (const SDL_MouseMotionEvent & sEvent) override; - bool isActive(); - - bool isHeroSleeping(const CGHeroInstance *hero); - void setHeroSleeping(const CGHeroInstance *hero, bool sleep); - int getNextHeroIndex(int startIndex); //for Next Hero button - cycles awake heroes with movement only - - void setPlayer(PlayerColor Player); - void startHotSeatWait(PlayerColor Player); - void startTurn(); - void endingTurn(); - void aiTurnStarted(); - - void adjustActiveness(bool aiTurnStart); //should be called every time at AI/human turn transition; blocks GUI during AI turn - void quickCombatLock(); //should be called when quick battle started - void quickCombatUnlock(); - void tileLClicked(const int3 &mapPos); - void tileHovered(const int3 &mapPos); - void tileRClicked(const int3 &mapPos); - void enterCastingMode(const CSpell * sp); - void leaveCastingMode(bool cast = false, int3 dest = int3(-1, -1, -1)); - const CGHeroInstance * curHero() const; - const CGTownInstance * curTown() const; - const IShipyard * ourInaccessibleShipyard(const CGObjectInstance *obj) const; //checks if obj is our ashipyard and cursor is 0,0 -> returns shipyard or nullptr else - //button updates - void updateSleepWake(const CGHeroInstance *h); - void updateMoveHero(const CGHeroInstance *h, tribool hasPath = boost::logic::indeterminate); - void updateSpellbook(const CGHeroInstance *h); - void updateNextHero(const CGHeroInstance *h); - - /// changes current adventure map mode; used to switch between default view and world view; scale is ignored if EAdvMapMode == NORMAL - void changeMode(EAdvMapMode newMode, float newScale = 0.36f); - - void handleMapScrollingUpdate(); - void handleSwipeUpdate(); - -private: - void ShowMoveDetailsInStatusbar(const CGHeroInstance & hero, const CGPathNode & pathNode); -}; - -extern std::shared_ptr adventureInt; From 730b8e3fc24b048d8814089b8e72714cc13aa423 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:33:51 +0200 Subject: [PATCH 58/79] Moved IFont to a separate file --- client/render/{Fonts.h => IFont.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename client/render/{Fonts.h => IFont.h} (100%) diff --git a/client/render/Fonts.h b/client/render/IFont.h similarity index 100% rename from client/render/Fonts.h rename to client/render/IFont.h From 1884c409f9fc60e13b08d4646ff28edb1e5bbc75 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:34:50 +0200 Subject: [PATCH 59/79] Moved CBitmapFont to a separate file --- client/render/{Fonts.cpp => CBitmapFont.cpp} | 0 client/render/{Fonts.h => CBitmapFont.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/render/{Fonts.cpp => CBitmapFont.cpp} (100%) rename client/render/{Fonts.h => CBitmapFont.h} (100%) diff --git a/client/render/Fonts.cpp b/client/render/CBitmapFont.cpp similarity index 100% rename from client/render/Fonts.cpp rename to client/render/CBitmapFont.cpp diff --git a/client/render/Fonts.h b/client/render/CBitmapFont.h similarity index 100% rename from client/render/Fonts.h rename to client/render/CBitmapFont.h From aab7e0a5ed75d2e797a33d398b5b0d342813a5a8 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:35:52 +0200 Subject: [PATCH 60/79] Moved CTrueTypeFont to a separate file --- client/render/{Fonts.cpp => CTrueTypeFont.cpp} | 0 client/render/{Fonts.h => CTrueTypeFont.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/render/{Fonts.cpp => CTrueTypeFont.cpp} (100%) rename client/render/{Fonts.h => CTrueTypeFont.h} (100%) diff --git a/client/render/Fonts.cpp b/client/render/CTrueTypeFont.cpp similarity index 100% rename from client/render/Fonts.cpp rename to client/render/CTrueTypeFont.cpp diff --git a/client/render/Fonts.h b/client/render/CTrueTypeFont.h similarity index 100% rename from client/render/Fonts.h rename to client/render/CTrueTypeFont.h From 3da4c9bb251f0d969f6744b0d07cfd61791782df Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:36:38 +0200 Subject: [PATCH 61/79] Moved CBitmapHanFont to a separate file --- client/render/{Fonts.cpp => CBitmapHanFont.cpp} | 0 client/render/{Fonts.h => CBitmapHanFont.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/render/{Fonts.cpp => CBitmapHanFont.cpp} (100%) rename client/render/{Fonts.h => CBitmapHanFont.h} (100%) diff --git a/client/render/Fonts.cpp b/client/render/CBitmapHanFont.cpp similarity index 100% rename from client/render/Fonts.cpp rename to client/render/CBitmapHanFont.cpp diff --git a/client/render/Fonts.h b/client/render/CBitmapHanFont.h similarity index 100% rename from client/render/Fonts.h rename to client/render/CBitmapHanFont.h From bfec00b0227472431e6518c9f920c52047c9a5ad Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:42:21 +0200 Subject: [PATCH 62/79] Remove duplicated code in new files --- client/render/CBitmapFont.cpp | 250 -------------------------- client/render/CBitmapFont.h | 79 --------- client/render/CBitmapHanFont.cpp | 267 ---------------------------- client/render/CBitmapHanFont.h | 69 ------- client/render/CTrueTypeFont.cpp | 296 ------------------------------- client/render/CTrueTypeFont.h | 91 ---------- client/render/IFont.cpp | 83 +++++++++ client/render/IFont.h | 72 -------- 8 files changed, 83 insertions(+), 1124 deletions(-) create mode 100644 client/render/IFont.cpp diff --git a/client/render/CBitmapFont.cpp b/client/render/CBitmapFont.cpp index 9eb024aaf..345ed7e68 100644 --- a/client/render/CBitmapFont.cpp +++ b/client/render/CBitmapFont.cpp @@ -18,69 +18,6 @@ #include "../../lib/filesystem/Filesystem.h" #include "../../lib/CGeneralTextHandler.h" -size_t IFont::getStringWidth(const std::string & data) const -{ - size_t width = 0; - - for(size_t i=0; i & data, const SDL_Color & color, const Point & pos) const -{ - Point currPos = pos; - - for(const std::string & line : data) - { - renderTextLeft(surface, line, color, currPos); - currPos.y += (int)getLineHeight(); - } -} - -void IFont::renderTextLinesRight(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const -{ - Point currPos = pos; - currPos.y -= (int)data.size() * (int)getLineHeight(); - - for(const std::string & line : data) - { - renderTextRight(surface, line, color, currPos); - currPos.y += (int)getLineHeight(); - } -} - -void IFont::renderTextLinesCenter(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const -{ - Point currPos = pos; - currPos.y -= (int)data.size() * (int)getLineHeight() / 2; - - for(const std::string & line : data) - { - renderTextCenter(surface, line, color, currPos); - currPos.y += (int)getLineHeight(); - } -} - std::array CBitmapFont::loadChars() const { std::array ret; @@ -203,190 +140,3 @@ void CBitmapFont::renderText(SDL_Surface * surface, const std::string & data, co SDL_UnlockSurface(surface); } -std::pair, ui64> CTrueTypeFont::loadData(const JsonNode & config) -{ - std::string filename = "Data/" + config["file"].String(); - return CResourceHandler::get()->load(ResourceID(filename, EResType::TTF_FONT))->readAll(); -} - -TTF_Font * CTrueTypeFont::loadFont(const JsonNode &config) -{ - int pointSize = static_cast(config["size"].Float()); - - if(!TTF_WasInit() && TTF_Init()==-1) - throw std::runtime_error(std::string("Failed to initialize true type support: ") + TTF_GetError() + "\n"); - - return TTF_OpenFontRW(SDL_RWFromConstMem(data.first.get(), (int)data.second), 1, pointSize); -} - -int CTrueTypeFont::getFontStyle(const JsonNode &config) -{ - const JsonVector & names = config["style"].Vector(); - int ret = 0; - for(const JsonNode & node : names) - { - if (node.String() == "bold") - ret |= TTF_STYLE_BOLD; - else if (node.String() == "italic") - ret |= TTF_STYLE_ITALIC; - } - return ret; -} - -CTrueTypeFont::CTrueTypeFont(const JsonNode & fontConfig): - data(loadData(fontConfig)), - font(loadFont(fontConfig), TTF_CloseFont), - blended(fontConfig["blend"].Bool()) -{ - assert(font); - - TTF_SetFontStyle(font.get(), getFontStyle(fontConfig)); -} - -size_t CTrueTypeFont::getLineHeight() const -{ - return TTF_FontHeight(font.get()); -} - -size_t CTrueTypeFont::getGlyphWidth(const char *data) const -{ - return getStringWidth(std::string(data, Unicode::getCharacterSize(*data))); - /* - int advance; - TTF_GlyphMetrics(font.get(), *data, nullptr, nullptr, nullptr, nullptr, &advance); - return advance; - */ -} - -size_t CTrueTypeFont::getStringWidth(const std::string & data) const -{ - int width; - TTF_SizeUTF8(font.get(), data.c_str(), &width, nullptr); - return width; -} - -void CTrueTypeFont::renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const -{ - if (color.r != 0 && color.g != 0 && color.b != 0) // not black - add shadow - renderText(surface, data, Colors::BLACK, pos + Point(1,1)); - - if (!data.empty()) - { - SDL_Surface * rendered; - if (blended) - rendered = TTF_RenderUTF8_Blended(font.get(), data.c_str(), color); - else - rendered = TTF_RenderUTF8_Solid(font.get(), data.c_str(), color); - - assert(rendered); - - CSDL_Ext::blitSurface(rendered, surface, pos); - SDL_FreeSurface(rendered); - } -} - -size_t CBitmapHanFont::getCharacterDataOffset(size_t index) const -{ - size_t rowSize = (size + 7) / 8; // 1 bit per pixel, rounded up - size_t charSize = rowSize * size; // glyph contains "size" rows - return index * charSize; -} - -size_t CBitmapHanFont::getCharacterIndex(ui8 first, ui8 second) const -{ - if (second > 0x7f ) - second--; - - return (first - 0x81) * (12*16 - 2) + (second - 0x40); -} - -void CBitmapHanFont::renderCharacter(SDL_Surface * surface, int characterIndex, const SDL_Color & color, int &posX, int &posY) const -{ - //TODO: somewhat duplicated with CBitmapFont::renderCharacter(); - Rect clipRect; - CSDL_Ext::getClipRect(surface, clipRect); - - CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface, 0); - uint8_t bpp = surface->format->BytesPerPixel; - - // start of line, may differ from 0 due to end of surface or clipped surface - int lineBegin = std::max(0, clipRect.y - posY); - int lineEnd = std::min((int)size, clipRect.y + clipRect.h - posY); - - // start end end of each row, may differ from 0 - int rowBegin = std::max(0, clipRect.x - posX); - int rowEnd = std::min((int)size, clipRect.x + clipRect.w - posX); - - //for each line in symbol - for(int dy = lineBegin; dy pixels; - uint8_t *source = data.first.get() + getCharacterDataOffset(characterIndex); - - // shift source\destination pixels to current position - dstLine += (posY+dy) * surface->pitch + posX * bpp; - source += ((size + 7) / 8) * dy; - - //for each column in line - for(int dx = rowBegin; dx < rowEnd; dx++) - { - // select current bit in bitmap - int bit = (source[dx / 8] << (dx % 8)) & 0x80; - - uint8_t* dstPixel = dstLine + dx*bpp; - if (bit != 0) - colorPutter(dstPixel, color.r, color.g, color.b); - } - } - posX += (int)size + 1; -} - -void CBitmapHanFont::renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const -{ - int posX = pos.x; - int posY = pos.y; - - SDL_LockSurface(surface); - - for(size_t i=0; irenderCharacter(surface, fallback->chars[ui8(localChar[0])], color, posX, posY); - - if (localChar.size() == 2) - renderCharacter(surface, (int)getCharacterIndex(localChar[0], localChar[1]), color, posX, posY); - } - SDL_UnlockSurface(surface); -} - -CBitmapHanFont::CBitmapHanFont(const JsonNode &config): - fallback(new CBitmapFont(config["fallback"].String())), - data(CResourceHandler::get()->load(ResourceID("data/" + config["name"].String(), EResType::OTHER))->readAll()), - size((size_t)config["size"].Float()) -{ - // basic tests to make sure that fonts are OK - // 1) fonts must contain 190 "sections", 126 symbols each. - assert(getCharacterIndex(0xfe, 0xff) == 190*126); - // 2) ensure that font size is correct - enough to fit all possible symbols - assert(getCharacterDataOffset(getCharacterIndex(0xfe, 0xff)) == data.second); -} - -size_t CBitmapHanFont::getLineHeight() const -{ - return std::max(size + 1, fallback->getLineHeight()); -} - -size_t CBitmapHanFont::getGlyphWidth(const char * data) const -{ - std::string localChar = Unicode::fromUnicode(std::string(data, Unicode::getCharacterSize(data[0]))); - - if (localChar.size() == 1) - return fallback->getGlyphWidth(data); - - if (localChar.size() == 2) - return size + 1; - - return 0; -} diff --git a/client/render/CBitmapFont.h b/client/render/CBitmapFont.h index 2811a79a3..c4b608a6b 100644 --- a/client/render/CBitmapFont.h +++ b/client/render/CBitmapFont.h @@ -24,44 +24,6 @@ typedef struct _TTF_Font TTF_Font; class CBitmapFont; class CBitmapHanFont; -class IFont -{ -protected: - /// Internal function to render font, see renderTextLeft - virtual void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const = 0; - -public: - virtual ~IFont() - {} - - /// Returns height of font - virtual size_t getLineHeight() const = 0; - /// Returns width, in pixels of a character glyph. Pointer must contain at least characterSize valid bytes - virtual size_t getGlyphWidth(const char * data) const = 0; - /// Return width of the string - virtual size_t getStringWidth(const std::string & data) const; - - /** - * @param surface - destination to print text on - * @param data - string to print - * @param color - font color - * @param pos - position of rendered font - */ - /// pos = topleft corner of the text - void renderTextLeft(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const; - /// pos = center of the text - void renderTextRight(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const; - /// pos = bottomright corner of the text - void renderTextCenter(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const; - - /// pos = topleft corner of the text - void renderTextLinesLeft(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const; - /// pos = center of the text - void renderTextLinesRight(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const; - /// pos = bottomright corner of the text - void renderTextLinesCenter(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const; -}; - class CBitmapFont : public IFont { static const size_t totalChars = 256; @@ -93,44 +55,3 @@ public: friend class CBitmapHanFont; }; -/// supports multi-byte characters for such languages like Chinese -class CBitmapHanFont : public IFont -{ - std::unique_ptr fallback; - // data, directly copied from file - const std::pair, ui64> data; - - // size of the font. Not available in file but needed for proper rendering - const size_t size; - - size_t getCharacterDataOffset(size_t index) const; - size_t getCharacterIndex(ui8 first, ui8 second) const; - - void renderCharacter(SDL_Surface * surface, int characterIndex, const SDL_Color & color, int &posX, int &posY) const; - void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const override; -public: - CBitmapHanFont(const JsonNode & config); - - size_t getLineHeight() const override; - size_t getGlyphWidth(const char * data) const override; -}; - -class CTrueTypeFont : public IFont -{ - const std::pair, ui64> data; - - const std::unique_ptr font; - const bool blended; - - std::pair, ui64> loadData(const JsonNode & config); - TTF_Font * loadFont(const JsonNode & config); - int getFontStyle(const JsonNode & config); - - void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const override; -public: - CTrueTypeFont(const JsonNode & fontConfig); - - size_t getLineHeight() const override; - size_t getGlyphWidth(const char * data) const override; - size_t getStringWidth(const std::string & data) const override; -}; diff --git a/client/render/CBitmapHanFont.cpp b/client/render/CBitmapHanFont.cpp index 9eb024aaf..e474495ee 100644 --- a/client/render/CBitmapHanFont.cpp +++ b/client/render/CBitmapHanFont.cpp @@ -18,273 +18,6 @@ #include "../../lib/filesystem/Filesystem.h" #include "../../lib/CGeneralTextHandler.h" -size_t IFont::getStringWidth(const std::string & data) const -{ - size_t width = 0; - - for(size_t i=0; i & data, const SDL_Color & color, const Point & pos) const -{ - Point currPos = pos; - - for(const std::string & line : data) - { - renderTextLeft(surface, line, color, currPos); - currPos.y += (int)getLineHeight(); - } -} - -void IFont::renderTextLinesRight(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const -{ - Point currPos = pos; - currPos.y -= (int)data.size() * (int)getLineHeight(); - - for(const std::string & line : data) - { - renderTextRight(surface, line, color, currPos); - currPos.y += (int)getLineHeight(); - } -} - -void IFont::renderTextLinesCenter(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const -{ - Point currPos = pos; - currPos.y -= (int)data.size() * (int)getLineHeight() / 2; - - for(const std::string & line : data) - { - renderTextCenter(surface, line, color, currPos); - currPos.y += (int)getLineHeight(); - } -} - -std::array CBitmapFont::loadChars() const -{ - std::array ret; - - size_t offset = 32; - - for (auto & elem : ret) - { - elem.leftOffset = read_le_u32(data.first.get() + offset); offset+=4; - elem.width = read_le_u32(data.first.get() + offset); offset+=4; - elem.rightOffset = read_le_u32(data.first.get() + offset); offset+=4; - } - - for (auto & elem : ret) - { - int pixelOffset = read_le_u32(data.first.get() + offset); offset+=4; - elem.pixels = data.first.get() + 4128 + pixelOffset; - - assert(pixelOffset + 4128 < data.second); - } - return ret; -} - -CBitmapFont::CBitmapFont(const std::string & filename): - data(CResourceHandler::get()->load(ResourceID("data/" + filename, EResType::BMP_FONT))->readAll()), - chars(loadChars()), - height(data.first.get()[5]) -{} - -size_t CBitmapFont::getLineHeight() const -{ - return height; -} - -size_t CBitmapFont::getGlyphWidth(const char * data) const -{ - std::string localChar = Unicode::fromUnicode(std::string(data, Unicode::getCharacterSize(data[0]))); - - if (localChar.size() == 1) - { - const BitmapChar & ch = chars[ui8(localChar[0])]; - return ch.leftOffset + ch.width + ch.rightOffset; - } - return 0; -} - -void CBitmapFont::renderCharacter(SDL_Surface * surface, const BitmapChar & character, const SDL_Color & color, int &posX, int &posY) const -{ - Rect clipRect; - CSDL_Ext::getClipRect(surface, clipRect); - - posX += character.leftOffset; - - CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface, 0); - - uint8_t bpp = surface->format->BytesPerPixel; - - // start of line, may differ from 0 due to end of surface or clipped surface - int lineBegin = std::max(0, clipRect.y - posY); - int lineEnd = std::min(height, clipRect.y + clipRect.h - posY - 1); - - // start end end of each row, may differ from 0 - int rowBegin = std::max(0, clipRect.x - posX); - int rowEnd = std::min(character.width, clipRect.x + clipRect.w - posX - 1); - - //for each line in symbol - for(int dy = lineBegin; dy pixels; - uint8_t *srcLine = character.pixels; - - // shift source\destination pixels to current position - dstLine += (posY+dy) * surface->pitch + posX * bpp; - srcLine += dy * character.width; - - //for each column in line - for(int dx = rowBegin; dx < rowEnd; dx++) - { - uint8_t* dstPixel = dstLine + dx*bpp; - switch(srcLine[dx]) - { - case 1: //black "shadow" - colorPutter(dstPixel, 0, 0, 0); - break; - case 255: //text colour - colorPutter(dstPixel, color.r, color.g, color.b); - break; - default : - break; //transparency - } - } - } - posX += character.width; - posX += character.rightOffset; -} - -void CBitmapFont::renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const -{ - if (data.empty()) - return; - - assert(surface); - - int posX = pos.x; - int posY = pos.y; - - // Should be used to detect incorrect text parsing. Disabled right now due to some old UI code (mostly pregame and battles) - //assert(data[0] != '{'); - //assert(data[data.size()-1] != '}'); - - SDL_LockSurface(surface); - - for(size_t i=0; i, ui64> CTrueTypeFont::loadData(const JsonNode & config) -{ - std::string filename = "Data/" + config["file"].String(); - return CResourceHandler::get()->load(ResourceID(filename, EResType::TTF_FONT))->readAll(); -} - -TTF_Font * CTrueTypeFont::loadFont(const JsonNode &config) -{ - int pointSize = static_cast(config["size"].Float()); - - if(!TTF_WasInit() && TTF_Init()==-1) - throw std::runtime_error(std::string("Failed to initialize true type support: ") + TTF_GetError() + "\n"); - - return TTF_OpenFontRW(SDL_RWFromConstMem(data.first.get(), (int)data.second), 1, pointSize); -} - -int CTrueTypeFont::getFontStyle(const JsonNode &config) -{ - const JsonVector & names = config["style"].Vector(); - int ret = 0; - for(const JsonNode & node : names) - { - if (node.String() == "bold") - ret |= TTF_STYLE_BOLD; - else if (node.String() == "italic") - ret |= TTF_STYLE_ITALIC; - } - return ret; -} - -CTrueTypeFont::CTrueTypeFont(const JsonNode & fontConfig): - data(loadData(fontConfig)), - font(loadFont(fontConfig), TTF_CloseFont), - blended(fontConfig["blend"].Bool()) -{ - assert(font); - - TTF_SetFontStyle(font.get(), getFontStyle(fontConfig)); -} - -size_t CTrueTypeFont::getLineHeight() const -{ - return TTF_FontHeight(font.get()); -} - -size_t CTrueTypeFont::getGlyphWidth(const char *data) const -{ - return getStringWidth(std::string(data, Unicode::getCharacterSize(*data))); - /* - int advance; - TTF_GlyphMetrics(font.get(), *data, nullptr, nullptr, nullptr, nullptr, &advance); - return advance; - */ -} - -size_t CTrueTypeFont::getStringWidth(const std::string & data) const -{ - int width; - TTF_SizeUTF8(font.get(), data.c_str(), &width, nullptr); - return width; -} - -void CTrueTypeFont::renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const -{ - if (color.r != 0 && color.g != 0 && color.b != 0) // not black - add shadow - renderText(surface, data, Colors::BLACK, pos + Point(1,1)); - - if (!data.empty()) - { - SDL_Surface * rendered; - if (blended) - rendered = TTF_RenderUTF8_Blended(font.get(), data.c_str(), color); - else - rendered = TTF_RenderUTF8_Solid(font.get(), data.c_str(), color); - - assert(rendered); - - CSDL_Ext::blitSurface(rendered, surface, pos); - SDL_FreeSurface(rendered); - } -} - size_t CBitmapHanFont::getCharacterDataOffset(size_t index) const { size_t rowSize = (size + 7) / 8; // 1 bit per pixel, rounded up diff --git a/client/render/CBitmapHanFont.h b/client/render/CBitmapHanFont.h index 2811a79a3..605415f91 100644 --- a/client/render/CBitmapHanFont.h +++ b/client/render/CBitmapHanFont.h @@ -24,75 +24,6 @@ typedef struct _TTF_Font TTF_Font; class CBitmapFont; class CBitmapHanFont; -class IFont -{ -protected: - /// Internal function to render font, see renderTextLeft - virtual void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const = 0; - -public: - virtual ~IFont() - {} - - /// Returns height of font - virtual size_t getLineHeight() const = 0; - /// Returns width, in pixels of a character glyph. Pointer must contain at least characterSize valid bytes - virtual size_t getGlyphWidth(const char * data) const = 0; - /// Return width of the string - virtual size_t getStringWidth(const std::string & data) const; - - /** - * @param surface - destination to print text on - * @param data - string to print - * @param color - font color - * @param pos - position of rendered font - */ - /// pos = topleft corner of the text - void renderTextLeft(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const; - /// pos = center of the text - void renderTextRight(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const; - /// pos = bottomright corner of the text - void renderTextCenter(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const; - - /// pos = topleft corner of the text - void renderTextLinesLeft(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const; - /// pos = center of the text - void renderTextLinesRight(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const; - /// pos = bottomright corner of the text - void renderTextLinesCenter(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const; -}; - -class CBitmapFont : public IFont -{ - static const size_t totalChars = 256; - - struct BitmapChar - { - si32 leftOffset; - ui32 width; - si32 rightOffset; - ui8 *pixels; // pixels of this character, part of BitmapFont::data - }; - - const std::pair, ui64> data; - - const std::array chars; - const ui8 height; - - std::array loadChars() const; - - void renderCharacter(SDL_Surface * surface, const BitmapChar & character, const SDL_Color & color, int &posX, int &posY) const; - - void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const override; -public: - CBitmapFont(const std::string & filename); - - size_t getLineHeight() const override; - size_t getGlyphWidth(const char * data) const override; - - friend class CBitmapHanFont; -}; - /// supports multi-byte characters for such languages like Chinese class CBitmapHanFont : public IFont { diff --git a/client/render/CTrueTypeFont.cpp b/client/render/CTrueTypeFont.cpp index 9eb024aaf..5b1f2ad4f 100644 --- a/client/render/CTrueTypeFont.cpp +++ b/client/render/CTrueTypeFont.cpp @@ -18,197 +18,6 @@ #include "../../lib/filesystem/Filesystem.h" #include "../../lib/CGeneralTextHandler.h" -size_t IFont::getStringWidth(const std::string & data) const -{ - size_t width = 0; - - for(size_t i=0; i & data, const SDL_Color & color, const Point & pos) const -{ - Point currPos = pos; - - for(const std::string & line : data) - { - renderTextLeft(surface, line, color, currPos); - currPos.y += (int)getLineHeight(); - } -} - -void IFont::renderTextLinesRight(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const -{ - Point currPos = pos; - currPos.y -= (int)data.size() * (int)getLineHeight(); - - for(const std::string & line : data) - { - renderTextRight(surface, line, color, currPos); - currPos.y += (int)getLineHeight(); - } -} - -void IFont::renderTextLinesCenter(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const -{ - Point currPos = pos; - currPos.y -= (int)data.size() * (int)getLineHeight() / 2; - - for(const std::string & line : data) - { - renderTextCenter(surface, line, color, currPos); - currPos.y += (int)getLineHeight(); - } -} - -std::array CBitmapFont::loadChars() const -{ - std::array ret; - - size_t offset = 32; - - for (auto & elem : ret) - { - elem.leftOffset = read_le_u32(data.first.get() + offset); offset+=4; - elem.width = read_le_u32(data.first.get() + offset); offset+=4; - elem.rightOffset = read_le_u32(data.first.get() + offset); offset+=4; - } - - for (auto & elem : ret) - { - int pixelOffset = read_le_u32(data.first.get() + offset); offset+=4; - elem.pixels = data.first.get() + 4128 + pixelOffset; - - assert(pixelOffset + 4128 < data.second); - } - return ret; -} - -CBitmapFont::CBitmapFont(const std::string & filename): - data(CResourceHandler::get()->load(ResourceID("data/" + filename, EResType::BMP_FONT))->readAll()), - chars(loadChars()), - height(data.first.get()[5]) -{} - -size_t CBitmapFont::getLineHeight() const -{ - return height; -} - -size_t CBitmapFont::getGlyphWidth(const char * data) const -{ - std::string localChar = Unicode::fromUnicode(std::string(data, Unicode::getCharacterSize(data[0]))); - - if (localChar.size() == 1) - { - const BitmapChar & ch = chars[ui8(localChar[0])]; - return ch.leftOffset + ch.width + ch.rightOffset; - } - return 0; -} - -void CBitmapFont::renderCharacter(SDL_Surface * surface, const BitmapChar & character, const SDL_Color & color, int &posX, int &posY) const -{ - Rect clipRect; - CSDL_Ext::getClipRect(surface, clipRect); - - posX += character.leftOffset; - - CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface, 0); - - uint8_t bpp = surface->format->BytesPerPixel; - - // start of line, may differ from 0 due to end of surface or clipped surface - int lineBegin = std::max(0, clipRect.y - posY); - int lineEnd = std::min(height, clipRect.y + clipRect.h - posY - 1); - - // start end end of each row, may differ from 0 - int rowBegin = std::max(0, clipRect.x - posX); - int rowEnd = std::min(character.width, clipRect.x + clipRect.w - posX - 1); - - //for each line in symbol - for(int dy = lineBegin; dy pixels; - uint8_t *srcLine = character.pixels; - - // shift source\destination pixels to current position - dstLine += (posY+dy) * surface->pitch + posX * bpp; - srcLine += dy * character.width; - - //for each column in line - for(int dx = rowBegin; dx < rowEnd; dx++) - { - uint8_t* dstPixel = dstLine + dx*bpp; - switch(srcLine[dx]) - { - case 1: //black "shadow" - colorPutter(dstPixel, 0, 0, 0); - break; - case 255: //text colour - colorPutter(dstPixel, color.r, color.g, color.b); - break; - default : - break; //transparency - } - } - } - posX += character.width; - posX += character.rightOffset; -} - -void CBitmapFont::renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const -{ - if (data.empty()) - return; - - assert(surface); - - int posX = pos.x; - int posY = pos.y; - - // Should be used to detect incorrect text parsing. Disabled right now due to some old UI code (mostly pregame and battles) - //assert(data[0] != '{'); - //assert(data[data.size()-1] != '}'); - - SDL_LockSurface(surface); - - for(size_t i=0; i, ui64> CTrueTypeFont::loadData(const JsonNode & config) -{ - std::string filename = "Data/" + config["file"].String(); - return CResourceHandler::get()->load(ResourceID(filename, EResType::TTF_FONT))->readAll(); -} - TTF_Font * CTrueTypeFont::loadFont(const JsonNode &config) { int pointSize = static_cast(config["size"].Float()); @@ -285,108 +94,3 @@ void CTrueTypeFont::renderText(SDL_Surface * surface, const std::string & data, } } -size_t CBitmapHanFont::getCharacterDataOffset(size_t index) const -{ - size_t rowSize = (size + 7) / 8; // 1 bit per pixel, rounded up - size_t charSize = rowSize * size; // glyph contains "size" rows - return index * charSize; -} - -size_t CBitmapHanFont::getCharacterIndex(ui8 first, ui8 second) const -{ - if (second > 0x7f ) - second--; - - return (first - 0x81) * (12*16 - 2) + (second - 0x40); -} - -void CBitmapHanFont::renderCharacter(SDL_Surface * surface, int characterIndex, const SDL_Color & color, int &posX, int &posY) const -{ - //TODO: somewhat duplicated with CBitmapFont::renderCharacter(); - Rect clipRect; - CSDL_Ext::getClipRect(surface, clipRect); - - CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface, 0); - uint8_t bpp = surface->format->BytesPerPixel; - - // start of line, may differ from 0 due to end of surface or clipped surface - int lineBegin = std::max(0, clipRect.y - posY); - int lineEnd = std::min((int)size, clipRect.y + clipRect.h - posY); - - // start end end of each row, may differ from 0 - int rowBegin = std::max(0, clipRect.x - posX); - int rowEnd = std::min((int)size, clipRect.x + clipRect.w - posX); - - //for each line in symbol - for(int dy = lineBegin; dy pixels; - uint8_t *source = data.first.get() + getCharacterDataOffset(characterIndex); - - // shift source\destination pixels to current position - dstLine += (posY+dy) * surface->pitch + posX * bpp; - source += ((size + 7) / 8) * dy; - - //for each column in line - for(int dx = rowBegin; dx < rowEnd; dx++) - { - // select current bit in bitmap - int bit = (source[dx / 8] << (dx % 8)) & 0x80; - - uint8_t* dstPixel = dstLine + dx*bpp; - if (bit != 0) - colorPutter(dstPixel, color.r, color.g, color.b); - } - } - posX += (int)size + 1; -} - -void CBitmapHanFont::renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const -{ - int posX = pos.x; - int posY = pos.y; - - SDL_LockSurface(surface); - - for(size_t i=0; irenderCharacter(surface, fallback->chars[ui8(localChar[0])], color, posX, posY); - - if (localChar.size() == 2) - renderCharacter(surface, (int)getCharacterIndex(localChar[0], localChar[1]), color, posX, posY); - } - SDL_UnlockSurface(surface); -} - -CBitmapHanFont::CBitmapHanFont(const JsonNode &config): - fallback(new CBitmapFont(config["fallback"].String())), - data(CResourceHandler::get()->load(ResourceID("data/" + config["name"].String(), EResType::OTHER))->readAll()), - size((size_t)config["size"].Float()) -{ - // basic tests to make sure that fonts are OK - // 1) fonts must contain 190 "sections", 126 symbols each. - assert(getCharacterIndex(0xfe, 0xff) == 190*126); - // 2) ensure that font size is correct - enough to fit all possible symbols - assert(getCharacterDataOffset(getCharacterIndex(0xfe, 0xff)) == data.second); -} - -size_t CBitmapHanFont::getLineHeight() const -{ - return std::max(size + 1, fallback->getLineHeight()); -} - -size_t CBitmapHanFont::getGlyphWidth(const char * data) const -{ - std::string localChar = Unicode::fromUnicode(std::string(data, Unicode::getCharacterSize(data[0]))); - - if (localChar.size() == 1) - return fallback->getGlyphWidth(data); - - if (localChar.size() == 2) - return size + 1; - - return 0; -} diff --git a/client/render/CTrueTypeFont.h b/client/render/CTrueTypeFont.h index 2811a79a3..d4b67710a 100644 --- a/client/render/CTrueTypeFont.h +++ b/client/render/CTrueTypeFont.h @@ -24,97 +24,6 @@ typedef struct _TTF_Font TTF_Font; class CBitmapFont; class CBitmapHanFont; -class IFont -{ -protected: - /// Internal function to render font, see renderTextLeft - virtual void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const = 0; - -public: - virtual ~IFont() - {} - - /// Returns height of font - virtual size_t getLineHeight() const = 0; - /// Returns width, in pixels of a character glyph. Pointer must contain at least characterSize valid bytes - virtual size_t getGlyphWidth(const char * data) const = 0; - /// Return width of the string - virtual size_t getStringWidth(const std::string & data) const; - - /** - * @param surface - destination to print text on - * @param data - string to print - * @param color - font color - * @param pos - position of rendered font - */ - /// pos = topleft corner of the text - void renderTextLeft(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const; - /// pos = center of the text - void renderTextRight(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const; - /// pos = bottomright corner of the text - void renderTextCenter(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const; - - /// pos = topleft corner of the text - void renderTextLinesLeft(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const; - /// pos = center of the text - void renderTextLinesRight(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const; - /// pos = bottomright corner of the text - void renderTextLinesCenter(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const; -}; - -class CBitmapFont : public IFont -{ - static const size_t totalChars = 256; - - struct BitmapChar - { - si32 leftOffset; - ui32 width; - si32 rightOffset; - ui8 *pixels; // pixels of this character, part of BitmapFont::data - }; - - const std::pair, ui64> data; - - const std::array chars; - const ui8 height; - - std::array loadChars() const; - - void renderCharacter(SDL_Surface * surface, const BitmapChar & character, const SDL_Color & color, int &posX, int &posY) const; - - void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const override; -public: - CBitmapFont(const std::string & filename); - - size_t getLineHeight() const override; - size_t getGlyphWidth(const char * data) const override; - - friend class CBitmapHanFont; -}; - -/// supports multi-byte characters for such languages like Chinese -class CBitmapHanFont : public IFont -{ - std::unique_ptr fallback; - // data, directly copied from file - const std::pair, ui64> data; - - // size of the font. Not available in file but needed for proper rendering - const size_t size; - - size_t getCharacterDataOffset(size_t index) const; - size_t getCharacterIndex(ui8 first, ui8 second) const; - - void renderCharacter(SDL_Surface * surface, int characterIndex, const SDL_Color & color, int &posX, int &posY) const; - void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const override; -public: - CBitmapHanFont(const JsonNode & config); - - size_t getLineHeight() const override; - size_t getGlyphWidth(const char * data) const override; -}; - class CTrueTypeFont : public IFont { const std::pair, ui64> data; diff --git a/client/render/IFont.cpp b/client/render/IFont.cpp new file mode 100644 index 000000000..5c99bf020 --- /dev/null +++ b/client/render/IFont.cpp @@ -0,0 +1,83 @@ +/* + * Fonts.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#include "StdInc.h" +#include "Fonts.h" + +#include + +#include "SDL_Extensions.h" +#include "../../lib/JsonNode.h" +#include "../../lib/vcmi_endian.h" +#include "../../lib/filesystem/Filesystem.h" +#include "../../lib/CGeneralTextHandler.h" + +size_t IFont::getStringWidth(const std::string & data) const +{ + size_t width = 0; + + for(size_t i=0; i & data, const SDL_Color & color, const Point & pos) const +{ + Point currPos = pos; + + for(const std::string & line : data) + { + renderTextLeft(surface, line, color, currPos); + currPos.y += (int)getLineHeight(); + } +} + +void IFont::renderTextLinesRight(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const +{ + Point currPos = pos; + currPos.y -= (int)data.size() * (int)getLineHeight(); + + for(const std::string & line : data) + { + renderTextRight(surface, line, color, currPos); + currPos.y += (int)getLineHeight(); + } +} + +void IFont::renderTextLinesCenter(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const +{ + Point currPos = pos; + currPos.y -= (int)data.size() * (int)getLineHeight() / 2; + + for(const std::string & line : data) + { + renderTextCenter(surface, line, color, currPos); + currPos.y += (int)getLineHeight(); + } +} + diff --git a/client/render/IFont.h b/client/render/IFont.h index 2811a79a3..a73c81b1c 100644 --- a/client/render/IFont.h +++ b/client/render/IFont.h @@ -62,75 +62,3 @@ public: void renderTextLinesCenter(SDL_Surface * surface, const std::vector & data, const SDL_Color & color, const Point & pos) const; }; -class CBitmapFont : public IFont -{ - static const size_t totalChars = 256; - - struct BitmapChar - { - si32 leftOffset; - ui32 width; - si32 rightOffset; - ui8 *pixels; // pixels of this character, part of BitmapFont::data - }; - - const std::pair, ui64> data; - - const std::array chars; - const ui8 height; - - std::array loadChars() const; - - void renderCharacter(SDL_Surface * surface, const BitmapChar & character, const SDL_Color & color, int &posX, int &posY) const; - - void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const override; -public: - CBitmapFont(const std::string & filename); - - size_t getLineHeight() const override; - size_t getGlyphWidth(const char * data) const override; - - friend class CBitmapHanFont; -}; - -/// supports multi-byte characters for such languages like Chinese -class CBitmapHanFont : public IFont -{ - std::unique_ptr fallback; - // data, directly copied from file - const std::pair, ui64> data; - - // size of the font. Not available in file but needed for proper rendering - const size_t size; - - size_t getCharacterDataOffset(size_t index) const; - size_t getCharacterIndex(ui8 first, ui8 second) const; - - void renderCharacter(SDL_Surface * surface, int characterIndex, const SDL_Color & color, int &posX, int &posY) const; - void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const override; -public: - CBitmapHanFont(const JsonNode & config); - - size_t getLineHeight() const override; - size_t getGlyphWidth(const char * data) const override; -}; - -class CTrueTypeFont : public IFont -{ - const std::pair, ui64> data; - - const std::unique_ptr font; - const bool blended; - - std::pair, ui64> loadData(const JsonNode & config); - TTF_Font * loadFont(const JsonNode & config); - int getFontStyle(const JsonNode & config); - - void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const override; -public: - CTrueTypeFont(const JsonNode & fontConfig); - - size_t getLineHeight() const override; - size_t getGlyphWidth(const char * data) const override; - size_t getStringWidth(const std::string & data) const override; -}; From 67e7731752255a0e27c69837401ca0d4f3b9ba5a Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:45:22 +0200 Subject: [PATCH 63/79] Split ICursor into a new file --- client/gui/{CursorHandler.h => ICursor.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename client/gui/{CursorHandler.h => ICursor.h} (100%) diff --git a/client/gui/CursorHandler.h b/client/gui/ICursor.h similarity index 100% rename from client/gui/CursorHandler.h rename to client/gui/ICursor.h From 418fd1491bec1ed2371ae0b3006e818f18a00958 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:48:06 +0200 Subject: [PATCH 64/79] Split CursorHardware into a new file --- client/gui/{CursorHandler.cpp => CursorHardware.cpp} | 0 client/gui/{CursorHandler.h => CursorHardware.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/gui/{CursorHandler.cpp => CursorHardware.cpp} (100%) rename client/gui/{CursorHandler.h => CursorHardware.h} (100%) diff --git a/client/gui/CursorHandler.cpp b/client/gui/CursorHardware.cpp similarity index 100% rename from client/gui/CursorHandler.cpp rename to client/gui/CursorHardware.cpp diff --git a/client/gui/CursorHandler.h b/client/gui/CursorHardware.h similarity index 100% rename from client/gui/CursorHandler.h rename to client/gui/CursorHardware.h From bdc2d0c92018a9f75f2518e485aac52b87e9d259 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:48:59 +0200 Subject: [PATCH 65/79] Split CursorSoftware into a new file --- client/gui/{CursorHandler.cpp => CursorSoftware.cpp} | 0 client/gui/{CursorHandler.h => CursorSoftware.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/gui/{CursorHandler.cpp => CursorSoftware.cpp} (100%) rename client/gui/{CursorHandler.h => CursorSoftware.h} (100%) diff --git a/client/gui/CursorHandler.cpp b/client/gui/CursorSoftware.cpp similarity index 100% rename from client/gui/CursorHandler.cpp rename to client/gui/CursorSoftware.cpp diff --git a/client/gui/CursorHandler.h b/client/gui/CursorSoftware.h similarity index 100% rename from client/gui/CursorHandler.h rename to client/gui/CursorSoftware.h From 769d4b3bfb668cde82eefb7a20797521c78050c9 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:50:12 +0200 Subject: [PATCH 66/79] temporary rename --- client/gui/{CursorHandler.cpp => CursorHandlerBase.cpp} | 0 client/gui/{CursorHandler.h => CursorHandlerBase.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/gui/{CursorHandler.cpp => CursorHandlerBase.cpp} (100%) rename client/gui/{CursorHandler.h => CursorHandlerBase.h} (100%) diff --git a/client/gui/CursorHandler.cpp b/client/gui/CursorHandlerBase.cpp similarity index 100% rename from client/gui/CursorHandler.cpp rename to client/gui/CursorHandlerBase.cpp diff --git a/client/gui/CursorHandler.h b/client/gui/CursorHandlerBase.h similarity index 100% rename from client/gui/CursorHandler.h rename to client/gui/CursorHandlerBase.h From dfbcfb7b3c5f85995cac0f5d1d54cdf992a0827f Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:56:44 +0200 Subject: [PATCH 67/79] Remove duplicated code from new files --- client/gui/CursorHandlerBase.cpp | 145 ------------ client/gui/CursorHandlerBase.h | 51 ----- client/gui/CursorHardware.cpp | 371 ------------------------------- client/gui/CursorHardware.h | 202 ----------------- client/gui/CursorSoftware.cpp | 350 ----------------------------- client/gui/CursorSoftware.h | 194 ---------------- client/gui/ICursor.h | 207 ----------------- 7 files changed, 1520 deletions(-) diff --git a/client/gui/CursorHandlerBase.cpp b/client/gui/CursorHandlerBase.cpp index b44cb3040..4d1760f7a 100644 --- a/client/gui/CursorHandlerBase.cpp +++ b/client/gui/CursorHandlerBase.cpp @@ -311,148 +311,3 @@ void CursorHandler::show() cursor->setVisible(true); } -void CursorSoftware::render() -{ - //texture must be updated in the main (renderer) thread, but changes to cursor type may come from other threads - if (needUpdate) - updateTexture(); - - Point renderPos = pos - pivot; - - SDL_Rect destRect; - destRect.x = renderPos.x; - destRect.y = renderPos.y; - destRect.w = 40; - destRect.h = 40; - - SDL_RenderCopy(mainRenderer, cursorTexture, nullptr, &destRect); -} - -void CursorSoftware::createTexture(const Point & dimensions) -{ - if(cursorTexture) - SDL_DestroyTexture(cursorTexture); - - if (cursorSurface) - SDL_FreeSurface(cursorSurface); - - cursorSurface = CSDL_Ext::newSurface(dimensions.x, dimensions.y); - cursorTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, dimensions.x, dimensions.y); - - SDL_SetSurfaceBlendMode(cursorSurface, SDL_BLENDMODE_NONE); - SDL_SetTextureBlendMode(cursorTexture, SDL_BLENDMODE_BLEND); -} - -void CursorSoftware::updateTexture() -{ - Point dimensions(-1, -1); - - if (!cursorSurface || Point(cursorSurface->w, cursorSurface->h) != cursorImage->dimensions()) - createTexture(cursorImage->dimensions()); - - CSDL_Ext::fillSurface(cursorSurface, Colors::TRANSPARENCY); - - cursorImage->draw(cursorSurface); - SDL_UpdateTexture(cursorTexture, NULL, cursorSurface->pixels, cursorSurface->pitch); - needUpdate = false; -} - -void CursorSoftware::setImage(std::shared_ptr image, const Point & pivotOffset) -{ - assert(image != nullptr); - cursorImage = image; - pivot = pivotOffset; - needUpdate = true; -} - -void CursorSoftware::setCursorPosition( const Point & newPos ) -{ - pos = newPos; -} - -void CursorSoftware::setVisible(bool on) -{ - visible = on; -} - -CursorSoftware::CursorSoftware(): - cursorTexture(nullptr), - cursorSurface(nullptr), - needUpdate(false), - visible(false), - pivot(0,0) -{ - SDL_ShowCursor(SDL_DISABLE); -} - -CursorSoftware::~CursorSoftware() -{ - if(cursorTexture) - SDL_DestroyTexture(cursorTexture); - - if (cursorSurface) - SDL_FreeSurface(cursorSurface); -} - -CursorHardware::CursorHardware(): - cursor(nullptr) -{ - SDL_ShowCursor(SDL_DISABLE); -} - -CursorHardware::~CursorHardware() -{ - if(cursor) - SDL_FreeCursor(cursor); -} - -void CursorHardware::setVisible(bool on) -{ -#ifdef VCMI_APPLE - dispatch_async(dispatch_get_main_queue(), ^{ -#endif - if (on) - SDL_ShowCursor(SDL_ENABLE); - else - SDL_ShowCursor(SDL_DISABLE); -#ifdef VCMI_APPLE - }); -#endif -} - -void CursorHardware::setImage(std::shared_ptr image, const Point & pivotOffset) -{ - auto cursorSurface = CSDL_Ext::newSurface(image->dimensions().x, image->dimensions().y); - - CSDL_Ext::fillSurface(cursorSurface, Colors::TRANSPARENCY); - - image->draw(cursorSurface); - - auto oldCursor = cursor; - cursor = SDL_CreateColorCursor(cursorSurface, pivotOffset.x, pivotOffset.y); - - if (!cursor) - logGlobal->error("Failed to set cursor! SDL says %s", SDL_GetError()); - - SDL_FreeSurface(cursorSurface); -#ifdef VCMI_APPLE - dispatch_async(dispatch_get_main_queue(), ^{ -#endif - SDL_SetCursor(cursor); - - if (oldCursor) - SDL_FreeCursor(oldCursor); -#ifdef VCMI_APPLE - }); -#endif -} - -void CursorHardware::setCursorPosition( const Point & newPos ) -{ - //no-op -} - -void CursorHardware::render() -{ - //no-op -} diff --git a/client/gui/CursorHandlerBase.h b/client/gui/CursorHandlerBase.h index b66bfb92b..807f90164 100644 --- a/client/gui/CursorHandlerBase.h +++ b/client/gui/CursorHandlerBase.h @@ -112,57 +112,6 @@ namespace Cursor }; } -class ICursor -{ -public: - virtual ~ICursor() = default; - - virtual void setImage(std::shared_ptr image, const Point & pivotOffset) = 0; - virtual void setCursorPosition( const Point & newPos ) = 0; - virtual void render() = 0; - virtual void setVisible( bool on) = 0; -}; - -class CursorHardware : public ICursor -{ - std::shared_ptr cursorImage; - - SDL_Cursor * cursor; - -public: - CursorHardware(); - ~CursorHardware(); - - void setImage(std::shared_ptr image, const Point & pivotOffset) override; - void setCursorPosition( const Point & newPos ) override; - void render() override; - void setVisible( bool on) override; -}; - -class CursorSoftware : public ICursor -{ - std::shared_ptr cursorImage; - - SDL_Texture * cursorTexture; - SDL_Surface * cursorSurface; - - Point pos; - Point pivot; - bool needUpdate; - bool visible; - - void createTexture(const Point & dimensions); - void updateTexture(); -public: - CursorSoftware(); - ~CursorSoftware(); - - void setImage(std::shared_ptr image, const Point & pivotOffset) override; - void setCursorPosition( const Point & newPos ) override; - void render() override; - void setVisible( bool on) override; -}; - /// handles mouse cursor class CursorHandler final { diff --git a/client/gui/CursorHardware.cpp b/client/gui/CursorHardware.cpp index b44cb3040..a426f06a7 100644 --- a/client/gui/CursorHardware.cpp +++ b/client/gui/CursorHardware.cpp @@ -23,377 +23,6 @@ #include #endif -std::unique_ptr CursorHandler::createCursor() -{ - if (settings["video"]["cursor"].String() == "auto") - { -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - return std::make_unique(); -#else - return std::make_unique(); -#endif - } - - if (settings["video"]["cursor"].String() == "hardware") - return std::make_unique(); - - assert(settings["video"]["cursor"].String() == "software"); - return std::make_unique(); -} - -CursorHandler::CursorHandler() - : cursor(createCursor()) - , frameTime(0.f) - , showing(false) - , pos(0,0) -{ - - type = Cursor::Type::DEFAULT; - dndObject = nullptr; - - cursors = - { - std::make_unique("CRADVNTR"), - std::make_unique("CRCOMBAT"), - std::make_unique("CRDEFLT"), - std::make_unique("CRSPELL") - }; - - for (auto & cursor : cursors) - cursor->preload(); - - set(Cursor::Map::POINTER); -} - -Point CursorHandler::position() const -{ - return pos; -} - -void CursorHandler::changeGraphic(Cursor::Type type, size_t index) -{ - assert(dndObject == nullptr); - - if (type == this->type && index == this->frame) - return; - - this->type = type; - this->frame = index; - - cursor->setImage(getCurrentImage(), getPivotOffset()); -} - -void CursorHandler::set(Cursor::Default index) -{ - changeGraphic(Cursor::Type::DEFAULT, static_cast(index)); -} - -void CursorHandler::set(Cursor::Map index) -{ - changeGraphic(Cursor::Type::ADVENTURE, static_cast(index)); -} - -void CursorHandler::set(Cursor::Combat index) -{ - changeGraphic(Cursor::Type::COMBAT, static_cast(index)); -} - -void CursorHandler::set(Cursor::Spellcast index) -{ - //Note: this is animated cursor, ignore specified frame and only change type - changeGraphic(Cursor::Type::SPELLBOOK, frame); -} - -void CursorHandler::dragAndDropCursor(std::shared_ptr image) -{ - dndObject = image; - cursor->setImage(getCurrentImage(), getPivotOffset()); -} - -void CursorHandler::dragAndDropCursor (std::string path, size_t index) -{ - CAnimation anim(path); - anim.load(index); - dragAndDropCursor(anim.getImage(index)); -} - -void CursorHandler::cursorMove(const int & x, const int & y) -{ - pos.x = x; - pos.y = y; - - cursor->setCursorPosition(pos); -} - -Point CursorHandler::getPivotOffsetDefault(size_t index) -{ - return {0, 0}; -} - -Point CursorHandler::getPivotOffsetMap(size_t index) -{ - static const std::array offsets = {{ - { 0, 0}, // POINTER = 0, - { 0, 0}, // HOURGLASS = 1, - { 12, 10}, // HERO = 2, - { 12, 12}, // TOWN = 3, - - { 15, 13}, // T1_MOVE = 4, - { 13, 13}, // T1_ATTACK = 5, - { 16, 32}, // T1_SAIL = 6, - { 13, 20}, // T1_DISEMBARK = 7, - { 8, 9}, // T1_EXCHANGE = 8, - { 14, 16}, // T1_VISIT = 9, - - { 15, 13}, // T2_MOVE = 10, - { 13, 13}, // T2_ATTACK = 11, - { 16, 32}, // T2_SAIL = 12, - { 13, 20}, // T2_DISEMBARK = 13, - { 8, 9}, // T2_EXCHANGE = 14, - { 14, 16}, // T2_VISIT = 15, - - { 15, 13}, // T3_MOVE = 16, - { 13, 13}, // T3_ATTACK = 17, - { 16, 32}, // T3_SAIL = 18, - { 13, 20}, // T3_DISEMBARK = 19, - { 8, 9}, // T3_EXCHANGE = 20, - { 14, 16}, // T3_VISIT = 21, - - { 15, 13}, // T4_MOVE = 22, - { 13, 13}, // T4_ATTACK = 23, - { 16, 32}, // T4_SAIL = 24, - { 13, 20}, // T4_DISEMBARK = 25, - { 8, 9}, // T4_EXCHANGE = 26, - { 14, 16}, // T4_VISIT = 27, - - { 16, 32}, // T1_SAIL_VISIT = 28, - { 16, 32}, // T2_SAIL_VISIT = 29, - { 16, 32}, // T3_SAIL_VISIT = 30, - { 16, 32}, // T4_SAIL_VISIT = 31, - - { 6, 1}, // SCROLL_NORTH = 32, - { 16, 2}, // SCROLL_NORTHEAST = 33, - { 21, 6}, // SCROLL_EAST = 34, - { 16, 16}, // SCROLL_SOUTHEAST = 35, - { 6, 21}, // SCROLL_SOUTH = 36, - { 1, 16}, // SCROLL_SOUTHWEST = 37, - { 1, 5}, // SCROLL_WEST = 38, - { 2, 1}, // SCROLL_NORTHWEST = 39, - - { 0, 0}, // POINTER_COPY = 40, - { 14, 16}, // TELEPORT = 41, - { 20, 20}, // SCUTTLE_BOAT = 42 - }}; - - assert(offsets.size() == size_t(Cursor::Map::COUNT)); //Invalid number of pivot offsets for cursor - assert(index < offsets.size()); - return offsets[index]; -} - -Point CursorHandler::getPivotOffsetCombat(size_t index) -{ - static const std::array offsets = {{ - { 12, 12 }, // BLOCKED = 0, - { 10, 14 }, // MOVE = 1, - { 14, 14 }, // FLY = 2, - { 12, 12 }, // SHOOT = 3, - { 12, 12 }, // HERO = 4, - { 8, 12 }, // QUERY = 5, - { 0, 0 }, // POINTER = 6, - { 21, 0 }, // HIT_NORTHEAST = 7, - { 31, 5 }, // HIT_EAST = 8, - { 21, 21 }, // HIT_SOUTHEAST = 9, - { 0, 21 }, // HIT_SOUTHWEST = 10, - { 0, 5 }, // HIT_WEST = 11, - { 0, 0 }, // HIT_NORTHWEST = 12, - { 6, 0 }, // HIT_NORTH = 13, - { 6, 31 }, // HIT_SOUTH = 14, - { 14, 0 }, // SHOOT_PENALTY = 15, - { 12, 12 }, // SHOOT_CATAPULT = 16, - { 12, 12 }, // HEAL = 17, - { 12, 12 }, // SACRIFICE = 18, - { 14, 20 }, // TELEPORT = 19 - }}; - - assert(offsets.size() == size_t(Cursor::Combat::COUNT)); //Invalid number of pivot offsets for cursor - assert(index < offsets.size()); - return offsets[index]; -} - -Point CursorHandler::getPivotOffsetSpellcast() -{ - return { 18, 28}; -} - -Point CursorHandler::getPivotOffset() -{ - if (dndObject) - return dndObject->dimensions() / 2; - - switch (type) { - case Cursor::Type::ADVENTURE: return getPivotOffsetMap(frame); - case Cursor::Type::COMBAT: return getPivotOffsetCombat(frame); - case Cursor::Type::DEFAULT: return getPivotOffsetDefault(frame); - case Cursor::Type::SPELLBOOK: return getPivotOffsetSpellcast(); - }; - - assert(0); - return {0, 0}; -} - -std::shared_ptr CursorHandler::getCurrentImage() -{ - if (dndObject) - return dndObject; - - return cursors[static_cast(type)]->getImage(frame); -} - -void CursorHandler::centerCursor() -{ - Point screenSize {screen->w, screen->h}; - pos = screenSize / 2 - getPivotOffset(); - - SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); - CSDL_Ext::warpMouse(pos.x, pos.y); - SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE); - - cursor->setCursorPosition(pos); -} - -void CursorHandler::updateSpellcastCursor() -{ - static const float frameDisplayDuration = 0.1f; // H3 uses 100 ms per frame - - frameTime += GH.mainFPSmng->getElapsedMilliseconds() / 1000.f; - size_t newFrame = frame; - - while (frameTime >= frameDisplayDuration) - { - frameTime -= frameDisplayDuration; - newFrame++; - } - - auto & animation = cursors.at(static_cast(type)); - - while (newFrame >= animation->size()) - newFrame -= animation->size(); - - changeGraphic(Cursor::Type::SPELLBOOK, newFrame); -} - -void CursorHandler::render() -{ - if(!showing) - return; - - if (type == Cursor::Type::SPELLBOOK) - updateSpellcastCursor(); - - cursor->render(); -} - -void CursorHandler::hide() -{ - if (!showing) - return; - - showing = false; - cursor->setVisible(false); -} - -void CursorHandler::show() -{ - if (showing) - return; - - showing = true; - cursor->setVisible(true); -} - -void CursorSoftware::render() -{ - //texture must be updated in the main (renderer) thread, but changes to cursor type may come from other threads - if (needUpdate) - updateTexture(); - - Point renderPos = pos - pivot; - - SDL_Rect destRect; - destRect.x = renderPos.x; - destRect.y = renderPos.y; - destRect.w = 40; - destRect.h = 40; - - SDL_RenderCopy(mainRenderer, cursorTexture, nullptr, &destRect); -} - -void CursorSoftware::createTexture(const Point & dimensions) -{ - if(cursorTexture) - SDL_DestroyTexture(cursorTexture); - - if (cursorSurface) - SDL_FreeSurface(cursorSurface); - - cursorSurface = CSDL_Ext::newSurface(dimensions.x, dimensions.y); - cursorTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, dimensions.x, dimensions.y); - - SDL_SetSurfaceBlendMode(cursorSurface, SDL_BLENDMODE_NONE); - SDL_SetTextureBlendMode(cursorTexture, SDL_BLENDMODE_BLEND); -} - -void CursorSoftware::updateTexture() -{ - Point dimensions(-1, -1); - - if (!cursorSurface || Point(cursorSurface->w, cursorSurface->h) != cursorImage->dimensions()) - createTexture(cursorImage->dimensions()); - - CSDL_Ext::fillSurface(cursorSurface, Colors::TRANSPARENCY); - - cursorImage->draw(cursorSurface); - SDL_UpdateTexture(cursorTexture, NULL, cursorSurface->pixels, cursorSurface->pitch); - needUpdate = false; -} - -void CursorSoftware::setImage(std::shared_ptr image, const Point & pivotOffset) -{ - assert(image != nullptr); - cursorImage = image; - pivot = pivotOffset; - needUpdate = true; -} - -void CursorSoftware::setCursorPosition( const Point & newPos ) -{ - pos = newPos; -} - -void CursorSoftware::setVisible(bool on) -{ - visible = on; -} - -CursorSoftware::CursorSoftware(): - cursorTexture(nullptr), - cursorSurface(nullptr), - needUpdate(false), - visible(false), - pivot(0,0) -{ - SDL_ShowCursor(SDL_DISABLE); -} - -CursorSoftware::~CursorSoftware() -{ - if(cursorTexture) - SDL_DestroyTexture(cursorTexture); - - if (cursorSurface) - SDL_FreeSurface(cursorSurface); -} - CursorHardware::CursorHardware(): cursor(nullptr) { diff --git a/client/gui/CursorHardware.h b/client/gui/CursorHardware.h index b66bfb92b..7e299130a 100644 --- a/client/gui/CursorHardware.h +++ b/client/gui/CursorHardware.h @@ -17,112 +17,6 @@ struct SDL_Cursor; #include "../../lib/Point.h" -namespace Cursor -{ - enum class Type { - ADVENTURE, // set of various cursors for adventure map - COMBAT, // set of various cursors for combat - DEFAULT, // default arrow and hourglass cursors - SPELLBOOK // animated cursor for spellcasting - }; - - enum class Default { - POINTER = 0, - //ARROW_COPY = 1, // probably unused - HOURGLASS = 2, - }; - - enum class Combat { - INVALID = -1, - - BLOCKED = 0, - MOVE = 1, - FLY = 2, - SHOOT = 3, - HERO = 4, - QUERY = 5, - POINTER = 6, - HIT_NORTHEAST = 7, - HIT_EAST = 8, - HIT_SOUTHEAST = 9, - HIT_SOUTHWEST = 10, - HIT_WEST = 11, - HIT_NORTHWEST = 12, - HIT_NORTH = 13, - HIT_SOUTH = 14, - SHOOT_PENALTY = 15, - SHOOT_CATAPULT = 16, - HEAL = 17, - SACRIFICE = 18, - TELEPORT = 19, - - COUNT - }; - - enum class Map { - POINTER = 0, - HOURGLASS = 1, - HERO = 2, - TOWN = 3, - T1_MOVE = 4, - T1_ATTACK = 5, - T1_SAIL = 6, - T1_DISEMBARK = 7, - T1_EXCHANGE = 8, - T1_VISIT = 9, - T2_MOVE = 10, - T2_ATTACK = 11, - T2_SAIL = 12, - T2_DISEMBARK = 13, - T2_EXCHANGE = 14, - T2_VISIT = 15, - T3_MOVE = 16, - T3_ATTACK = 17, - T3_SAIL = 18, - T3_DISEMBARK = 19, - T3_EXCHANGE = 20, - T3_VISIT = 21, - T4_MOVE = 22, - T4_ATTACK = 23, - T4_SAIL = 24, - T4_DISEMBARK = 25, - T4_EXCHANGE = 26, - T4_VISIT = 27, - T1_SAIL_VISIT = 28, - T2_SAIL_VISIT = 29, - T3_SAIL_VISIT = 30, - T4_SAIL_VISIT = 31, - SCROLL_NORTH = 32, - SCROLL_NORTHEAST = 33, - SCROLL_EAST = 34, - SCROLL_SOUTHEAST = 35, - SCROLL_SOUTH = 36, - SCROLL_SOUTHWEST = 37, - SCROLL_WEST = 38, - SCROLL_NORTHWEST = 39, - //POINTER_COPY = 40, // probably unused - TELEPORT = 41, - SCUTTLE_BOAT = 42, - - COUNT - }; - - enum class Spellcast { - SPELL = 0, - }; -} - -class ICursor -{ -public: - virtual ~ICursor() = default; - - virtual void setImage(std::shared_ptr image, const Point & pivotOffset) = 0; - virtual void setCursorPosition( const Point & newPos ) = 0; - virtual void render() = 0; - virtual void setVisible( bool on) = 0; -}; - class CursorHardware : public ICursor { std::shared_ptr cursorImage; @@ -139,99 +33,3 @@ public: void setVisible( bool on) override; }; -class CursorSoftware : public ICursor -{ - std::shared_ptr cursorImage; - - SDL_Texture * cursorTexture; - SDL_Surface * cursorSurface; - - Point pos; - Point pivot; - bool needUpdate; - bool visible; - - void createTexture(const Point & dimensions); - void updateTexture(); -public: - CursorSoftware(); - ~CursorSoftware(); - - void setImage(std::shared_ptr image, const Point & pivotOffset) override; - void setCursorPosition( const Point & newPos ) override; - void render() override; - void setVisible( bool on) override; -}; - -/// handles mouse cursor -class CursorHandler final -{ - std::shared_ptr dndObject; //if set, overrides currentCursor - - std::array, 4> cursors; - - bool showing; - - /// Current cursor - Cursor::Type type; - size_t frame; - float frameTime; - Point pos; - - void changeGraphic(Cursor::Type type, size_t index); - - Point getPivotOffsetDefault(size_t index); - Point getPivotOffsetMap(size_t index); - Point getPivotOffsetCombat(size_t index); - Point getPivotOffsetSpellcast(); - Point getPivotOffset(); - - void updateSpellcastCursor(); - - std::shared_ptr getCurrentImage(); - - std::unique_ptr cursor; - - static std::unique_ptr createCursor(); -public: - CursorHandler(); - ~CursorHandler(); - - /// Replaces the cursor with a custom image. - /// @param image Image to replace cursor with or nullptr to use the normal cursor. - void dragAndDropCursor(std::shared_ptr image); - - void dragAndDropCursor(std::string path, size_t index); - - /// Returns current position of the cursor - Point position() const; - - /// Changes cursor to specified index - void set(Cursor::Default index); - void set(Cursor::Map index); - void set(Cursor::Combat index); - void set(Cursor::Spellcast index); - - /// Returns current index of cursor - template - Index get() - { - assert((std::is_same::value )|| type != Cursor::Type::DEFAULT ); - assert((std::is_same::value )|| type != Cursor::Type::ADVENTURE ); - assert((std::is_same::value )|| type != Cursor::Type::COMBAT ); - assert((std::is_same::value )|| type != Cursor::Type::SPELLBOOK ); - - return static_cast(frame); - } - - void render(); - - void hide(); - void show(); - - /// change cursor's positions to (x, y) - void cursorMove(const int & x, const int & y); - /// Move cursor to screen center - void centerCursor(); - -}; diff --git a/client/gui/CursorSoftware.cpp b/client/gui/CursorSoftware.cpp index b44cb3040..f6ee7f9ac 100644 --- a/client/gui/CursorSoftware.cpp +++ b/client/gui/CursorSoftware.cpp @@ -23,294 +23,6 @@ #include #endif -std::unique_ptr CursorHandler::createCursor() -{ - if (settings["video"]["cursor"].String() == "auto") - { -#if defined(VCMI_ANDROID) || defined(VCMI_IOS) - return std::make_unique(); -#else - return std::make_unique(); -#endif - } - - if (settings["video"]["cursor"].String() == "hardware") - return std::make_unique(); - - assert(settings["video"]["cursor"].String() == "software"); - return std::make_unique(); -} - -CursorHandler::CursorHandler() - : cursor(createCursor()) - , frameTime(0.f) - , showing(false) - , pos(0,0) -{ - - type = Cursor::Type::DEFAULT; - dndObject = nullptr; - - cursors = - { - std::make_unique("CRADVNTR"), - std::make_unique("CRCOMBAT"), - std::make_unique("CRDEFLT"), - std::make_unique("CRSPELL") - }; - - for (auto & cursor : cursors) - cursor->preload(); - - set(Cursor::Map::POINTER); -} - -Point CursorHandler::position() const -{ - return pos; -} - -void CursorHandler::changeGraphic(Cursor::Type type, size_t index) -{ - assert(dndObject == nullptr); - - if (type == this->type && index == this->frame) - return; - - this->type = type; - this->frame = index; - - cursor->setImage(getCurrentImage(), getPivotOffset()); -} - -void CursorHandler::set(Cursor::Default index) -{ - changeGraphic(Cursor::Type::DEFAULT, static_cast(index)); -} - -void CursorHandler::set(Cursor::Map index) -{ - changeGraphic(Cursor::Type::ADVENTURE, static_cast(index)); -} - -void CursorHandler::set(Cursor::Combat index) -{ - changeGraphic(Cursor::Type::COMBAT, static_cast(index)); -} - -void CursorHandler::set(Cursor::Spellcast index) -{ - //Note: this is animated cursor, ignore specified frame and only change type - changeGraphic(Cursor::Type::SPELLBOOK, frame); -} - -void CursorHandler::dragAndDropCursor(std::shared_ptr image) -{ - dndObject = image; - cursor->setImage(getCurrentImage(), getPivotOffset()); -} - -void CursorHandler::dragAndDropCursor (std::string path, size_t index) -{ - CAnimation anim(path); - anim.load(index); - dragAndDropCursor(anim.getImage(index)); -} - -void CursorHandler::cursorMove(const int & x, const int & y) -{ - pos.x = x; - pos.y = y; - - cursor->setCursorPosition(pos); -} - -Point CursorHandler::getPivotOffsetDefault(size_t index) -{ - return {0, 0}; -} - -Point CursorHandler::getPivotOffsetMap(size_t index) -{ - static const std::array offsets = {{ - { 0, 0}, // POINTER = 0, - { 0, 0}, // HOURGLASS = 1, - { 12, 10}, // HERO = 2, - { 12, 12}, // TOWN = 3, - - { 15, 13}, // T1_MOVE = 4, - { 13, 13}, // T1_ATTACK = 5, - { 16, 32}, // T1_SAIL = 6, - { 13, 20}, // T1_DISEMBARK = 7, - { 8, 9}, // T1_EXCHANGE = 8, - { 14, 16}, // T1_VISIT = 9, - - { 15, 13}, // T2_MOVE = 10, - { 13, 13}, // T2_ATTACK = 11, - { 16, 32}, // T2_SAIL = 12, - { 13, 20}, // T2_DISEMBARK = 13, - { 8, 9}, // T2_EXCHANGE = 14, - { 14, 16}, // T2_VISIT = 15, - - { 15, 13}, // T3_MOVE = 16, - { 13, 13}, // T3_ATTACK = 17, - { 16, 32}, // T3_SAIL = 18, - { 13, 20}, // T3_DISEMBARK = 19, - { 8, 9}, // T3_EXCHANGE = 20, - { 14, 16}, // T3_VISIT = 21, - - { 15, 13}, // T4_MOVE = 22, - { 13, 13}, // T4_ATTACK = 23, - { 16, 32}, // T4_SAIL = 24, - { 13, 20}, // T4_DISEMBARK = 25, - { 8, 9}, // T4_EXCHANGE = 26, - { 14, 16}, // T4_VISIT = 27, - - { 16, 32}, // T1_SAIL_VISIT = 28, - { 16, 32}, // T2_SAIL_VISIT = 29, - { 16, 32}, // T3_SAIL_VISIT = 30, - { 16, 32}, // T4_SAIL_VISIT = 31, - - { 6, 1}, // SCROLL_NORTH = 32, - { 16, 2}, // SCROLL_NORTHEAST = 33, - { 21, 6}, // SCROLL_EAST = 34, - { 16, 16}, // SCROLL_SOUTHEAST = 35, - { 6, 21}, // SCROLL_SOUTH = 36, - { 1, 16}, // SCROLL_SOUTHWEST = 37, - { 1, 5}, // SCROLL_WEST = 38, - { 2, 1}, // SCROLL_NORTHWEST = 39, - - { 0, 0}, // POINTER_COPY = 40, - { 14, 16}, // TELEPORT = 41, - { 20, 20}, // SCUTTLE_BOAT = 42 - }}; - - assert(offsets.size() == size_t(Cursor::Map::COUNT)); //Invalid number of pivot offsets for cursor - assert(index < offsets.size()); - return offsets[index]; -} - -Point CursorHandler::getPivotOffsetCombat(size_t index) -{ - static const std::array offsets = {{ - { 12, 12 }, // BLOCKED = 0, - { 10, 14 }, // MOVE = 1, - { 14, 14 }, // FLY = 2, - { 12, 12 }, // SHOOT = 3, - { 12, 12 }, // HERO = 4, - { 8, 12 }, // QUERY = 5, - { 0, 0 }, // POINTER = 6, - { 21, 0 }, // HIT_NORTHEAST = 7, - { 31, 5 }, // HIT_EAST = 8, - { 21, 21 }, // HIT_SOUTHEAST = 9, - { 0, 21 }, // HIT_SOUTHWEST = 10, - { 0, 5 }, // HIT_WEST = 11, - { 0, 0 }, // HIT_NORTHWEST = 12, - { 6, 0 }, // HIT_NORTH = 13, - { 6, 31 }, // HIT_SOUTH = 14, - { 14, 0 }, // SHOOT_PENALTY = 15, - { 12, 12 }, // SHOOT_CATAPULT = 16, - { 12, 12 }, // HEAL = 17, - { 12, 12 }, // SACRIFICE = 18, - { 14, 20 }, // TELEPORT = 19 - }}; - - assert(offsets.size() == size_t(Cursor::Combat::COUNT)); //Invalid number of pivot offsets for cursor - assert(index < offsets.size()); - return offsets[index]; -} - -Point CursorHandler::getPivotOffsetSpellcast() -{ - return { 18, 28}; -} - -Point CursorHandler::getPivotOffset() -{ - if (dndObject) - return dndObject->dimensions() / 2; - - switch (type) { - case Cursor::Type::ADVENTURE: return getPivotOffsetMap(frame); - case Cursor::Type::COMBAT: return getPivotOffsetCombat(frame); - case Cursor::Type::DEFAULT: return getPivotOffsetDefault(frame); - case Cursor::Type::SPELLBOOK: return getPivotOffsetSpellcast(); - }; - - assert(0); - return {0, 0}; -} - -std::shared_ptr CursorHandler::getCurrentImage() -{ - if (dndObject) - return dndObject; - - return cursors[static_cast(type)]->getImage(frame); -} - -void CursorHandler::centerCursor() -{ - Point screenSize {screen->w, screen->h}; - pos = screenSize / 2 - getPivotOffset(); - - SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); - CSDL_Ext::warpMouse(pos.x, pos.y); - SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE); - - cursor->setCursorPosition(pos); -} - -void CursorHandler::updateSpellcastCursor() -{ - static const float frameDisplayDuration = 0.1f; // H3 uses 100 ms per frame - - frameTime += GH.mainFPSmng->getElapsedMilliseconds() / 1000.f; - size_t newFrame = frame; - - while (frameTime >= frameDisplayDuration) - { - frameTime -= frameDisplayDuration; - newFrame++; - } - - auto & animation = cursors.at(static_cast(type)); - - while (newFrame >= animation->size()) - newFrame -= animation->size(); - - changeGraphic(Cursor::Type::SPELLBOOK, newFrame); -} - -void CursorHandler::render() -{ - if(!showing) - return; - - if (type == Cursor::Type::SPELLBOOK) - updateSpellcastCursor(); - - cursor->render(); -} - -void CursorHandler::hide() -{ - if (!showing) - return; - - showing = false; - cursor->setVisible(false); -} - -void CursorHandler::show() -{ - if (showing) - return; - - showing = true; - cursor->setVisible(true); -} - void CursorSoftware::render() { //texture must be updated in the main (renderer) thread, but changes to cursor type may come from other threads @@ -394,65 +106,3 @@ CursorSoftware::~CursorSoftware() SDL_FreeSurface(cursorSurface); } -CursorHardware::CursorHardware(): - cursor(nullptr) -{ - SDL_ShowCursor(SDL_DISABLE); -} - -CursorHardware::~CursorHardware() -{ - if(cursor) - SDL_FreeCursor(cursor); -} - -void CursorHardware::setVisible(bool on) -{ -#ifdef VCMI_APPLE - dispatch_async(dispatch_get_main_queue(), ^{ -#endif - if (on) - SDL_ShowCursor(SDL_ENABLE); - else - SDL_ShowCursor(SDL_DISABLE); -#ifdef VCMI_APPLE - }); -#endif -} - -void CursorHardware::setImage(std::shared_ptr image, const Point & pivotOffset) -{ - auto cursorSurface = CSDL_Ext::newSurface(image->dimensions().x, image->dimensions().y); - - CSDL_Ext::fillSurface(cursorSurface, Colors::TRANSPARENCY); - - image->draw(cursorSurface); - - auto oldCursor = cursor; - cursor = SDL_CreateColorCursor(cursorSurface, pivotOffset.x, pivotOffset.y); - - if (!cursor) - logGlobal->error("Failed to set cursor! SDL says %s", SDL_GetError()); - - SDL_FreeSurface(cursorSurface); -#ifdef VCMI_APPLE - dispatch_async(dispatch_get_main_queue(), ^{ -#endif - SDL_SetCursor(cursor); - - if (oldCursor) - SDL_FreeCursor(oldCursor); -#ifdef VCMI_APPLE - }); -#endif -} - -void CursorHardware::setCursorPosition( const Point & newPos ) -{ - //no-op -} - -void CursorHardware::render() -{ - //no-op -} diff --git a/client/gui/CursorSoftware.h b/client/gui/CursorSoftware.h index b66bfb92b..f61b5139c 100644 --- a/client/gui/CursorSoftware.h +++ b/client/gui/CursorSoftware.h @@ -17,128 +17,6 @@ struct SDL_Cursor; #include "../../lib/Point.h" -namespace Cursor -{ - enum class Type { - ADVENTURE, // set of various cursors for adventure map - COMBAT, // set of various cursors for combat - DEFAULT, // default arrow and hourglass cursors - SPELLBOOK // animated cursor for spellcasting - }; - - enum class Default { - POINTER = 0, - //ARROW_COPY = 1, // probably unused - HOURGLASS = 2, - }; - - enum class Combat { - INVALID = -1, - - BLOCKED = 0, - MOVE = 1, - FLY = 2, - SHOOT = 3, - HERO = 4, - QUERY = 5, - POINTER = 6, - HIT_NORTHEAST = 7, - HIT_EAST = 8, - HIT_SOUTHEAST = 9, - HIT_SOUTHWEST = 10, - HIT_WEST = 11, - HIT_NORTHWEST = 12, - HIT_NORTH = 13, - HIT_SOUTH = 14, - SHOOT_PENALTY = 15, - SHOOT_CATAPULT = 16, - HEAL = 17, - SACRIFICE = 18, - TELEPORT = 19, - - COUNT - }; - - enum class Map { - POINTER = 0, - HOURGLASS = 1, - HERO = 2, - TOWN = 3, - T1_MOVE = 4, - T1_ATTACK = 5, - T1_SAIL = 6, - T1_DISEMBARK = 7, - T1_EXCHANGE = 8, - T1_VISIT = 9, - T2_MOVE = 10, - T2_ATTACK = 11, - T2_SAIL = 12, - T2_DISEMBARK = 13, - T2_EXCHANGE = 14, - T2_VISIT = 15, - T3_MOVE = 16, - T3_ATTACK = 17, - T3_SAIL = 18, - T3_DISEMBARK = 19, - T3_EXCHANGE = 20, - T3_VISIT = 21, - T4_MOVE = 22, - T4_ATTACK = 23, - T4_SAIL = 24, - T4_DISEMBARK = 25, - T4_EXCHANGE = 26, - T4_VISIT = 27, - T1_SAIL_VISIT = 28, - T2_SAIL_VISIT = 29, - T3_SAIL_VISIT = 30, - T4_SAIL_VISIT = 31, - SCROLL_NORTH = 32, - SCROLL_NORTHEAST = 33, - SCROLL_EAST = 34, - SCROLL_SOUTHEAST = 35, - SCROLL_SOUTH = 36, - SCROLL_SOUTHWEST = 37, - SCROLL_WEST = 38, - SCROLL_NORTHWEST = 39, - //POINTER_COPY = 40, // probably unused - TELEPORT = 41, - SCUTTLE_BOAT = 42, - - COUNT - }; - - enum class Spellcast { - SPELL = 0, - }; -} - -class ICursor -{ -public: - virtual ~ICursor() = default; - - virtual void setImage(std::shared_ptr image, const Point & pivotOffset) = 0; - virtual void setCursorPosition( const Point & newPos ) = 0; - virtual void render() = 0; - virtual void setVisible( bool on) = 0; -}; - -class CursorHardware : public ICursor -{ - std::shared_ptr cursorImage; - - SDL_Cursor * cursor; - -public: - CursorHardware(); - ~CursorHardware(); - - void setImage(std::shared_ptr image, const Point & pivotOffset) override; - void setCursorPosition( const Point & newPos ) override; - void render() override; - void setVisible( bool on) override; -}; - class CursorSoftware : public ICursor { std::shared_ptr cursorImage; @@ -163,75 +41,3 @@ public: void setVisible( bool on) override; }; -/// handles mouse cursor -class CursorHandler final -{ - std::shared_ptr dndObject; //if set, overrides currentCursor - - std::array, 4> cursors; - - bool showing; - - /// Current cursor - Cursor::Type type; - size_t frame; - float frameTime; - Point pos; - - void changeGraphic(Cursor::Type type, size_t index); - - Point getPivotOffsetDefault(size_t index); - Point getPivotOffsetMap(size_t index); - Point getPivotOffsetCombat(size_t index); - Point getPivotOffsetSpellcast(); - Point getPivotOffset(); - - void updateSpellcastCursor(); - - std::shared_ptr getCurrentImage(); - - std::unique_ptr cursor; - - static std::unique_ptr createCursor(); -public: - CursorHandler(); - ~CursorHandler(); - - /// Replaces the cursor with a custom image. - /// @param image Image to replace cursor with or nullptr to use the normal cursor. - void dragAndDropCursor(std::shared_ptr image); - - void dragAndDropCursor(std::string path, size_t index); - - /// Returns current position of the cursor - Point position() const; - - /// Changes cursor to specified index - void set(Cursor::Default index); - void set(Cursor::Map index); - void set(Cursor::Combat index); - void set(Cursor::Spellcast index); - - /// Returns current index of cursor - template - Index get() - { - assert((std::is_same::value )|| type != Cursor::Type::DEFAULT ); - assert((std::is_same::value )|| type != Cursor::Type::ADVENTURE ); - assert((std::is_same::value )|| type != Cursor::Type::COMBAT ); - assert((std::is_same::value )|| type != Cursor::Type::SPELLBOOK ); - - return static_cast(frame); - } - - void render(); - - void hide(); - void show(); - - /// change cursor's positions to (x, y) - void cursorMove(const int & x, const int & y); - /// Move cursor to screen center - void centerCursor(); - -}; diff --git a/client/gui/ICursor.h b/client/gui/ICursor.h index b66bfb92b..8951a18b6 100644 --- a/client/gui/ICursor.h +++ b/client/gui/ICursor.h @@ -17,101 +17,6 @@ struct SDL_Cursor; #include "../../lib/Point.h" -namespace Cursor -{ - enum class Type { - ADVENTURE, // set of various cursors for adventure map - COMBAT, // set of various cursors for combat - DEFAULT, // default arrow and hourglass cursors - SPELLBOOK // animated cursor for spellcasting - }; - - enum class Default { - POINTER = 0, - //ARROW_COPY = 1, // probably unused - HOURGLASS = 2, - }; - - enum class Combat { - INVALID = -1, - - BLOCKED = 0, - MOVE = 1, - FLY = 2, - SHOOT = 3, - HERO = 4, - QUERY = 5, - POINTER = 6, - HIT_NORTHEAST = 7, - HIT_EAST = 8, - HIT_SOUTHEAST = 9, - HIT_SOUTHWEST = 10, - HIT_WEST = 11, - HIT_NORTHWEST = 12, - HIT_NORTH = 13, - HIT_SOUTH = 14, - SHOOT_PENALTY = 15, - SHOOT_CATAPULT = 16, - HEAL = 17, - SACRIFICE = 18, - TELEPORT = 19, - - COUNT - }; - - enum class Map { - POINTER = 0, - HOURGLASS = 1, - HERO = 2, - TOWN = 3, - T1_MOVE = 4, - T1_ATTACK = 5, - T1_SAIL = 6, - T1_DISEMBARK = 7, - T1_EXCHANGE = 8, - T1_VISIT = 9, - T2_MOVE = 10, - T2_ATTACK = 11, - T2_SAIL = 12, - T2_DISEMBARK = 13, - T2_EXCHANGE = 14, - T2_VISIT = 15, - T3_MOVE = 16, - T3_ATTACK = 17, - T3_SAIL = 18, - T3_DISEMBARK = 19, - T3_EXCHANGE = 20, - T3_VISIT = 21, - T4_MOVE = 22, - T4_ATTACK = 23, - T4_SAIL = 24, - T4_DISEMBARK = 25, - T4_EXCHANGE = 26, - T4_VISIT = 27, - T1_SAIL_VISIT = 28, - T2_SAIL_VISIT = 29, - T3_SAIL_VISIT = 30, - T4_SAIL_VISIT = 31, - SCROLL_NORTH = 32, - SCROLL_NORTHEAST = 33, - SCROLL_EAST = 34, - SCROLL_SOUTHEAST = 35, - SCROLL_SOUTH = 36, - SCROLL_SOUTHWEST = 37, - SCROLL_WEST = 38, - SCROLL_NORTHWEST = 39, - //POINTER_COPY = 40, // probably unused - TELEPORT = 41, - SCUTTLE_BOAT = 42, - - COUNT - }; - - enum class Spellcast { - SPELL = 0, - }; -} - class ICursor { public: @@ -123,115 +28,3 @@ public: virtual void setVisible( bool on) = 0; }; -class CursorHardware : public ICursor -{ - std::shared_ptr cursorImage; - - SDL_Cursor * cursor; - -public: - CursorHardware(); - ~CursorHardware(); - - void setImage(std::shared_ptr image, const Point & pivotOffset) override; - void setCursorPosition( const Point & newPos ) override; - void render() override; - void setVisible( bool on) override; -}; - -class CursorSoftware : public ICursor -{ - std::shared_ptr cursorImage; - - SDL_Texture * cursorTexture; - SDL_Surface * cursorSurface; - - Point pos; - Point pivot; - bool needUpdate; - bool visible; - - void createTexture(const Point & dimensions); - void updateTexture(); -public: - CursorSoftware(); - ~CursorSoftware(); - - void setImage(std::shared_ptr image, const Point & pivotOffset) override; - void setCursorPosition( const Point & newPos ) override; - void render() override; - void setVisible( bool on) override; -}; - -/// handles mouse cursor -class CursorHandler final -{ - std::shared_ptr dndObject; //if set, overrides currentCursor - - std::array, 4> cursors; - - bool showing; - - /// Current cursor - Cursor::Type type; - size_t frame; - float frameTime; - Point pos; - - void changeGraphic(Cursor::Type type, size_t index); - - Point getPivotOffsetDefault(size_t index); - Point getPivotOffsetMap(size_t index); - Point getPivotOffsetCombat(size_t index); - Point getPivotOffsetSpellcast(); - Point getPivotOffset(); - - void updateSpellcastCursor(); - - std::shared_ptr getCurrentImage(); - - std::unique_ptr cursor; - - static std::unique_ptr createCursor(); -public: - CursorHandler(); - ~CursorHandler(); - - /// Replaces the cursor with a custom image. - /// @param image Image to replace cursor with or nullptr to use the normal cursor. - void dragAndDropCursor(std::shared_ptr image); - - void dragAndDropCursor(std::string path, size_t index); - - /// Returns current position of the cursor - Point position() const; - - /// Changes cursor to specified index - void set(Cursor::Default index); - void set(Cursor::Map index); - void set(Cursor::Combat index); - void set(Cursor::Spellcast index); - - /// Returns current index of cursor - template - Index get() - { - assert((std::is_same::value )|| type != Cursor::Type::DEFAULT ); - assert((std::is_same::value )|| type != Cursor::Type::ADVENTURE ); - assert((std::is_same::value )|| type != Cursor::Type::COMBAT ); - assert((std::is_same::value )|| type != Cursor::Type::SPELLBOOK ); - - return static_cast(frame); - } - - void render(); - - void hide(); - void show(); - - /// change cursor's positions to (x, y) - void cursorMove(const int & x, const int & y); - /// Move cursor to screen center - void centerCursor(); - -}; From f5cd6a9abe31a01e96213090950120ee1f2fb994 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 15:59:52 +0200 Subject: [PATCH 68/79] split IImage into separate file --- client/render/{CAnimation.h => IImage.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename client/render/{CAnimation.h => IImage.h} (100%) diff --git a/client/render/CAnimation.h b/client/render/IImage.h similarity index 100% rename from client/render/CAnimation.h rename to client/render/IImage.h From d593b887139982a50220fc84bfa7f287600f959f Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 16:00:32 +0200 Subject: [PATCH 69/79] split SDLImage into separate file --- client/render/{CAnimation.cpp => SDLImage.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename client/render/{CAnimation.cpp => SDLImage.cpp} (100%) diff --git a/client/render/CAnimation.cpp b/client/render/SDLImage.cpp similarity index 100% rename from client/render/CAnimation.cpp rename to client/render/SDLImage.cpp From eef5876069866523358c136c0ef266312af31410 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 16:01:47 +0200 Subject: [PATCH 70/79] split SDLImageLoader into separate file --- client/render/{CAnimation.cpp => SDLImageLoader.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename client/render/{CAnimation.cpp => SDLImageLoader.cpp} (100%) diff --git a/client/render/CAnimation.cpp b/client/render/SDLImageLoader.cpp similarity index 100% rename from client/render/CAnimation.cpp rename to client/render/SDLImageLoader.cpp From 3a88e7ce0712395b7f1f7a9803a40aea4f5ec3dd Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 16:02:33 +0200 Subject: [PATCH 71/79] split CDefFile into separate file --- client/render/{CAnimation.cpp => CDefFile.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename client/render/{CAnimation.cpp => CDefFile.cpp} (100%) diff --git a/client/render/CAnimation.cpp b/client/render/CDefFile.cpp similarity index 100% rename from client/render/CAnimation.cpp rename to client/render/CDefFile.cpp From 54a95efc4d1d5232e0bbb767ca2f57ef77336701 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 16:03:17 +0200 Subject: [PATCH 72/79] split CFadeAnimation into separate file --- client/render/{CAnimation.cpp => CFadeAnimation.cpp} | 0 client/render/{CAnimation.h => CFadeAnimation.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/render/{CAnimation.cpp => CFadeAnimation.cpp} (100%) rename client/render/{CAnimation.h => CFadeAnimation.h} (100%) diff --git a/client/render/CAnimation.cpp b/client/render/CFadeAnimation.cpp similarity index 100% rename from client/render/CAnimation.cpp rename to client/render/CFadeAnimation.cpp diff --git a/client/render/CAnimation.h b/client/render/CFadeAnimation.h similarity index 100% rename from client/render/CAnimation.h rename to client/render/CFadeAnimation.h From f6fa7f1ae0525c12bcfa96f15cdeca3c30965437 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 16:03:48 +0200 Subject: [PATCH 73/79] temp rename --- client/render/{CAnimation.cpp => Animation.cpp} | 0 client/render/{CAnimation.h => Animation.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename client/render/{CAnimation.cpp => Animation.cpp} (100%) rename client/render/{CAnimation.h => Animation.h} (100%) diff --git a/client/render/CAnimation.cpp b/client/render/Animation.cpp similarity index 100% rename from client/render/CAnimation.cpp rename to client/render/Animation.cpp diff --git a/client/render/CAnimation.h b/client/render/Animation.h similarity index 100% rename from client/render/CAnimation.h rename to client/render/Animation.h From ae968d1865cd379d5170ccf9db76779d8e596e2c Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 16:12:01 +0200 Subject: [PATCH 74/79] Remove duplicated code from new files --- client/render/Animation.cpp | 920 ---------------------- client/render/Animation.h | 82 -- client/render/CDefFile.cpp | 939 ----------------------- client/render/CDefFile.h | 71 ++ client/render/CFadeAnimation.cpp | 1193 ----------------------------- client/render/CFadeAnimation.h | 127 ---- client/render/IImage.h | 101 --- client/render/SDLImage.cpp | 960 ----------------------- client/render/SDLImage.h | 90 +++ client/render/SDLImageLoader.cpp | 1219 ------------------------------ client/render/SDLImageLoader.h | 54 ++ 11 files changed, 215 insertions(+), 5541 deletions(-) create mode 100644 client/render/CDefFile.h create mode 100644 client/render/SDLImage.h create mode 100644 client/render/SDLImageLoader.h diff --git a/client/render/Animation.cpp b/client/render/Animation.cpp index 31a18f5e5..6fa584767 100644 --- a/client/render/Animation.cpp +++ b/client/render/Animation.cpp @@ -24,841 +24,6 @@ #include -class SDLImageLoader; - -typedef std::map > source_map; -typedef std::map image_map; -typedef std::map group_map; - -/// Class for def loading -/// After loading will store general info (palette and frame offsets) and pointer to file itself -class CDefFile -{ -private: - - PACKED_STRUCT_BEGIN - struct SSpriteDef - { - ui32 size; - ui32 format; /// format in which pixel data is stored - ui32 fullWidth; /// full width and height of frame, including borders - ui32 fullHeight; - ui32 width; /// width and height of pixel data, borders excluded - ui32 height; - si32 leftMargin; - si32 topMargin; - } PACKED_STRUCT_END; - //offset[group][frame] - offset of frame data in file - std::map > offset; - - std::unique_ptr data; - std::unique_ptr palette; - -public: - CDefFile(std::string Name); - ~CDefFile(); - - //load frame as SDL_Surface - template - void loadFrame(size_t frame, size_t group, ImageLoader &loader) const; - - const std::map getEntries() const; -}; - - -/* - * Wrapper around SDL_Surface - */ -class SDLImage : public IImage -{ -public: - - const static int DEFAULT_PALETTE_COLORS = 256; - - //Surface without empty borders - SDL_Surface * surf; - //size of left and top borders - Point margins; - //total size including borders - Point fullSize; - -public: - //Load image from def file - SDLImage(CDefFile *data, size_t frame, size_t group=0); - //Load from bitmap file - SDLImage(std::string filename); - - SDLImage(const JsonNode & conf); - //Create using existing surface, extraRef will increase refcount on SDL_Surface - SDLImage(SDL_Surface * from, bool extraRef); - ~SDLImage(); - - // Keep the original palette, in order to do color switching operation - void savePalette(); - - void draw(SDL_Surface * where, int posX=0, int posY=0, const Rect *src=nullptr) const override; - void draw(SDL_Surface * where, const Rect * dest, const Rect * src) const override; - std::shared_ptr scaleFast(const Point & size) const override; - void exportBitmap(const boost::filesystem::path & path) const override; - void playerColored(PlayerColor player) override; - void setFlagColor(PlayerColor player) override; - bool isTransparent(const Point & coords) const override; - Point dimensions() const override; - - void horizontalFlip() override; - void verticalFlip() override; - - void shiftPalette(int from, int howMany) override; - void adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) override; - void resetPalette(int colorID) override; - void resetPalette() override; - - void setAlpha(uint8_t value) override; - - void setSpecialPallete(const SpecialPalette & SpecialPalette) override; - - friend class SDLImageLoader; - -private: - SDL_Palette * originalPalette; -}; - -class SDLImageLoader -{ - SDLImage * image; - ui8 * lineStart; - ui8 * position; -public: - //load size raw pixels from data - inline void Load(size_t size, const ui8 * data); - //set size pixels to color - inline void Load(size_t size, ui8 color=0); - inline void EndLine(); - //init image with these sizes and palette - inline void init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal); - - SDLImageLoader(SDLImage * Img); - ~SDLImageLoader(); -}; - -std::shared_ptr IImage::createFromFile( const std::string & path ) -{ - return std::shared_ptr(new SDLImage(path)); -} - -std::shared_ptr IImage::createFromSurface( SDL_Surface * source ) -{ - return std::shared_ptr(new SDLImage(source, true)); -} - -// Extremely simple file cache. TODO: smarter, more general solution -class CFileCache -{ - static const int cacheSize = 50; //Max number of cached files - struct FileData - { - ResourceID name; - size_t size; - std::unique_ptr data; - - std::unique_ptr getCopy() - { - auto ret = std::unique_ptr(new ui8[size]); - std::copy(data.get(), data.get() + size, ret.get()); - return ret; - } - FileData(ResourceID name_, size_t size_, std::unique_ptr data_): - name{std::move(name_)}, - size{size_}, - data{std::move(data_)} - {} - }; - - std::deque cache; -public: - std::unique_ptr getCachedFile(ResourceID rid) - { - for(auto & file : cache) - { - if (file.name == rid) - return file.getCopy(); - } - // Still here? Cache miss - if (cache.size() > cacheSize) - cache.pop_front(); - - auto data = CResourceHandler::get()->load(rid)->readAll(); - - cache.emplace_back(std::move(rid), data.second, std::move(data.first)); - - return cache.back().getCopy(); - } -}; - -enum class DefType : uint32_t -{ - SPELL = 0x40, - SPRITE = 0x41, - CREATURE = 0x42, - MAP = 0x43, - MAP_HERO = 0x44, - TERRAIN = 0x45, - CURSOR = 0x46, - INTERFACE = 0x47, - SPRITE_FRAME = 0x48, - BATTLE_HERO = 0x49 -}; - -static CFileCache animationCache; - -/************************************************************************* - * DefFile, class used for def loading * - *************************************************************************/ - -bool operator== (const SDL_Color & lhs, const SDL_Color & rhs) -{ - return (lhs.a == rhs.a) && (lhs.b == rhs.b) &&(lhs.g == rhs.g) &&(lhs.r == rhs.r); -} - -CDefFile::CDefFile(std::string Name): - data(nullptr), - palette(nullptr) -{ - //First 8 colors in def palette used for transparency - static SDL_Color H3Palette[8] = - { - { 0, 0, 0, 0},// transparency ( used in most images ) - { 0, 0, 0, 64},// shadow border ( used in battle, adventure map def's ) - { 0, 0, 0, 64},// shadow border ( used in fog-of-war def's ) - { 0, 0, 0, 128},// shadow body ( used in fog-of-war def's ) - { 0, 0, 0, 128},// shadow body ( used in battle, adventure map def's ) - { 0, 0, 0, 0},// selection ( used in battle def's ) - { 0, 0, 0, 128},// shadow body below selection ( used in battle def's ) - { 0, 0, 0, 64} // shadow border below selection ( used in battle def's ) - }; - data = animationCache.getCachedFile(ResourceID(std::string("SPRITES/") + Name, EResType::ANIMATION)); - - palette = std::unique_ptr(new SDL_Color[256]); - int it = 0; - - ui32 type = read_le_u32(data.get() + it); - it+=4; - //int width = read_le_u32(data + it); it+=4;//not used - //int height = read_le_u32(data + it); it+=4; - it+=8; - ui32 totalBlocks = read_le_u32(data.get() + it); - it+=4; - - for (ui32 i= 0; i<256; i++) - { - palette[i].r = data[it++]; - palette[i].g = data[it++]; - palette[i].b = data[it++]; - palette[i].a = SDL_ALPHA_OPAQUE; - } - - switch(static_cast(type)) - { - case DefType::SPELL: - palette[0] = H3Palette[0]; - break; - case DefType::SPRITE: - case DefType::SPRITE_FRAME: - for(ui32 i= 0; i<8; i++) - palette[i] = H3Palette[i]; - break; - case DefType::CREATURE: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - palette[5] = H3Palette[5]; - palette[6] = H3Palette[6]; - palette[7] = H3Palette[7]; - break; - case DefType::MAP: - case DefType::MAP_HERO: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - //5 = owner flag, handled separately - break; - case DefType::TERRAIN: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[2] = H3Palette[2]; - palette[3] = H3Palette[3]; - palette[4] = H3Palette[4]; - break; - case DefType::CURSOR: - palette[0] = H3Palette[0]; - break; - case DefType::INTERFACE: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - //player colors handled separately - //TODO: disallow colorizing other def types - break; - case DefType::BATTLE_HERO: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - break; - default: - logAnim->error("Unknown def type %d in %s", type, Name); - break; - } - - - for (ui32 i=0; i -void CDefFile::loadFrame(size_t frame, size_t group, ImageLoader &loader) const -{ - std::map >::const_iterator it; - it = offset.find(group); - assert (it != offset.end()); - - const ui8 * FDef = data.get()+it->second[frame]; - - const SSpriteDef sd = * reinterpret_cast(FDef); - SSpriteDef sprite; - - sprite.format = read_le_u32(&sd.format); - sprite.fullWidth = read_le_u32(&sd.fullWidth); - sprite.fullHeight = read_le_u32(&sd.fullHeight); - sprite.width = read_le_u32(&sd.width); - sprite.height = read_le_u32(&sd.height); - sprite.leftMargin = read_le_u32(&sd.leftMargin); - sprite.topMargin = read_le_u32(&sd.topMargin); - - ui32 currentOffset = sizeof(SSpriteDef); - - //special case for some "old" format defs (SGTWMTA.DEF and SGTWMTB.DEF) - - if(sprite.format == 1 && sprite.width > sprite.fullWidth && sprite.height > sprite.fullHeight) - { - sprite.leftMargin = 0; - sprite.topMargin = 0; - sprite.width = sprite.fullWidth; - sprite.height = sprite.fullHeight; - - currentOffset -= 16; - } - - const ui32 BaseOffset = currentOffset; - - loader.init(Point(sprite.width, sprite.height), - Point(sprite.leftMargin, sprite.topMargin), - Point(sprite.fullWidth, sprite.fullHeight), palette.get()); - - switch(sprite.format) - { - case 0: - { - //pixel data is not compressed, copy data to surface - for(ui32 i=0; i(FDef+currentOffset); - currentOffset += sizeof(ui32) * sprite.height; - - for(ui32 i=0; ierror("Error: unsupported format of def file: %d", sprite.format); - break; - } -} - -CDefFile::~CDefFile() = default; - -const std::map CDefFile::getEntries() const -{ - std::map ret; - - for (auto & elem : offset) - ret[elem.first] = elem.second.size(); - return ret; -} - -/************************************************************************* - * Classes for image loaders - helpers for loading from def files * - *************************************************************************/ - -SDLImageLoader::SDLImageLoader(SDLImage * Img): - image(Img), - lineStart(nullptr), - position(nullptr) -{ -} - -void SDLImageLoader::init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal) -{ - //Init image - image->surf = SDL_CreateRGBSurface(0, SpriteSize.x, SpriteSize.y, 8, 0, 0, 0, 0); - image->margins = Margins; - image->fullSize = FullSize; - - //Prepare surface - SDL_Palette * p = SDL_AllocPalette(SDLImage::DEFAULT_PALETTE_COLORS); - SDL_SetPaletteColors(p, pal, 0, SDLImage::DEFAULT_PALETTE_COLORS); - SDL_SetSurfacePalette(image->surf, p); - SDL_FreePalette(p); - - SDL_LockSurface(image->surf); - lineStart = position = (ui8*)image->surf->pixels; -} - -inline void SDLImageLoader::Load(size_t size, const ui8 * data) -{ - if (size) - { - memcpy((void *)position, data, size); - position += size; - } -} - -inline void SDLImageLoader::Load(size_t size, ui8 color) -{ - if (size) - { - memset((void *)position, color, size); - position += size; - } -} - -inline void SDLImageLoader::EndLine() -{ - lineStart += image->surf->pitch; - position = lineStart; -} - -SDLImageLoader::~SDLImageLoader() -{ - SDL_UnlockSurface(image->surf); - SDL_SetColorKey(image->surf, SDL_TRUE, 0); - //TODO: RLE if compressed and bpp>1 -} - -/************************************************************************* - * Classes for images, support loading from file and drawing on surface * - *************************************************************************/ - -IImage::IImage() = default; -IImage::~IImage() = default; - -int IImage::width() const -{ - return dimensions().x; -} - -int IImage::height() const -{ - return dimensions().y; -} - -SDLImage::SDLImage(CDefFile * data, size_t frame, size_t group) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - SDLImageLoader loader(this); - data->loadFrame(frame, group, loader); - - savePalette(); -} - -SDLImage::SDLImage(SDL_Surface * from, bool extraRef) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - surf = from; - if (surf == nullptr) - return; - - savePalette(); - - if (extraRef) - surf->refcount++; - fullSize.x = surf->w; - fullSize.y = surf->h; -} - -SDLImage::SDLImage(const JsonNode & conf) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - std::string filename = conf["file"].String(); - - surf = BitmapHandler::loadBitmap(filename); - - if(surf == nullptr) - return; - - savePalette(); - - const JsonNode & jsonMargins = conf["margins"]; - - margins.x = static_cast(jsonMargins["left"].Integer()); - margins.y = static_cast(jsonMargins["top"].Integer()); - - fullSize.x = static_cast(conf["width"].Integer()); - fullSize.y = static_cast(conf["height"].Integer()); - - if(fullSize.x == 0) - { - fullSize.x = margins.x + surf->w + (int)jsonMargins["right"].Integer(); - } - - if(fullSize.y == 0) - { - fullSize.y = margins.y + surf->h + (int)jsonMargins["bottom"].Integer(); - } -} - -SDLImage::SDLImage(std::string filename) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - surf = BitmapHandler::loadBitmap(filename); - - if(surf == nullptr) - { - logGlobal->error("Error: failed to load image %s", filename); - return; - } - else - { - savePalette(); - fullSize.x = surf->w; - fullSize.y = surf->h; - } -} - -void SDLImage::draw(SDL_Surface *where, int posX, int posY, const Rect *src) const -{ - if(!surf) - return; - - Rect destRect(posX, posY, surf->w, surf->h); - draw(where, &destRect, src); -} - -void SDLImage::draw(SDL_Surface* where, const Rect * dest, const Rect* src) const -{ - if (!surf) - return; - - Rect sourceRect(0, 0, surf->w, surf->h); - - Point destShift(0, 0); - - if(src) - { - if(src->x < margins.x) - destShift.x += margins.x - src->x; - - if(src->y < margins.y) - destShift.y += margins.y - src->y; - - sourceRect = Rect(*src).intersect(Rect(margins.x, margins.y, surf->w, surf->h)); - - sourceRect -= margins; - } - else - destShift = margins; - - if(dest) - destShift += dest->topLeft(); - - uint8_t perSurfaceAlpha; - if (SDL_GetSurfaceAlphaMod(surf, &perSurfaceAlpha) != 0) - logGlobal->error("SDL_GetSurfaceAlphaMod faied! %s", SDL_GetError()); - - if(surf->format->BitsPerPixel == 8 && perSurfaceAlpha == SDL_ALPHA_OPAQUE) - { - CSDL_Ext::blit8bppAlphaTo24bpp(surf, sourceRect, where, destShift); - } - else - { - CSDL_Ext::blitSurface(surf, sourceRect, where, destShift); - } -} - -std::shared_ptr SDLImage::scaleFast(const Point & size) const -{ - float scaleX = float(size.x) / width(); - float scaleY = float(size.y) / height(); - - auto scaled = CSDL_Ext::scaleSurfaceFast(surf, (int)(surf->w * scaleX), (int)(surf->h * scaleY)); - - if (scaled->format && scaled->format->palette) // fix color keying, because SDL loses it at this point - CSDL_Ext::setColorKey(scaled, scaled->format->palette->colors[0]); - else if(scaled->format && scaled->format->Amask) - SDL_SetSurfaceBlendMode(scaled, SDL_BLENDMODE_BLEND);//just in case - else - CSDL_Ext::setDefaultColorKey(scaled);//just in case - - SDLImage * ret = new SDLImage(scaled, false); - - ret->fullSize.x = (int) round((float)fullSize.x * scaleX); - ret->fullSize.y = (int) round((float)fullSize.y * scaleY); - - ret->margins.x = (int) round((float)margins.x * scaleX); - ret->margins.y = (int) round((float)margins.y * scaleY); - - return std::shared_ptr(ret); -} - -void SDLImage::exportBitmap(const boost::filesystem::path& path) const -{ - SDL_SaveBMP(surf, path.string().c_str()); -} - -void SDLImage::playerColored(PlayerColor player) -{ - graphics->blueToPlayersAdv(surf, player); -} - -void SDLImage::setAlpha(uint8_t value) -{ - CSDL_Ext::setAlpha (surf, value); - SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_BLEND); -} - -void SDLImage::setFlagColor(PlayerColor player) -{ - if(player < PlayerColor::PLAYER_LIMIT || player==PlayerColor::NEUTRAL) - CSDL_Ext::setPlayerColor(surf, player); -} - -bool SDLImage::isTransparent(const Point & coords) const -{ - return CSDL_Ext::isTransparent(surf, coords.x, coords.y); -} - -Point SDLImage::dimensions() const -{ - return fullSize; -} - -void SDLImage::horizontalFlip() -{ - margins.y = fullSize.y - surf->h - margins.y; - - //todo: modify in-place - SDL_Surface * flipped = CSDL_Ext::horizontalFlip(surf); - SDL_FreeSurface(surf); - surf = flipped; -} - -void SDLImage::verticalFlip() -{ - margins.x = fullSize.x - surf->w - margins.x; - - //todo: modify in-place - SDL_Surface * flipped = CSDL_Ext::verticalFlip(surf); - SDL_FreeSurface(surf); - surf = flipped; -} - -// Keep the original palette, in order to do color switching operation -void SDLImage::savePalette() -{ - // For some images that don't have palette, skip this - if(surf->format->palette == nullptr) - return; - - if(originalPalette == nullptr) - originalPalette = SDL_AllocPalette(DEFAULT_PALETTE_COLORS); - - SDL_SetPaletteColors(originalPalette, surf->format->palette->colors, 0, DEFAULT_PALETTE_COLORS); -} - -void SDLImage::shiftPalette(int from, int howMany) -{ - //works with at most 16 colors, if needed more -> increase values - assert(howMany < 16); - - if(surf->format->palette) - { - SDL_Color palette[16]; - - for(int i=0; iformat->palette->colors[from + i]; - } - CSDL_Ext::setColors(surf, palette, from, howMany); - } -} - -void SDLImage::adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) -{ - if(originalPalette == nullptr) - return; - - SDL_Palette* palette = surf->format->palette; - - // Note: here we skip first colors in the palette that are predefined in H3 images - for(int i = colorsToSkip; i < palette->ncolors; i++) - { - palette->colors[i] = shifter.shiftColor(originalPalette->colors[i]); - } -} - -void SDLImage::resetPalette() -{ - if(originalPalette == nullptr) - return; - - // Always keept the original palette not changed, copy a new palette to assign to surface - SDL_SetPaletteColors(surf->format->palette, originalPalette->colors, 0, originalPalette->ncolors); -} - -void SDLImage::resetPalette( int colorID ) -{ - if(originalPalette == nullptr) - return; - - // Always keept the original palette not changed, copy a new palette to assign to surface - SDL_SetPaletteColors(surf->format->palette, originalPalette->colors + colorID, colorID, 1); -} - -void SDLImage::setSpecialPallete(const IImage::SpecialPalette & SpecialPalette) -{ - if(surf->format->palette) - { - CSDL_Ext::setColors(surf, const_cast(SpecialPalette.data()), 1, 7); - } -} - -SDLImage::~SDLImage() -{ - SDL_FreeSurface(surf); - - if(originalPalette != nullptr) - { - SDL_FreePalette(originalPalette); - originalPalette = nullptr; - } -} - std::shared_ptr CAnimation::getFromExtraDef(std::string filename) { size_t pos = filename.find(':'); @@ -1217,88 +382,3 @@ void CAnimation::createFlippedGroup(const size_t sourceGroup, const size_t targe } } -float CFadeAnimation::initialCounter() const -{ - if (fadingMode == EMode::OUT) - return 1.0f; - return 0.0f; -} - -void CFadeAnimation::update() -{ - if (!fading) - return; - - if (fadingMode == EMode::OUT) - fadingCounter -= delta; - else - fadingCounter += delta; - - if (isFinished()) - { - fading = false; - if (shouldFreeSurface) - { - SDL_FreeSurface(fadingSurface); - fadingSurface = nullptr; - } - } -} - -bool CFadeAnimation::isFinished() const -{ - if (fadingMode == EMode::OUT) - return fadingCounter <= 0.0f; - return fadingCounter >= 1.0f; -} - -CFadeAnimation::CFadeAnimation() - : delta(0), fadingSurface(nullptr), fading(false), fadingCounter(0), shouldFreeSurface(false), - fadingMode(EMode::NONE) -{ -} - -CFadeAnimation::~CFadeAnimation() -{ - if (fadingSurface && shouldFreeSurface) - SDL_FreeSurface(fadingSurface); -} - -void CFadeAnimation::init(EMode mode, SDL_Surface * sourceSurface, bool freeSurfaceAtEnd, float animDelta) -{ - if (fading) - { - // in that case, immediately finish the previous fade - // (alternatively, we could just return here to ignore the new fade request until this one finished (but we'd need to free the passed bitmap to avoid leaks)) - logGlobal->warn("Tried to init fading animation that is already running."); - if (fadingSurface && shouldFreeSurface) - SDL_FreeSurface(fadingSurface); - } - if (animDelta <= 0.0f) - { - logGlobal->warn("Fade anim: delta should be positive; %f given.", animDelta); - animDelta = DEFAULT_DELTA; - } - - if (sourceSurface) - fadingSurface = sourceSurface; - - delta = animDelta; - fadingMode = mode; - fadingCounter = initialCounter(); - fading = true; - shouldFreeSurface = freeSurfaceAtEnd; -} - -void CFadeAnimation::draw(SDL_Surface * targetSurface, const Point &targetPoint) -{ - if (!fading || !fadingSurface || fadingMode == EMode::NONE) - { - fading = false; - return; - } - - CSDL_Ext::setAlpha(fadingSurface, (int)(fadingCounter * 255)); - CSDL_Ext::blitSurface(fadingSurface, targetSurface, targetPoint); //FIXME - CSDL_Ext::setAlpha(fadingSurface, 255); -} diff --git a/client/render/Animation.h b/client/render/Animation.h index e5881c65f..88ff80415 100644 --- a/client/render/Animation.h +++ b/client/render/Animation.h @@ -32,60 +32,6 @@ struct SDL_Color; class CDefFile; class ColorFilter; -/* - * Base class for images, can be used for non-animation pictures as well - */ -class IImage -{ -public: - using SpecialPalette = std::array; - - //draws image on surface "where" at position - virtual void draw(SDL_Surface * where, int posX = 0, int posY = 0, const Rect * src = nullptr) const = 0; - virtual void draw(SDL_Surface * where, const Rect * dest, const Rect * src) const = 0; - - virtual std::shared_ptr scaleFast(const Point & size) const = 0; - - virtual void exportBitmap(const boost::filesystem::path & path) const = 0; - - //Change palette to specific player - virtual void playerColored(PlayerColor player)=0; - - //set special color for flag - virtual void setFlagColor(PlayerColor player)=0; - - //test transparency of specific pixel - virtual bool isTransparent(const Point & coords) const = 0; - - virtual Point dimensions() const = 0; - int width() const; - int height() const; - - //only indexed bitmaps, 16 colors maximum - virtual void shiftPalette(int from, int howMany) = 0; - virtual void adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) = 0; - virtual void resetPalette(int colorID) = 0; - virtual void resetPalette() = 0; - - virtual void setAlpha(uint8_t value) = 0; - - //only indexed bitmaps with 7 special colors - virtual void setSpecialPallete(const SpecialPalette & SpecialPalette) = 0; - - virtual void horizontalFlip() = 0; - virtual void verticalFlip() = 0; - - IImage(); - virtual ~IImage(); - - /// loads image from specified file. Returns 0-sized images on failure - static std::shared_ptr createFromFile( const std::string & path ); - - /// temporary compatibility method. Creates IImage from existing SDL_Surface - /// Surface will be shared, called must still free it with SDL_FreeSurface - static std::shared_ptr createFromSurface( SDL_Surface * source ); -}; - /// Class for handling animation class CAnimation { @@ -159,31 +105,3 @@ public: void createFlippedGroup(const size_t sourceGroup, const size_t targetGroup); }; -const float DEFAULT_DELTA = 0.05f; - -class CFadeAnimation -{ -public: - enum class EMode - { - NONE, IN, OUT - }; -private: - float delta; - SDL_Surface * fadingSurface; - bool fading; - float fadingCounter; - bool shouldFreeSurface; - - float initialCounter() const; - bool isFinished() const; -public: - EMode fadingMode; - - CFadeAnimation(); - ~CFadeAnimation(); - void init(EMode mode, SDL_Surface * sourceSurface, bool freeSurfaceAtEnd = false, float animDelta = DEFAULT_DELTA); - void update(); - void draw(SDL_Surface * targetSurface, const Point & targetPoint); - bool isFading() const { return fading; } -}; diff --git a/client/render/CDefFile.cpp b/client/render/CDefFile.cpp index 31a18f5e5..d42440d73 100644 --- a/client/render/CDefFile.cpp +++ b/client/render/CDefFile.cpp @@ -24,133 +24,6 @@ #include -class SDLImageLoader; - -typedef std::map > source_map; -typedef std::map image_map; -typedef std::map group_map; - -/// Class for def loading -/// After loading will store general info (palette and frame offsets) and pointer to file itself -class CDefFile -{ -private: - - PACKED_STRUCT_BEGIN - struct SSpriteDef - { - ui32 size; - ui32 format; /// format in which pixel data is stored - ui32 fullWidth; /// full width and height of frame, including borders - ui32 fullHeight; - ui32 width; /// width and height of pixel data, borders excluded - ui32 height; - si32 leftMargin; - si32 topMargin; - } PACKED_STRUCT_END; - //offset[group][frame] - offset of frame data in file - std::map > offset; - - std::unique_ptr data; - std::unique_ptr palette; - -public: - CDefFile(std::string Name); - ~CDefFile(); - - //load frame as SDL_Surface - template - void loadFrame(size_t frame, size_t group, ImageLoader &loader) const; - - const std::map getEntries() const; -}; - - -/* - * Wrapper around SDL_Surface - */ -class SDLImage : public IImage -{ -public: - - const static int DEFAULT_PALETTE_COLORS = 256; - - //Surface without empty borders - SDL_Surface * surf; - //size of left and top borders - Point margins; - //total size including borders - Point fullSize; - -public: - //Load image from def file - SDLImage(CDefFile *data, size_t frame, size_t group=0); - //Load from bitmap file - SDLImage(std::string filename); - - SDLImage(const JsonNode & conf); - //Create using existing surface, extraRef will increase refcount on SDL_Surface - SDLImage(SDL_Surface * from, bool extraRef); - ~SDLImage(); - - // Keep the original palette, in order to do color switching operation - void savePalette(); - - void draw(SDL_Surface * where, int posX=0, int posY=0, const Rect *src=nullptr) const override; - void draw(SDL_Surface * where, const Rect * dest, const Rect * src) const override; - std::shared_ptr scaleFast(const Point & size) const override; - void exportBitmap(const boost::filesystem::path & path) const override; - void playerColored(PlayerColor player) override; - void setFlagColor(PlayerColor player) override; - bool isTransparent(const Point & coords) const override; - Point dimensions() const override; - - void horizontalFlip() override; - void verticalFlip() override; - - void shiftPalette(int from, int howMany) override; - void adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) override; - void resetPalette(int colorID) override; - void resetPalette() override; - - void setAlpha(uint8_t value) override; - - void setSpecialPallete(const SpecialPalette & SpecialPalette) override; - - friend class SDLImageLoader; - -private: - SDL_Palette * originalPalette; -}; - -class SDLImageLoader -{ - SDLImage * image; - ui8 * lineStart; - ui8 * position; -public: - //load size raw pixels from data - inline void Load(size_t size, const ui8 * data); - //set size pixels to color - inline void Load(size_t size, ui8 color=0); - inline void EndLine(); - //init image with these sizes and palette - inline void init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal); - - SDLImageLoader(SDLImage * Img); - ~SDLImageLoader(); -}; - -std::shared_ptr IImage::createFromFile( const std::string & path ) -{ - return std::shared_ptr(new SDLImage(path)); -} - -std::shared_ptr IImage::createFromSurface( SDL_Surface * source ) -{ - return std::shared_ptr(new SDLImage(source, true)); -} - // Extremely simple file cache. TODO: smarter, more general solution class CFileCache { @@ -490,815 +363,3 @@ const std::map CDefFile::getEntries() const return ret; } -/************************************************************************* - * Classes for image loaders - helpers for loading from def files * - *************************************************************************/ - -SDLImageLoader::SDLImageLoader(SDLImage * Img): - image(Img), - lineStart(nullptr), - position(nullptr) -{ -} - -void SDLImageLoader::init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal) -{ - //Init image - image->surf = SDL_CreateRGBSurface(0, SpriteSize.x, SpriteSize.y, 8, 0, 0, 0, 0); - image->margins = Margins; - image->fullSize = FullSize; - - //Prepare surface - SDL_Palette * p = SDL_AllocPalette(SDLImage::DEFAULT_PALETTE_COLORS); - SDL_SetPaletteColors(p, pal, 0, SDLImage::DEFAULT_PALETTE_COLORS); - SDL_SetSurfacePalette(image->surf, p); - SDL_FreePalette(p); - - SDL_LockSurface(image->surf); - lineStart = position = (ui8*)image->surf->pixels; -} - -inline void SDLImageLoader::Load(size_t size, const ui8 * data) -{ - if (size) - { - memcpy((void *)position, data, size); - position += size; - } -} - -inline void SDLImageLoader::Load(size_t size, ui8 color) -{ - if (size) - { - memset((void *)position, color, size); - position += size; - } -} - -inline void SDLImageLoader::EndLine() -{ - lineStart += image->surf->pitch; - position = lineStart; -} - -SDLImageLoader::~SDLImageLoader() -{ - SDL_UnlockSurface(image->surf); - SDL_SetColorKey(image->surf, SDL_TRUE, 0); - //TODO: RLE if compressed and bpp>1 -} - -/************************************************************************* - * Classes for images, support loading from file and drawing on surface * - *************************************************************************/ - -IImage::IImage() = default; -IImage::~IImage() = default; - -int IImage::width() const -{ - return dimensions().x; -} - -int IImage::height() const -{ - return dimensions().y; -} - -SDLImage::SDLImage(CDefFile * data, size_t frame, size_t group) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - SDLImageLoader loader(this); - data->loadFrame(frame, group, loader); - - savePalette(); -} - -SDLImage::SDLImage(SDL_Surface * from, bool extraRef) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - surf = from; - if (surf == nullptr) - return; - - savePalette(); - - if (extraRef) - surf->refcount++; - fullSize.x = surf->w; - fullSize.y = surf->h; -} - -SDLImage::SDLImage(const JsonNode & conf) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - std::string filename = conf["file"].String(); - - surf = BitmapHandler::loadBitmap(filename); - - if(surf == nullptr) - return; - - savePalette(); - - const JsonNode & jsonMargins = conf["margins"]; - - margins.x = static_cast(jsonMargins["left"].Integer()); - margins.y = static_cast(jsonMargins["top"].Integer()); - - fullSize.x = static_cast(conf["width"].Integer()); - fullSize.y = static_cast(conf["height"].Integer()); - - if(fullSize.x == 0) - { - fullSize.x = margins.x + surf->w + (int)jsonMargins["right"].Integer(); - } - - if(fullSize.y == 0) - { - fullSize.y = margins.y + surf->h + (int)jsonMargins["bottom"].Integer(); - } -} - -SDLImage::SDLImage(std::string filename) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - surf = BitmapHandler::loadBitmap(filename); - - if(surf == nullptr) - { - logGlobal->error("Error: failed to load image %s", filename); - return; - } - else - { - savePalette(); - fullSize.x = surf->w; - fullSize.y = surf->h; - } -} - -void SDLImage::draw(SDL_Surface *where, int posX, int posY, const Rect *src) const -{ - if(!surf) - return; - - Rect destRect(posX, posY, surf->w, surf->h); - draw(where, &destRect, src); -} - -void SDLImage::draw(SDL_Surface* where, const Rect * dest, const Rect* src) const -{ - if (!surf) - return; - - Rect sourceRect(0, 0, surf->w, surf->h); - - Point destShift(0, 0); - - if(src) - { - if(src->x < margins.x) - destShift.x += margins.x - src->x; - - if(src->y < margins.y) - destShift.y += margins.y - src->y; - - sourceRect = Rect(*src).intersect(Rect(margins.x, margins.y, surf->w, surf->h)); - - sourceRect -= margins; - } - else - destShift = margins; - - if(dest) - destShift += dest->topLeft(); - - uint8_t perSurfaceAlpha; - if (SDL_GetSurfaceAlphaMod(surf, &perSurfaceAlpha) != 0) - logGlobal->error("SDL_GetSurfaceAlphaMod faied! %s", SDL_GetError()); - - if(surf->format->BitsPerPixel == 8 && perSurfaceAlpha == SDL_ALPHA_OPAQUE) - { - CSDL_Ext::blit8bppAlphaTo24bpp(surf, sourceRect, where, destShift); - } - else - { - CSDL_Ext::blitSurface(surf, sourceRect, where, destShift); - } -} - -std::shared_ptr SDLImage::scaleFast(const Point & size) const -{ - float scaleX = float(size.x) / width(); - float scaleY = float(size.y) / height(); - - auto scaled = CSDL_Ext::scaleSurfaceFast(surf, (int)(surf->w * scaleX), (int)(surf->h * scaleY)); - - if (scaled->format && scaled->format->palette) // fix color keying, because SDL loses it at this point - CSDL_Ext::setColorKey(scaled, scaled->format->palette->colors[0]); - else if(scaled->format && scaled->format->Amask) - SDL_SetSurfaceBlendMode(scaled, SDL_BLENDMODE_BLEND);//just in case - else - CSDL_Ext::setDefaultColorKey(scaled);//just in case - - SDLImage * ret = new SDLImage(scaled, false); - - ret->fullSize.x = (int) round((float)fullSize.x * scaleX); - ret->fullSize.y = (int) round((float)fullSize.y * scaleY); - - ret->margins.x = (int) round((float)margins.x * scaleX); - ret->margins.y = (int) round((float)margins.y * scaleY); - - return std::shared_ptr(ret); -} - -void SDLImage::exportBitmap(const boost::filesystem::path& path) const -{ - SDL_SaveBMP(surf, path.string().c_str()); -} - -void SDLImage::playerColored(PlayerColor player) -{ - graphics->blueToPlayersAdv(surf, player); -} - -void SDLImage::setAlpha(uint8_t value) -{ - CSDL_Ext::setAlpha (surf, value); - SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_BLEND); -} - -void SDLImage::setFlagColor(PlayerColor player) -{ - if(player < PlayerColor::PLAYER_LIMIT || player==PlayerColor::NEUTRAL) - CSDL_Ext::setPlayerColor(surf, player); -} - -bool SDLImage::isTransparent(const Point & coords) const -{ - return CSDL_Ext::isTransparent(surf, coords.x, coords.y); -} - -Point SDLImage::dimensions() const -{ - return fullSize; -} - -void SDLImage::horizontalFlip() -{ - margins.y = fullSize.y - surf->h - margins.y; - - //todo: modify in-place - SDL_Surface * flipped = CSDL_Ext::horizontalFlip(surf); - SDL_FreeSurface(surf); - surf = flipped; -} - -void SDLImage::verticalFlip() -{ - margins.x = fullSize.x - surf->w - margins.x; - - //todo: modify in-place - SDL_Surface * flipped = CSDL_Ext::verticalFlip(surf); - SDL_FreeSurface(surf); - surf = flipped; -} - -// Keep the original palette, in order to do color switching operation -void SDLImage::savePalette() -{ - // For some images that don't have palette, skip this - if(surf->format->palette == nullptr) - return; - - if(originalPalette == nullptr) - originalPalette = SDL_AllocPalette(DEFAULT_PALETTE_COLORS); - - SDL_SetPaletteColors(originalPalette, surf->format->palette->colors, 0, DEFAULT_PALETTE_COLORS); -} - -void SDLImage::shiftPalette(int from, int howMany) -{ - //works with at most 16 colors, if needed more -> increase values - assert(howMany < 16); - - if(surf->format->palette) - { - SDL_Color palette[16]; - - for(int i=0; iformat->palette->colors[from + i]; - } - CSDL_Ext::setColors(surf, palette, from, howMany); - } -} - -void SDLImage::adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) -{ - if(originalPalette == nullptr) - return; - - SDL_Palette* palette = surf->format->palette; - - // Note: here we skip first colors in the palette that are predefined in H3 images - for(int i = colorsToSkip; i < palette->ncolors; i++) - { - palette->colors[i] = shifter.shiftColor(originalPalette->colors[i]); - } -} - -void SDLImage::resetPalette() -{ - if(originalPalette == nullptr) - return; - - // Always keept the original palette not changed, copy a new palette to assign to surface - SDL_SetPaletteColors(surf->format->palette, originalPalette->colors, 0, originalPalette->ncolors); -} - -void SDLImage::resetPalette( int colorID ) -{ - if(originalPalette == nullptr) - return; - - // Always keept the original palette not changed, copy a new palette to assign to surface - SDL_SetPaletteColors(surf->format->palette, originalPalette->colors + colorID, colorID, 1); -} - -void SDLImage::setSpecialPallete(const IImage::SpecialPalette & SpecialPalette) -{ - if(surf->format->palette) - { - CSDL_Ext::setColors(surf, const_cast(SpecialPalette.data()), 1, 7); - } -} - -SDLImage::~SDLImage() -{ - SDL_FreeSurface(surf); - - if(originalPalette != nullptr) - { - SDL_FreePalette(originalPalette); - originalPalette = nullptr; - } -} - -std::shared_ptr CAnimation::getFromExtraDef(std::string filename) -{ - size_t pos = filename.find(':'); - if (pos == -1) - return nullptr; - CAnimation anim(filename.substr(0, pos)); - pos++; - size_t frame = atoi(filename.c_str()+pos); - size_t group = 0; - pos = filename.find(':', pos); - if (pos != -1) - { - pos++; - group = frame; - frame = atoi(filename.c_str()+pos); - } - anim.load(frame ,group); - auto ret = anim.images[group][frame]; - anim.images.clear(); - return ret; -} - -bool CAnimation::loadFrame(size_t frame, size_t group) -{ - if(size(group) <= frame) - { - printError(frame, group, "LoadFrame"); - return false; - } - - auto image = getImage(frame, group, false); - if(image) - { - return true; - } - - //try to get image from def - if(source[group][frame].getType() == JsonNode::JsonType::DATA_NULL) - { - if(defFile) - { - auto frameList = defFile->getEntries(); - - if(vstd::contains(frameList, group) && frameList.at(group) > frame) // frame is present - { - images[group][frame] = std::make_shared(defFile.get(), frame, group); - return true; - } - } - // still here? image is missing - - printError(frame, group, "LoadFrame"); - images[group][frame] = std::make_shared("DEFAULT"); - } - else //load from separate file - { - auto img = getFromExtraDef(source[group][frame]["file"].String()); - if(!img) - img = std::make_shared(source[group][frame]); - - images[group][frame] = img; - return true; - } - return false; -} - -bool CAnimation::unloadFrame(size_t frame, size_t group) -{ - auto image = getImage(frame, group, false); - if(image) - { - images[group].erase(frame); - - if(images[group].empty()) - images.erase(group); - return true; - } - return false; -} - -void CAnimation::initFromJson(const JsonNode & config) -{ - std::string basepath; - basepath = config["basepath"].String(); - - JsonNode base(JsonNode::JsonType::DATA_STRUCT); - base["margins"] = config["margins"]; - base["width"] = config["width"]; - base["height"] = config["height"]; - - for(const JsonNode & group : config["sequences"].Vector()) - { - size_t groupID = group["group"].Integer();//TODO: string-to-value conversion("moving" -> MOVING) - source[groupID].clear(); - - for(const JsonNode & frame : group["frames"].Vector()) - { - JsonNode toAdd(JsonNode::JsonType::DATA_STRUCT); - JsonUtils::inherit(toAdd, base); - toAdd["file"].String() = basepath + frame.String(); - source[groupID].push_back(toAdd); - } - } - - for(const JsonNode & node : config["images"].Vector()) - { - size_t group = node["group"].Integer(); - size_t frame = node["frame"].Integer(); - - if (source[group].size() <= frame) - source[group].resize(frame+1); - - JsonNode toAdd(JsonNode::JsonType::DATA_STRUCT); - JsonUtils::inherit(toAdd, base); - toAdd["file"].String() = basepath + node["file"].String(); - source[group][frame] = toAdd; - } -} - -void CAnimation::exportBitmaps(const boost::filesystem::path& path) const -{ - if(images.empty()) - { - logGlobal->error("Nothing to export, animation is empty"); - return; - } - - boost::filesystem::path actualPath = path / "SPRITES" / name; - boost::filesystem::create_directories(actualPath); - - size_t counter = 0; - - for(const auto & groupPair : images) - { - size_t group = groupPair.first; - - for(const auto & imagePair : groupPair.second) - { - size_t frame = imagePair.first; - const auto img = imagePair.second; - - boost::format fmt("%d_%d.bmp"); - fmt % group % frame; - - img->exportBitmap(actualPath / fmt.str()); - counter++; - } - } - - logGlobal->info("Exported %d frames to %s", counter, actualPath.string()); -} - -void CAnimation::init() -{ - if(defFile) - { - const std::map defEntries = defFile->getEntries(); - - for (auto & defEntry : defEntries) - source[defEntry.first].resize(defEntry.second); - } - - ResourceID resID(std::string("SPRITES/") + name, EResType::TEXT); - - if (vstd::contains(graphics->imageLists, resID.getName())) - initFromJson(graphics->imageLists[resID.getName()]); - - auto configList = CResourceHandler::get()->getResourcesWithName(resID); - - for(auto & loader : configList) - { - auto stream = loader->load(resID); - std::unique_ptr textData(new ui8[stream->getSize()]); - stream->read(textData.get(), stream->getSize()); - - const JsonNode config((char*)textData.get(), stream->getSize()); - - initFromJson(config); - } -} - -void CAnimation::printError(size_t frame, size_t group, std::string type) const -{ - logGlobal->error("%s error: Request for frame not present in CAnimation! File name: %s, Group: %d, Frame: %d", type, name, group, frame); -} - -CAnimation::CAnimation(std::string Name): - name(Name), - preloaded(false), - defFile() -{ - size_t dotPos = name.find_last_of('.'); - if ( dotPos!=-1 ) - name.erase(dotPos); - std::transform(name.begin(), name.end(), name.begin(), toupper); - - ResourceID resource(std::string("SPRITES/") + name, EResType::ANIMATION); - - if(CResourceHandler::get()->existsResource(resource)) - defFile = std::make_shared(name); - - init(); - - if(source.empty()) - logAnim->error("Animation %s failed to load", Name); -} - -CAnimation::CAnimation(): - name(""), - preloaded(false), - defFile() -{ - init(); -} - -CAnimation::~CAnimation() = default; - -void CAnimation::duplicateImage(const size_t sourceGroup, const size_t sourceFrame, const size_t targetGroup) -{ - if(!source.count(sourceGroup)) - { - logAnim->error("Group %d missing in %s", sourceGroup, name); - return; - } - - if(source[sourceGroup].size() <= sourceFrame) - { - logAnim->error("Frame [%d %d] missing in %s", sourceGroup, sourceFrame, name); - return; - } - - //todo: clone actual loaded Image object - JsonNode clone(source[sourceGroup][sourceFrame]); - - if(clone.getType() == JsonNode::JsonType::DATA_NULL) - { - std::string temp = name+":"+boost::lexical_cast(sourceGroup)+":"+boost::lexical_cast(sourceFrame); - clone["file"].String() = temp; - } - - source[targetGroup].push_back(clone); - - size_t index = source[targetGroup].size() - 1; - - if(preloaded) - load(index, targetGroup); -} - -void CAnimation::setCustom(std::string filename, size_t frame, size_t group) -{ - if (source[group].size() <= frame) - source[group].resize(frame+1); - source[group][frame]["file"].String() = filename; - //FIXME: update image if already loaded -} - -std::shared_ptr CAnimation::getImage(size_t frame, size_t group, bool verbose) const -{ - auto groupIter = images.find(group); - if (groupIter != images.end()) - { - auto imageIter = groupIter->second.find(frame); - if (imageIter != groupIter->second.end()) - return imageIter->second; - } - if (verbose) - printError(frame, group, "GetImage"); - return nullptr; -} - -void CAnimation::load() -{ - for (auto & elem : source) - for (size_t image=0; image < elem.second.size(); image++) - loadFrame(image, elem.first); -} - -void CAnimation::unload() -{ - for (auto & elem : source) - for (size_t image=0; image < elem.second.size(); image++) - unloadFrame(image, elem.first); - -} - -void CAnimation::preload() -{ - if(!preloaded) - { - preloaded = true; - load(); - } -} - -void CAnimation::loadGroup(size_t group) -{ - if (vstd::contains(source, group)) - for (size_t image=0; image < source[group].size(); image++) - loadFrame(image, group); -} - -void CAnimation::unloadGroup(size_t group) -{ - if (vstd::contains(source, group)) - for (size_t image=0; image < source[group].size(); image++) - unloadFrame(image, group); -} - -void CAnimation::load(size_t frame, size_t group) -{ - loadFrame(frame, group); -} - -void CAnimation::unload(size_t frame, size_t group) -{ - unloadFrame(frame, group); -} - -size_t CAnimation::size(size_t group) const -{ - auto iter = source.find(group); - if (iter != source.end()) - return iter->second.size(); - return 0; -} - -void CAnimation::horizontalFlip() -{ - for(auto & group : images) - for(auto & image : group.second) - image.second->horizontalFlip(); -} - -void CAnimation::verticalFlip() -{ - for(auto & group : images) - for(auto & image : group.second) - image.second->verticalFlip(); -} - -void CAnimation::playerColored(PlayerColor player) -{ - for(auto & group : images) - for(auto & image : group.second) - image.second->playerColored(player); -} - -void CAnimation::createFlippedGroup(const size_t sourceGroup, const size_t targetGroup) -{ - for(size_t frame = 0; frame < size(sourceGroup); ++frame) - { - duplicateImage(sourceGroup, frame, targetGroup); - - auto image = getImage(frame, targetGroup); - image->verticalFlip(); - } -} - -float CFadeAnimation::initialCounter() const -{ - if (fadingMode == EMode::OUT) - return 1.0f; - return 0.0f; -} - -void CFadeAnimation::update() -{ - if (!fading) - return; - - if (fadingMode == EMode::OUT) - fadingCounter -= delta; - else - fadingCounter += delta; - - if (isFinished()) - { - fading = false; - if (shouldFreeSurface) - { - SDL_FreeSurface(fadingSurface); - fadingSurface = nullptr; - } - } -} - -bool CFadeAnimation::isFinished() const -{ - if (fadingMode == EMode::OUT) - return fadingCounter <= 0.0f; - return fadingCounter >= 1.0f; -} - -CFadeAnimation::CFadeAnimation() - : delta(0), fadingSurface(nullptr), fading(false), fadingCounter(0), shouldFreeSurface(false), - fadingMode(EMode::NONE) -{ -} - -CFadeAnimation::~CFadeAnimation() -{ - if (fadingSurface && shouldFreeSurface) - SDL_FreeSurface(fadingSurface); -} - -void CFadeAnimation::init(EMode mode, SDL_Surface * sourceSurface, bool freeSurfaceAtEnd, float animDelta) -{ - if (fading) - { - // in that case, immediately finish the previous fade - // (alternatively, we could just return here to ignore the new fade request until this one finished (but we'd need to free the passed bitmap to avoid leaks)) - logGlobal->warn("Tried to init fading animation that is already running."); - if (fadingSurface && shouldFreeSurface) - SDL_FreeSurface(fadingSurface); - } - if (animDelta <= 0.0f) - { - logGlobal->warn("Fade anim: delta should be positive; %f given.", animDelta); - animDelta = DEFAULT_DELTA; - } - - if (sourceSurface) - fadingSurface = sourceSurface; - - delta = animDelta; - fadingMode = mode; - fadingCounter = initialCounter(); - fading = true; - shouldFreeSurface = freeSurfaceAtEnd; -} - -void CFadeAnimation::draw(SDL_Surface * targetSurface, const Point &targetPoint) -{ - if (!fading || !fadingSurface || fadingMode == EMode::NONE) - { - fading = false; - return; - } - - CSDL_Ext::setAlpha(fadingSurface, (int)(fadingCounter * 255)); - CSDL_Ext::blitSurface(fadingSurface, targetSurface, targetPoint); //FIXME - CSDL_Ext::setAlpha(fadingSurface, 255); -} diff --git a/client/render/CDefFile.h b/client/render/CDefFile.h new file mode 100644 index 000000000..5cdb21fb8 --- /dev/null +++ b/client/render/CDefFile.h @@ -0,0 +1,71 @@ +/* + * CAnimation.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include "../../lib/GameConstants.h" + +#ifdef IN +#undef IN +#endif + +#ifdef OUT +#undef OUT +#endif + +VCMI_LIB_NAMESPACE_BEGIN + +class JsonNode; +class Rect; +class Point; + +VCMI_LIB_NAMESPACE_END + +struct SDL_Surface; +struct SDL_Color; +class CDefFile; +class ColorFilter; + + +/// Class for def loading +/// After loading will store general info (palette and frame offsets) and pointer to file itself +class CDefFile +{ +private: + + PACKED_STRUCT_BEGIN + struct SSpriteDef + { + ui32 size; + ui32 format; /// format in which pixel data is stored + ui32 fullWidth; /// full width and height of frame, including borders + ui32 fullHeight; + ui32 width; /// width and height of pixel data, borders excluded + ui32 height; + si32 leftMargin; + si32 topMargin; + } PACKED_STRUCT_END; + //offset[group][frame] - offset of frame data in file + std::map > offset; + + std::unique_ptr data; + std::unique_ptr palette; + +public: + CDefFile(std::string Name); + ~CDefFile(); + + //load frame as SDL_Surface + template + void loadFrame(size_t frame, size_t group, ImageLoader &loader) const; + + const std::map getEntries() const; +}; + + diff --git a/client/render/CFadeAnimation.cpp b/client/render/CFadeAnimation.cpp index 31a18f5e5..5e4b998ee 100644 --- a/client/render/CFadeAnimation.cpp +++ b/client/render/CFadeAnimation.cpp @@ -24,1199 +24,6 @@ #include -class SDLImageLoader; - -typedef std::map > source_map; -typedef std::map image_map; -typedef std::map group_map; - -/// Class for def loading -/// After loading will store general info (palette and frame offsets) and pointer to file itself -class CDefFile -{ -private: - - PACKED_STRUCT_BEGIN - struct SSpriteDef - { - ui32 size; - ui32 format; /// format in which pixel data is stored - ui32 fullWidth; /// full width and height of frame, including borders - ui32 fullHeight; - ui32 width; /// width and height of pixel data, borders excluded - ui32 height; - si32 leftMargin; - si32 topMargin; - } PACKED_STRUCT_END; - //offset[group][frame] - offset of frame data in file - std::map > offset; - - std::unique_ptr data; - std::unique_ptr palette; - -public: - CDefFile(std::string Name); - ~CDefFile(); - - //load frame as SDL_Surface - template - void loadFrame(size_t frame, size_t group, ImageLoader &loader) const; - - const std::map getEntries() const; -}; - - -/* - * Wrapper around SDL_Surface - */ -class SDLImage : public IImage -{ -public: - - const static int DEFAULT_PALETTE_COLORS = 256; - - //Surface without empty borders - SDL_Surface * surf; - //size of left and top borders - Point margins; - //total size including borders - Point fullSize; - -public: - //Load image from def file - SDLImage(CDefFile *data, size_t frame, size_t group=0); - //Load from bitmap file - SDLImage(std::string filename); - - SDLImage(const JsonNode & conf); - //Create using existing surface, extraRef will increase refcount on SDL_Surface - SDLImage(SDL_Surface * from, bool extraRef); - ~SDLImage(); - - // Keep the original palette, in order to do color switching operation - void savePalette(); - - void draw(SDL_Surface * where, int posX=0, int posY=0, const Rect *src=nullptr) const override; - void draw(SDL_Surface * where, const Rect * dest, const Rect * src) const override; - std::shared_ptr scaleFast(const Point & size) const override; - void exportBitmap(const boost::filesystem::path & path) const override; - void playerColored(PlayerColor player) override; - void setFlagColor(PlayerColor player) override; - bool isTransparent(const Point & coords) const override; - Point dimensions() const override; - - void horizontalFlip() override; - void verticalFlip() override; - - void shiftPalette(int from, int howMany) override; - void adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) override; - void resetPalette(int colorID) override; - void resetPalette() override; - - void setAlpha(uint8_t value) override; - - void setSpecialPallete(const SpecialPalette & SpecialPalette) override; - - friend class SDLImageLoader; - -private: - SDL_Palette * originalPalette; -}; - -class SDLImageLoader -{ - SDLImage * image; - ui8 * lineStart; - ui8 * position; -public: - //load size raw pixels from data - inline void Load(size_t size, const ui8 * data); - //set size pixels to color - inline void Load(size_t size, ui8 color=0); - inline void EndLine(); - //init image with these sizes and palette - inline void init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal); - - SDLImageLoader(SDLImage * Img); - ~SDLImageLoader(); -}; - -std::shared_ptr IImage::createFromFile( const std::string & path ) -{ - return std::shared_ptr(new SDLImage(path)); -} - -std::shared_ptr IImage::createFromSurface( SDL_Surface * source ) -{ - return std::shared_ptr(new SDLImage(source, true)); -} - -// Extremely simple file cache. TODO: smarter, more general solution -class CFileCache -{ - static const int cacheSize = 50; //Max number of cached files - struct FileData - { - ResourceID name; - size_t size; - std::unique_ptr data; - - std::unique_ptr getCopy() - { - auto ret = std::unique_ptr(new ui8[size]); - std::copy(data.get(), data.get() + size, ret.get()); - return ret; - } - FileData(ResourceID name_, size_t size_, std::unique_ptr data_): - name{std::move(name_)}, - size{size_}, - data{std::move(data_)} - {} - }; - - std::deque cache; -public: - std::unique_ptr getCachedFile(ResourceID rid) - { - for(auto & file : cache) - { - if (file.name == rid) - return file.getCopy(); - } - // Still here? Cache miss - if (cache.size() > cacheSize) - cache.pop_front(); - - auto data = CResourceHandler::get()->load(rid)->readAll(); - - cache.emplace_back(std::move(rid), data.second, std::move(data.first)); - - return cache.back().getCopy(); - } -}; - -enum class DefType : uint32_t -{ - SPELL = 0x40, - SPRITE = 0x41, - CREATURE = 0x42, - MAP = 0x43, - MAP_HERO = 0x44, - TERRAIN = 0x45, - CURSOR = 0x46, - INTERFACE = 0x47, - SPRITE_FRAME = 0x48, - BATTLE_HERO = 0x49 -}; - -static CFileCache animationCache; - -/************************************************************************* - * DefFile, class used for def loading * - *************************************************************************/ - -bool operator== (const SDL_Color & lhs, const SDL_Color & rhs) -{ - return (lhs.a == rhs.a) && (lhs.b == rhs.b) &&(lhs.g == rhs.g) &&(lhs.r == rhs.r); -} - -CDefFile::CDefFile(std::string Name): - data(nullptr), - palette(nullptr) -{ - //First 8 colors in def palette used for transparency - static SDL_Color H3Palette[8] = - { - { 0, 0, 0, 0},// transparency ( used in most images ) - { 0, 0, 0, 64},// shadow border ( used in battle, adventure map def's ) - { 0, 0, 0, 64},// shadow border ( used in fog-of-war def's ) - { 0, 0, 0, 128},// shadow body ( used in fog-of-war def's ) - { 0, 0, 0, 128},// shadow body ( used in battle, adventure map def's ) - { 0, 0, 0, 0},// selection ( used in battle def's ) - { 0, 0, 0, 128},// shadow body below selection ( used in battle def's ) - { 0, 0, 0, 64} // shadow border below selection ( used in battle def's ) - }; - data = animationCache.getCachedFile(ResourceID(std::string("SPRITES/") + Name, EResType::ANIMATION)); - - palette = std::unique_ptr(new SDL_Color[256]); - int it = 0; - - ui32 type = read_le_u32(data.get() + it); - it+=4; - //int width = read_le_u32(data + it); it+=4;//not used - //int height = read_le_u32(data + it); it+=4; - it+=8; - ui32 totalBlocks = read_le_u32(data.get() + it); - it+=4; - - for (ui32 i= 0; i<256; i++) - { - palette[i].r = data[it++]; - palette[i].g = data[it++]; - palette[i].b = data[it++]; - palette[i].a = SDL_ALPHA_OPAQUE; - } - - switch(static_cast(type)) - { - case DefType::SPELL: - palette[0] = H3Palette[0]; - break; - case DefType::SPRITE: - case DefType::SPRITE_FRAME: - for(ui32 i= 0; i<8; i++) - palette[i] = H3Palette[i]; - break; - case DefType::CREATURE: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - palette[5] = H3Palette[5]; - palette[6] = H3Palette[6]; - palette[7] = H3Palette[7]; - break; - case DefType::MAP: - case DefType::MAP_HERO: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - //5 = owner flag, handled separately - break; - case DefType::TERRAIN: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[2] = H3Palette[2]; - palette[3] = H3Palette[3]; - palette[4] = H3Palette[4]; - break; - case DefType::CURSOR: - palette[0] = H3Palette[0]; - break; - case DefType::INTERFACE: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - //player colors handled separately - //TODO: disallow colorizing other def types - break; - case DefType::BATTLE_HERO: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - break; - default: - logAnim->error("Unknown def type %d in %s", type, Name); - break; - } - - - for (ui32 i=0; i -void CDefFile::loadFrame(size_t frame, size_t group, ImageLoader &loader) const -{ - std::map >::const_iterator it; - it = offset.find(group); - assert (it != offset.end()); - - const ui8 * FDef = data.get()+it->second[frame]; - - const SSpriteDef sd = * reinterpret_cast(FDef); - SSpriteDef sprite; - - sprite.format = read_le_u32(&sd.format); - sprite.fullWidth = read_le_u32(&sd.fullWidth); - sprite.fullHeight = read_le_u32(&sd.fullHeight); - sprite.width = read_le_u32(&sd.width); - sprite.height = read_le_u32(&sd.height); - sprite.leftMargin = read_le_u32(&sd.leftMargin); - sprite.topMargin = read_le_u32(&sd.topMargin); - - ui32 currentOffset = sizeof(SSpriteDef); - - //special case for some "old" format defs (SGTWMTA.DEF and SGTWMTB.DEF) - - if(sprite.format == 1 && sprite.width > sprite.fullWidth && sprite.height > sprite.fullHeight) - { - sprite.leftMargin = 0; - sprite.topMargin = 0; - sprite.width = sprite.fullWidth; - sprite.height = sprite.fullHeight; - - currentOffset -= 16; - } - - const ui32 BaseOffset = currentOffset; - - loader.init(Point(sprite.width, sprite.height), - Point(sprite.leftMargin, sprite.topMargin), - Point(sprite.fullWidth, sprite.fullHeight), palette.get()); - - switch(sprite.format) - { - case 0: - { - //pixel data is not compressed, copy data to surface - for(ui32 i=0; i(FDef+currentOffset); - currentOffset += sizeof(ui32) * sprite.height; - - for(ui32 i=0; ierror("Error: unsupported format of def file: %d", sprite.format); - break; - } -} - -CDefFile::~CDefFile() = default; - -const std::map CDefFile::getEntries() const -{ - std::map ret; - - for (auto & elem : offset) - ret[elem.first] = elem.second.size(); - return ret; -} - -/************************************************************************* - * Classes for image loaders - helpers for loading from def files * - *************************************************************************/ - -SDLImageLoader::SDLImageLoader(SDLImage * Img): - image(Img), - lineStart(nullptr), - position(nullptr) -{ -} - -void SDLImageLoader::init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal) -{ - //Init image - image->surf = SDL_CreateRGBSurface(0, SpriteSize.x, SpriteSize.y, 8, 0, 0, 0, 0); - image->margins = Margins; - image->fullSize = FullSize; - - //Prepare surface - SDL_Palette * p = SDL_AllocPalette(SDLImage::DEFAULT_PALETTE_COLORS); - SDL_SetPaletteColors(p, pal, 0, SDLImage::DEFAULT_PALETTE_COLORS); - SDL_SetSurfacePalette(image->surf, p); - SDL_FreePalette(p); - - SDL_LockSurface(image->surf); - lineStart = position = (ui8*)image->surf->pixels; -} - -inline void SDLImageLoader::Load(size_t size, const ui8 * data) -{ - if (size) - { - memcpy((void *)position, data, size); - position += size; - } -} - -inline void SDLImageLoader::Load(size_t size, ui8 color) -{ - if (size) - { - memset((void *)position, color, size); - position += size; - } -} - -inline void SDLImageLoader::EndLine() -{ - lineStart += image->surf->pitch; - position = lineStart; -} - -SDLImageLoader::~SDLImageLoader() -{ - SDL_UnlockSurface(image->surf); - SDL_SetColorKey(image->surf, SDL_TRUE, 0); - //TODO: RLE if compressed and bpp>1 -} - -/************************************************************************* - * Classes for images, support loading from file and drawing on surface * - *************************************************************************/ - -IImage::IImage() = default; -IImage::~IImage() = default; - -int IImage::width() const -{ - return dimensions().x; -} - -int IImage::height() const -{ - return dimensions().y; -} - -SDLImage::SDLImage(CDefFile * data, size_t frame, size_t group) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - SDLImageLoader loader(this); - data->loadFrame(frame, group, loader); - - savePalette(); -} - -SDLImage::SDLImage(SDL_Surface * from, bool extraRef) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - surf = from; - if (surf == nullptr) - return; - - savePalette(); - - if (extraRef) - surf->refcount++; - fullSize.x = surf->w; - fullSize.y = surf->h; -} - -SDLImage::SDLImage(const JsonNode & conf) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - std::string filename = conf["file"].String(); - - surf = BitmapHandler::loadBitmap(filename); - - if(surf == nullptr) - return; - - savePalette(); - - const JsonNode & jsonMargins = conf["margins"]; - - margins.x = static_cast(jsonMargins["left"].Integer()); - margins.y = static_cast(jsonMargins["top"].Integer()); - - fullSize.x = static_cast(conf["width"].Integer()); - fullSize.y = static_cast(conf["height"].Integer()); - - if(fullSize.x == 0) - { - fullSize.x = margins.x + surf->w + (int)jsonMargins["right"].Integer(); - } - - if(fullSize.y == 0) - { - fullSize.y = margins.y + surf->h + (int)jsonMargins["bottom"].Integer(); - } -} - -SDLImage::SDLImage(std::string filename) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - surf = BitmapHandler::loadBitmap(filename); - - if(surf == nullptr) - { - logGlobal->error("Error: failed to load image %s", filename); - return; - } - else - { - savePalette(); - fullSize.x = surf->w; - fullSize.y = surf->h; - } -} - -void SDLImage::draw(SDL_Surface *where, int posX, int posY, const Rect *src) const -{ - if(!surf) - return; - - Rect destRect(posX, posY, surf->w, surf->h); - draw(where, &destRect, src); -} - -void SDLImage::draw(SDL_Surface* where, const Rect * dest, const Rect* src) const -{ - if (!surf) - return; - - Rect sourceRect(0, 0, surf->w, surf->h); - - Point destShift(0, 0); - - if(src) - { - if(src->x < margins.x) - destShift.x += margins.x - src->x; - - if(src->y < margins.y) - destShift.y += margins.y - src->y; - - sourceRect = Rect(*src).intersect(Rect(margins.x, margins.y, surf->w, surf->h)); - - sourceRect -= margins; - } - else - destShift = margins; - - if(dest) - destShift += dest->topLeft(); - - uint8_t perSurfaceAlpha; - if (SDL_GetSurfaceAlphaMod(surf, &perSurfaceAlpha) != 0) - logGlobal->error("SDL_GetSurfaceAlphaMod faied! %s", SDL_GetError()); - - if(surf->format->BitsPerPixel == 8 && perSurfaceAlpha == SDL_ALPHA_OPAQUE) - { - CSDL_Ext::blit8bppAlphaTo24bpp(surf, sourceRect, where, destShift); - } - else - { - CSDL_Ext::blitSurface(surf, sourceRect, where, destShift); - } -} - -std::shared_ptr SDLImage::scaleFast(const Point & size) const -{ - float scaleX = float(size.x) / width(); - float scaleY = float(size.y) / height(); - - auto scaled = CSDL_Ext::scaleSurfaceFast(surf, (int)(surf->w * scaleX), (int)(surf->h * scaleY)); - - if (scaled->format && scaled->format->palette) // fix color keying, because SDL loses it at this point - CSDL_Ext::setColorKey(scaled, scaled->format->palette->colors[0]); - else if(scaled->format && scaled->format->Amask) - SDL_SetSurfaceBlendMode(scaled, SDL_BLENDMODE_BLEND);//just in case - else - CSDL_Ext::setDefaultColorKey(scaled);//just in case - - SDLImage * ret = new SDLImage(scaled, false); - - ret->fullSize.x = (int) round((float)fullSize.x * scaleX); - ret->fullSize.y = (int) round((float)fullSize.y * scaleY); - - ret->margins.x = (int) round((float)margins.x * scaleX); - ret->margins.y = (int) round((float)margins.y * scaleY); - - return std::shared_ptr(ret); -} - -void SDLImage::exportBitmap(const boost::filesystem::path& path) const -{ - SDL_SaveBMP(surf, path.string().c_str()); -} - -void SDLImage::playerColored(PlayerColor player) -{ - graphics->blueToPlayersAdv(surf, player); -} - -void SDLImage::setAlpha(uint8_t value) -{ - CSDL_Ext::setAlpha (surf, value); - SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_BLEND); -} - -void SDLImage::setFlagColor(PlayerColor player) -{ - if(player < PlayerColor::PLAYER_LIMIT || player==PlayerColor::NEUTRAL) - CSDL_Ext::setPlayerColor(surf, player); -} - -bool SDLImage::isTransparent(const Point & coords) const -{ - return CSDL_Ext::isTransparent(surf, coords.x, coords.y); -} - -Point SDLImage::dimensions() const -{ - return fullSize; -} - -void SDLImage::horizontalFlip() -{ - margins.y = fullSize.y - surf->h - margins.y; - - //todo: modify in-place - SDL_Surface * flipped = CSDL_Ext::horizontalFlip(surf); - SDL_FreeSurface(surf); - surf = flipped; -} - -void SDLImage::verticalFlip() -{ - margins.x = fullSize.x - surf->w - margins.x; - - //todo: modify in-place - SDL_Surface * flipped = CSDL_Ext::verticalFlip(surf); - SDL_FreeSurface(surf); - surf = flipped; -} - -// Keep the original palette, in order to do color switching operation -void SDLImage::savePalette() -{ - // For some images that don't have palette, skip this - if(surf->format->palette == nullptr) - return; - - if(originalPalette == nullptr) - originalPalette = SDL_AllocPalette(DEFAULT_PALETTE_COLORS); - - SDL_SetPaletteColors(originalPalette, surf->format->palette->colors, 0, DEFAULT_PALETTE_COLORS); -} - -void SDLImage::shiftPalette(int from, int howMany) -{ - //works with at most 16 colors, if needed more -> increase values - assert(howMany < 16); - - if(surf->format->palette) - { - SDL_Color palette[16]; - - for(int i=0; iformat->palette->colors[from + i]; - } - CSDL_Ext::setColors(surf, palette, from, howMany); - } -} - -void SDLImage::adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) -{ - if(originalPalette == nullptr) - return; - - SDL_Palette* palette = surf->format->palette; - - // Note: here we skip first colors in the palette that are predefined in H3 images - for(int i = colorsToSkip; i < palette->ncolors; i++) - { - palette->colors[i] = shifter.shiftColor(originalPalette->colors[i]); - } -} - -void SDLImage::resetPalette() -{ - if(originalPalette == nullptr) - return; - - // Always keept the original palette not changed, copy a new palette to assign to surface - SDL_SetPaletteColors(surf->format->palette, originalPalette->colors, 0, originalPalette->ncolors); -} - -void SDLImage::resetPalette( int colorID ) -{ - if(originalPalette == nullptr) - return; - - // Always keept the original palette not changed, copy a new palette to assign to surface - SDL_SetPaletteColors(surf->format->palette, originalPalette->colors + colorID, colorID, 1); -} - -void SDLImage::setSpecialPallete(const IImage::SpecialPalette & SpecialPalette) -{ - if(surf->format->palette) - { - CSDL_Ext::setColors(surf, const_cast(SpecialPalette.data()), 1, 7); - } -} - -SDLImage::~SDLImage() -{ - SDL_FreeSurface(surf); - - if(originalPalette != nullptr) - { - SDL_FreePalette(originalPalette); - originalPalette = nullptr; - } -} - -std::shared_ptr CAnimation::getFromExtraDef(std::string filename) -{ - size_t pos = filename.find(':'); - if (pos == -1) - return nullptr; - CAnimation anim(filename.substr(0, pos)); - pos++; - size_t frame = atoi(filename.c_str()+pos); - size_t group = 0; - pos = filename.find(':', pos); - if (pos != -1) - { - pos++; - group = frame; - frame = atoi(filename.c_str()+pos); - } - anim.load(frame ,group); - auto ret = anim.images[group][frame]; - anim.images.clear(); - return ret; -} - -bool CAnimation::loadFrame(size_t frame, size_t group) -{ - if(size(group) <= frame) - { - printError(frame, group, "LoadFrame"); - return false; - } - - auto image = getImage(frame, group, false); - if(image) - { - return true; - } - - //try to get image from def - if(source[group][frame].getType() == JsonNode::JsonType::DATA_NULL) - { - if(defFile) - { - auto frameList = defFile->getEntries(); - - if(vstd::contains(frameList, group) && frameList.at(group) > frame) // frame is present - { - images[group][frame] = std::make_shared(defFile.get(), frame, group); - return true; - } - } - // still here? image is missing - - printError(frame, group, "LoadFrame"); - images[group][frame] = std::make_shared("DEFAULT"); - } - else //load from separate file - { - auto img = getFromExtraDef(source[group][frame]["file"].String()); - if(!img) - img = std::make_shared(source[group][frame]); - - images[group][frame] = img; - return true; - } - return false; -} - -bool CAnimation::unloadFrame(size_t frame, size_t group) -{ - auto image = getImage(frame, group, false); - if(image) - { - images[group].erase(frame); - - if(images[group].empty()) - images.erase(group); - return true; - } - return false; -} - -void CAnimation::initFromJson(const JsonNode & config) -{ - std::string basepath; - basepath = config["basepath"].String(); - - JsonNode base(JsonNode::JsonType::DATA_STRUCT); - base["margins"] = config["margins"]; - base["width"] = config["width"]; - base["height"] = config["height"]; - - for(const JsonNode & group : config["sequences"].Vector()) - { - size_t groupID = group["group"].Integer();//TODO: string-to-value conversion("moving" -> MOVING) - source[groupID].clear(); - - for(const JsonNode & frame : group["frames"].Vector()) - { - JsonNode toAdd(JsonNode::JsonType::DATA_STRUCT); - JsonUtils::inherit(toAdd, base); - toAdd["file"].String() = basepath + frame.String(); - source[groupID].push_back(toAdd); - } - } - - for(const JsonNode & node : config["images"].Vector()) - { - size_t group = node["group"].Integer(); - size_t frame = node["frame"].Integer(); - - if (source[group].size() <= frame) - source[group].resize(frame+1); - - JsonNode toAdd(JsonNode::JsonType::DATA_STRUCT); - JsonUtils::inherit(toAdd, base); - toAdd["file"].String() = basepath + node["file"].String(); - source[group][frame] = toAdd; - } -} - -void CAnimation::exportBitmaps(const boost::filesystem::path& path) const -{ - if(images.empty()) - { - logGlobal->error("Nothing to export, animation is empty"); - return; - } - - boost::filesystem::path actualPath = path / "SPRITES" / name; - boost::filesystem::create_directories(actualPath); - - size_t counter = 0; - - for(const auto & groupPair : images) - { - size_t group = groupPair.first; - - for(const auto & imagePair : groupPair.second) - { - size_t frame = imagePair.first; - const auto img = imagePair.second; - - boost::format fmt("%d_%d.bmp"); - fmt % group % frame; - - img->exportBitmap(actualPath / fmt.str()); - counter++; - } - } - - logGlobal->info("Exported %d frames to %s", counter, actualPath.string()); -} - -void CAnimation::init() -{ - if(defFile) - { - const std::map defEntries = defFile->getEntries(); - - for (auto & defEntry : defEntries) - source[defEntry.first].resize(defEntry.second); - } - - ResourceID resID(std::string("SPRITES/") + name, EResType::TEXT); - - if (vstd::contains(graphics->imageLists, resID.getName())) - initFromJson(graphics->imageLists[resID.getName()]); - - auto configList = CResourceHandler::get()->getResourcesWithName(resID); - - for(auto & loader : configList) - { - auto stream = loader->load(resID); - std::unique_ptr textData(new ui8[stream->getSize()]); - stream->read(textData.get(), stream->getSize()); - - const JsonNode config((char*)textData.get(), stream->getSize()); - - initFromJson(config); - } -} - -void CAnimation::printError(size_t frame, size_t group, std::string type) const -{ - logGlobal->error("%s error: Request for frame not present in CAnimation! File name: %s, Group: %d, Frame: %d", type, name, group, frame); -} - -CAnimation::CAnimation(std::string Name): - name(Name), - preloaded(false), - defFile() -{ - size_t dotPos = name.find_last_of('.'); - if ( dotPos!=-1 ) - name.erase(dotPos); - std::transform(name.begin(), name.end(), name.begin(), toupper); - - ResourceID resource(std::string("SPRITES/") + name, EResType::ANIMATION); - - if(CResourceHandler::get()->existsResource(resource)) - defFile = std::make_shared(name); - - init(); - - if(source.empty()) - logAnim->error("Animation %s failed to load", Name); -} - -CAnimation::CAnimation(): - name(""), - preloaded(false), - defFile() -{ - init(); -} - -CAnimation::~CAnimation() = default; - -void CAnimation::duplicateImage(const size_t sourceGroup, const size_t sourceFrame, const size_t targetGroup) -{ - if(!source.count(sourceGroup)) - { - logAnim->error("Group %d missing in %s", sourceGroup, name); - return; - } - - if(source[sourceGroup].size() <= sourceFrame) - { - logAnim->error("Frame [%d %d] missing in %s", sourceGroup, sourceFrame, name); - return; - } - - //todo: clone actual loaded Image object - JsonNode clone(source[sourceGroup][sourceFrame]); - - if(clone.getType() == JsonNode::JsonType::DATA_NULL) - { - std::string temp = name+":"+boost::lexical_cast(sourceGroup)+":"+boost::lexical_cast(sourceFrame); - clone["file"].String() = temp; - } - - source[targetGroup].push_back(clone); - - size_t index = source[targetGroup].size() - 1; - - if(preloaded) - load(index, targetGroup); -} - -void CAnimation::setCustom(std::string filename, size_t frame, size_t group) -{ - if (source[group].size() <= frame) - source[group].resize(frame+1); - source[group][frame]["file"].String() = filename; - //FIXME: update image if already loaded -} - -std::shared_ptr CAnimation::getImage(size_t frame, size_t group, bool verbose) const -{ - auto groupIter = images.find(group); - if (groupIter != images.end()) - { - auto imageIter = groupIter->second.find(frame); - if (imageIter != groupIter->second.end()) - return imageIter->second; - } - if (verbose) - printError(frame, group, "GetImage"); - return nullptr; -} - -void CAnimation::load() -{ - for (auto & elem : source) - for (size_t image=0; image < elem.second.size(); image++) - loadFrame(image, elem.first); -} - -void CAnimation::unload() -{ - for (auto & elem : source) - for (size_t image=0; image < elem.second.size(); image++) - unloadFrame(image, elem.first); - -} - -void CAnimation::preload() -{ - if(!preloaded) - { - preloaded = true; - load(); - } -} - -void CAnimation::loadGroup(size_t group) -{ - if (vstd::contains(source, group)) - for (size_t image=0; image < source[group].size(); image++) - loadFrame(image, group); -} - -void CAnimation::unloadGroup(size_t group) -{ - if (vstd::contains(source, group)) - for (size_t image=0; image < source[group].size(); image++) - unloadFrame(image, group); -} - -void CAnimation::load(size_t frame, size_t group) -{ - loadFrame(frame, group); -} - -void CAnimation::unload(size_t frame, size_t group) -{ - unloadFrame(frame, group); -} - -size_t CAnimation::size(size_t group) const -{ - auto iter = source.find(group); - if (iter != source.end()) - return iter->second.size(); - return 0; -} - -void CAnimation::horizontalFlip() -{ - for(auto & group : images) - for(auto & image : group.second) - image.second->horizontalFlip(); -} - -void CAnimation::verticalFlip() -{ - for(auto & group : images) - for(auto & image : group.second) - image.second->verticalFlip(); -} - -void CAnimation::playerColored(PlayerColor player) -{ - for(auto & group : images) - for(auto & image : group.second) - image.second->playerColored(player); -} - -void CAnimation::createFlippedGroup(const size_t sourceGroup, const size_t targetGroup) -{ - for(size_t frame = 0; frame < size(sourceGroup); ++frame) - { - duplicateImage(sourceGroup, frame, targetGroup); - - auto image = getImage(frame, targetGroup); - image->verticalFlip(); - } -} - float CFadeAnimation::initialCounter() const { if (fadingMode == EMode::OUT) diff --git a/client/render/CFadeAnimation.h b/client/render/CFadeAnimation.h index e5881c65f..e05bf40f3 100644 --- a/client/render/CFadeAnimation.h +++ b/client/render/CFadeAnimation.h @@ -32,133 +32,6 @@ struct SDL_Color; class CDefFile; class ColorFilter; -/* - * Base class for images, can be used for non-animation pictures as well - */ -class IImage -{ -public: - using SpecialPalette = std::array; - - //draws image on surface "where" at position - virtual void draw(SDL_Surface * where, int posX = 0, int posY = 0, const Rect * src = nullptr) const = 0; - virtual void draw(SDL_Surface * where, const Rect * dest, const Rect * src) const = 0; - - virtual std::shared_ptr scaleFast(const Point & size) const = 0; - - virtual void exportBitmap(const boost::filesystem::path & path) const = 0; - - //Change palette to specific player - virtual void playerColored(PlayerColor player)=0; - - //set special color for flag - virtual void setFlagColor(PlayerColor player)=0; - - //test transparency of specific pixel - virtual bool isTransparent(const Point & coords) const = 0; - - virtual Point dimensions() const = 0; - int width() const; - int height() const; - - //only indexed bitmaps, 16 colors maximum - virtual void shiftPalette(int from, int howMany) = 0; - virtual void adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) = 0; - virtual void resetPalette(int colorID) = 0; - virtual void resetPalette() = 0; - - virtual void setAlpha(uint8_t value) = 0; - - //only indexed bitmaps with 7 special colors - virtual void setSpecialPallete(const SpecialPalette & SpecialPalette) = 0; - - virtual void horizontalFlip() = 0; - virtual void verticalFlip() = 0; - - IImage(); - virtual ~IImage(); - - /// loads image from specified file. Returns 0-sized images on failure - static std::shared_ptr createFromFile( const std::string & path ); - - /// temporary compatibility method. Creates IImage from existing SDL_Surface - /// Surface will be shared, called must still free it with SDL_FreeSurface - static std::shared_ptr createFromSurface( SDL_Surface * source ); -}; - -/// Class for handling animation -class CAnimation -{ -private: - //source[group][position] - file with this frame, if string is empty - image located in def file - std::map > source; - - //bitmap[group][position], store objects with loaded bitmaps - std::map > > images; - - //animation file name - std::string name; - - bool preloaded; - - std::shared_ptr defFile; - - //loader, will be called by load(), require opened def file for loading from it. Returns true if image is loaded - bool loadFrame(size_t frame, size_t group); - - //unloadFrame, returns true if image has been unloaded ( either deleted or decreased refCount) - bool unloadFrame(size_t frame, size_t group); - - //initialize animation from file - void initFromJson(const JsonNode & input); - void init(); - - //to get rid of copy-pasting error message :] - void printError(size_t frame, size_t group, std::string type) const; - - //not a very nice method to get image from another def file - //TODO: remove after implementing resource manager - std::shared_ptr getFromExtraDef(std::string filename); - -public: - CAnimation(std::string Name); - CAnimation(); - ~CAnimation(); - - //duplicates frame at [sourceGroup, sourceFrame] as last frame in targetGroup - //and loads it if animation is preloaded - void duplicateImage(const size_t sourceGroup, const size_t sourceFrame, const size_t targetGroup); - - //add custom surface to the selected position. - void setCustom(std::string filename, size_t frame, size_t group=0); - - std::shared_ptr getImage(size_t frame, size_t group=0, bool verbose=true) const; - - void exportBitmaps(const boost::filesystem::path & path) const; - - //all available frames - void load (); - void unload(); - void preload(); - - //all frames from group - void loadGroup (size_t group); - void unloadGroup(size_t group); - - //single image - void load (size_t frame, size_t group=0); - void unload(size_t frame, size_t group=0); - - //total count of frames in group (including not loaded) - size_t size(size_t group=0) const; - - void horizontalFlip(); - void verticalFlip(); - void playerColored(PlayerColor player); - - void createFlippedGroup(const size_t sourceGroup, const size_t targetGroup); -}; - const float DEFAULT_DELTA = 0.05f; class CFadeAnimation diff --git a/client/render/IImage.h b/client/render/IImage.h index e5881c65f..d853fec7b 100644 --- a/client/render/IImage.h +++ b/client/render/IImage.h @@ -86,104 +86,3 @@ public: static std::shared_ptr createFromSurface( SDL_Surface * source ); }; -/// Class for handling animation -class CAnimation -{ -private: - //source[group][position] - file with this frame, if string is empty - image located in def file - std::map > source; - - //bitmap[group][position], store objects with loaded bitmaps - std::map > > images; - - //animation file name - std::string name; - - bool preloaded; - - std::shared_ptr defFile; - - //loader, will be called by load(), require opened def file for loading from it. Returns true if image is loaded - bool loadFrame(size_t frame, size_t group); - - //unloadFrame, returns true if image has been unloaded ( either deleted or decreased refCount) - bool unloadFrame(size_t frame, size_t group); - - //initialize animation from file - void initFromJson(const JsonNode & input); - void init(); - - //to get rid of copy-pasting error message :] - void printError(size_t frame, size_t group, std::string type) const; - - //not a very nice method to get image from another def file - //TODO: remove after implementing resource manager - std::shared_ptr getFromExtraDef(std::string filename); - -public: - CAnimation(std::string Name); - CAnimation(); - ~CAnimation(); - - //duplicates frame at [sourceGroup, sourceFrame] as last frame in targetGroup - //and loads it if animation is preloaded - void duplicateImage(const size_t sourceGroup, const size_t sourceFrame, const size_t targetGroup); - - //add custom surface to the selected position. - void setCustom(std::string filename, size_t frame, size_t group=0); - - std::shared_ptr getImage(size_t frame, size_t group=0, bool verbose=true) const; - - void exportBitmaps(const boost::filesystem::path & path) const; - - //all available frames - void load (); - void unload(); - void preload(); - - //all frames from group - void loadGroup (size_t group); - void unloadGroup(size_t group); - - //single image - void load (size_t frame, size_t group=0); - void unload(size_t frame, size_t group=0); - - //total count of frames in group (including not loaded) - size_t size(size_t group=0) const; - - void horizontalFlip(); - void verticalFlip(); - void playerColored(PlayerColor player); - - void createFlippedGroup(const size_t sourceGroup, const size_t targetGroup); -}; - -const float DEFAULT_DELTA = 0.05f; - -class CFadeAnimation -{ -public: - enum class EMode - { - NONE, IN, OUT - }; -private: - float delta; - SDL_Surface * fadingSurface; - bool fading; - float fadingCounter; - bool shouldFreeSurface; - - float initialCounter() const; - bool isFinished() const; -public: - EMode fadingMode; - - CFadeAnimation(); - ~CFadeAnimation(); - void init(EMode mode, SDL_Surface * sourceSurface, bool freeSurfaceAtEnd = false, float animDelta = DEFAULT_DELTA); - void update(); - void draw(SDL_Surface * targetSurface, const Point & targetPoint); - bool isFading() const { return fading; } -}; diff --git a/client/render/SDLImage.cpp b/client/render/SDLImage.cpp index 31a18f5e5..c6e609ad4 100644 --- a/client/render/SDLImage.cpp +++ b/client/render/SDLImage.cpp @@ -26,121 +26,6 @@ class SDLImageLoader; -typedef std::map > source_map; -typedef std::map image_map; -typedef std::map group_map; - -/// Class for def loading -/// After loading will store general info (palette and frame offsets) and pointer to file itself -class CDefFile -{ -private: - - PACKED_STRUCT_BEGIN - struct SSpriteDef - { - ui32 size; - ui32 format; /// format in which pixel data is stored - ui32 fullWidth; /// full width and height of frame, including borders - ui32 fullHeight; - ui32 width; /// width and height of pixel data, borders excluded - ui32 height; - si32 leftMargin; - si32 topMargin; - } PACKED_STRUCT_END; - //offset[group][frame] - offset of frame data in file - std::map > offset; - - std::unique_ptr data; - std::unique_ptr palette; - -public: - CDefFile(std::string Name); - ~CDefFile(); - - //load frame as SDL_Surface - template - void loadFrame(size_t frame, size_t group, ImageLoader &loader) const; - - const std::map getEntries() const; -}; - - -/* - * Wrapper around SDL_Surface - */ -class SDLImage : public IImage -{ -public: - - const static int DEFAULT_PALETTE_COLORS = 256; - - //Surface without empty borders - SDL_Surface * surf; - //size of left and top borders - Point margins; - //total size including borders - Point fullSize; - -public: - //Load image from def file - SDLImage(CDefFile *data, size_t frame, size_t group=0); - //Load from bitmap file - SDLImage(std::string filename); - - SDLImage(const JsonNode & conf); - //Create using existing surface, extraRef will increase refcount on SDL_Surface - SDLImage(SDL_Surface * from, bool extraRef); - ~SDLImage(); - - // Keep the original palette, in order to do color switching operation - void savePalette(); - - void draw(SDL_Surface * where, int posX=0, int posY=0, const Rect *src=nullptr) const override; - void draw(SDL_Surface * where, const Rect * dest, const Rect * src) const override; - std::shared_ptr scaleFast(const Point & size) const override; - void exportBitmap(const boost::filesystem::path & path) const override; - void playerColored(PlayerColor player) override; - void setFlagColor(PlayerColor player) override; - bool isTransparent(const Point & coords) const override; - Point dimensions() const override; - - void horizontalFlip() override; - void verticalFlip() override; - - void shiftPalette(int from, int howMany) override; - void adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) override; - void resetPalette(int colorID) override; - void resetPalette() override; - - void setAlpha(uint8_t value) override; - - void setSpecialPallete(const SpecialPalette & SpecialPalette) override; - - friend class SDLImageLoader; - -private: - SDL_Palette * originalPalette; -}; - -class SDLImageLoader -{ - SDLImage * image; - ui8 * lineStart; - ui8 * position; -public: - //load size raw pixels from data - inline void Load(size_t size, const ui8 * data); - //set size pixels to color - inline void Load(size_t size, ui8 color=0); - inline void EndLine(); - //init image with these sizes and palette - inline void init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal); - - SDLImageLoader(SDLImage * Img); - ~SDLImageLoader(); -}; - std::shared_ptr IImage::createFromFile( const std::string & path ) { return std::shared_ptr(new SDLImage(path)); @@ -151,408 +36,6 @@ std::shared_ptr IImage::createFromSurface( SDL_Surface * source ) return std::shared_ptr(new SDLImage(source, true)); } -// Extremely simple file cache. TODO: smarter, more general solution -class CFileCache -{ - static const int cacheSize = 50; //Max number of cached files - struct FileData - { - ResourceID name; - size_t size; - std::unique_ptr data; - - std::unique_ptr getCopy() - { - auto ret = std::unique_ptr(new ui8[size]); - std::copy(data.get(), data.get() + size, ret.get()); - return ret; - } - FileData(ResourceID name_, size_t size_, std::unique_ptr data_): - name{std::move(name_)}, - size{size_}, - data{std::move(data_)} - {} - }; - - std::deque cache; -public: - std::unique_ptr getCachedFile(ResourceID rid) - { - for(auto & file : cache) - { - if (file.name == rid) - return file.getCopy(); - } - // Still here? Cache miss - if (cache.size() > cacheSize) - cache.pop_front(); - - auto data = CResourceHandler::get()->load(rid)->readAll(); - - cache.emplace_back(std::move(rid), data.second, std::move(data.first)); - - return cache.back().getCopy(); - } -}; - -enum class DefType : uint32_t -{ - SPELL = 0x40, - SPRITE = 0x41, - CREATURE = 0x42, - MAP = 0x43, - MAP_HERO = 0x44, - TERRAIN = 0x45, - CURSOR = 0x46, - INTERFACE = 0x47, - SPRITE_FRAME = 0x48, - BATTLE_HERO = 0x49 -}; - -static CFileCache animationCache; - -/************************************************************************* - * DefFile, class used for def loading * - *************************************************************************/ - -bool operator== (const SDL_Color & lhs, const SDL_Color & rhs) -{ - return (lhs.a == rhs.a) && (lhs.b == rhs.b) &&(lhs.g == rhs.g) &&(lhs.r == rhs.r); -} - -CDefFile::CDefFile(std::string Name): - data(nullptr), - palette(nullptr) -{ - //First 8 colors in def palette used for transparency - static SDL_Color H3Palette[8] = - { - { 0, 0, 0, 0},// transparency ( used in most images ) - { 0, 0, 0, 64},// shadow border ( used in battle, adventure map def's ) - { 0, 0, 0, 64},// shadow border ( used in fog-of-war def's ) - { 0, 0, 0, 128},// shadow body ( used in fog-of-war def's ) - { 0, 0, 0, 128},// shadow body ( used in battle, adventure map def's ) - { 0, 0, 0, 0},// selection ( used in battle def's ) - { 0, 0, 0, 128},// shadow body below selection ( used in battle def's ) - { 0, 0, 0, 64} // shadow border below selection ( used in battle def's ) - }; - data = animationCache.getCachedFile(ResourceID(std::string("SPRITES/") + Name, EResType::ANIMATION)); - - palette = std::unique_ptr(new SDL_Color[256]); - int it = 0; - - ui32 type = read_le_u32(data.get() + it); - it+=4; - //int width = read_le_u32(data + it); it+=4;//not used - //int height = read_le_u32(data + it); it+=4; - it+=8; - ui32 totalBlocks = read_le_u32(data.get() + it); - it+=4; - - for (ui32 i= 0; i<256; i++) - { - palette[i].r = data[it++]; - palette[i].g = data[it++]; - palette[i].b = data[it++]; - palette[i].a = SDL_ALPHA_OPAQUE; - } - - switch(static_cast(type)) - { - case DefType::SPELL: - palette[0] = H3Palette[0]; - break; - case DefType::SPRITE: - case DefType::SPRITE_FRAME: - for(ui32 i= 0; i<8; i++) - palette[i] = H3Palette[i]; - break; - case DefType::CREATURE: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - palette[5] = H3Palette[5]; - palette[6] = H3Palette[6]; - palette[7] = H3Palette[7]; - break; - case DefType::MAP: - case DefType::MAP_HERO: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - //5 = owner flag, handled separately - break; - case DefType::TERRAIN: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[2] = H3Palette[2]; - palette[3] = H3Palette[3]; - palette[4] = H3Palette[4]; - break; - case DefType::CURSOR: - palette[0] = H3Palette[0]; - break; - case DefType::INTERFACE: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - //player colors handled separately - //TODO: disallow colorizing other def types - break; - case DefType::BATTLE_HERO: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - break; - default: - logAnim->error("Unknown def type %d in %s", type, Name); - break; - } - - - for (ui32 i=0; i -void CDefFile::loadFrame(size_t frame, size_t group, ImageLoader &loader) const -{ - std::map >::const_iterator it; - it = offset.find(group); - assert (it != offset.end()); - - const ui8 * FDef = data.get()+it->second[frame]; - - const SSpriteDef sd = * reinterpret_cast(FDef); - SSpriteDef sprite; - - sprite.format = read_le_u32(&sd.format); - sprite.fullWidth = read_le_u32(&sd.fullWidth); - sprite.fullHeight = read_le_u32(&sd.fullHeight); - sprite.width = read_le_u32(&sd.width); - sprite.height = read_le_u32(&sd.height); - sprite.leftMargin = read_le_u32(&sd.leftMargin); - sprite.topMargin = read_le_u32(&sd.topMargin); - - ui32 currentOffset = sizeof(SSpriteDef); - - //special case for some "old" format defs (SGTWMTA.DEF and SGTWMTB.DEF) - - if(sprite.format == 1 && sprite.width > sprite.fullWidth && sprite.height > sprite.fullHeight) - { - sprite.leftMargin = 0; - sprite.topMargin = 0; - sprite.width = sprite.fullWidth; - sprite.height = sprite.fullHeight; - - currentOffset -= 16; - } - - const ui32 BaseOffset = currentOffset; - - loader.init(Point(sprite.width, sprite.height), - Point(sprite.leftMargin, sprite.topMargin), - Point(sprite.fullWidth, sprite.fullHeight), palette.get()); - - switch(sprite.format) - { - case 0: - { - //pixel data is not compressed, copy data to surface - for(ui32 i=0; i(FDef+currentOffset); - currentOffset += sizeof(ui32) * sprite.height; - - for(ui32 i=0; ierror("Error: unsupported format of def file: %d", sprite.format); - break; - } -} - -CDefFile::~CDefFile() = default; - -const std::map CDefFile::getEntries() const -{ - std::map ret; - - for (auto & elem : offset) - ret[elem.first] = elem.second.size(); - return ret; -} - -/************************************************************************* - * Classes for image loaders - helpers for loading from def files * - *************************************************************************/ - -SDLImageLoader::SDLImageLoader(SDLImage * Img): - image(Img), - lineStart(nullptr), - position(nullptr) -{ -} - -void SDLImageLoader::init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal) -{ - //Init image - image->surf = SDL_CreateRGBSurface(0, SpriteSize.x, SpriteSize.y, 8, 0, 0, 0, 0); - image->margins = Margins; - image->fullSize = FullSize; - - //Prepare surface - SDL_Palette * p = SDL_AllocPalette(SDLImage::DEFAULT_PALETTE_COLORS); - SDL_SetPaletteColors(p, pal, 0, SDLImage::DEFAULT_PALETTE_COLORS); - SDL_SetSurfacePalette(image->surf, p); - SDL_FreePalette(p); - - SDL_LockSurface(image->surf); - lineStart = position = (ui8*)image->surf->pixels; -} - -inline void SDLImageLoader::Load(size_t size, const ui8 * data) -{ - if (size) - { - memcpy((void *)position, data, size); - position += size; - } -} - -inline void SDLImageLoader::Load(size_t size, ui8 color) -{ - if (size) - { - memset((void *)position, color, size); - position += size; - } -} - -inline void SDLImageLoader::EndLine() -{ - lineStart += image->surf->pitch; - position = lineStart; -} - -SDLImageLoader::~SDLImageLoader() -{ - SDL_UnlockSurface(image->surf); - SDL_SetColorKey(image->surf, SDL_TRUE, 0); - //TODO: RLE if compressed and bpp>1 -} - -/************************************************************************* - * Classes for images, support loading from file and drawing on surface * - *************************************************************************/ - IImage::IImage() = default; IImage::~IImage() = default; @@ -859,446 +342,3 @@ SDLImage::~SDLImage() } } -std::shared_ptr CAnimation::getFromExtraDef(std::string filename) -{ - size_t pos = filename.find(':'); - if (pos == -1) - return nullptr; - CAnimation anim(filename.substr(0, pos)); - pos++; - size_t frame = atoi(filename.c_str()+pos); - size_t group = 0; - pos = filename.find(':', pos); - if (pos != -1) - { - pos++; - group = frame; - frame = atoi(filename.c_str()+pos); - } - anim.load(frame ,group); - auto ret = anim.images[group][frame]; - anim.images.clear(); - return ret; -} - -bool CAnimation::loadFrame(size_t frame, size_t group) -{ - if(size(group) <= frame) - { - printError(frame, group, "LoadFrame"); - return false; - } - - auto image = getImage(frame, group, false); - if(image) - { - return true; - } - - //try to get image from def - if(source[group][frame].getType() == JsonNode::JsonType::DATA_NULL) - { - if(defFile) - { - auto frameList = defFile->getEntries(); - - if(vstd::contains(frameList, group) && frameList.at(group) > frame) // frame is present - { - images[group][frame] = std::make_shared(defFile.get(), frame, group); - return true; - } - } - // still here? image is missing - - printError(frame, group, "LoadFrame"); - images[group][frame] = std::make_shared("DEFAULT"); - } - else //load from separate file - { - auto img = getFromExtraDef(source[group][frame]["file"].String()); - if(!img) - img = std::make_shared(source[group][frame]); - - images[group][frame] = img; - return true; - } - return false; -} - -bool CAnimation::unloadFrame(size_t frame, size_t group) -{ - auto image = getImage(frame, group, false); - if(image) - { - images[group].erase(frame); - - if(images[group].empty()) - images.erase(group); - return true; - } - return false; -} - -void CAnimation::initFromJson(const JsonNode & config) -{ - std::string basepath; - basepath = config["basepath"].String(); - - JsonNode base(JsonNode::JsonType::DATA_STRUCT); - base["margins"] = config["margins"]; - base["width"] = config["width"]; - base["height"] = config["height"]; - - for(const JsonNode & group : config["sequences"].Vector()) - { - size_t groupID = group["group"].Integer();//TODO: string-to-value conversion("moving" -> MOVING) - source[groupID].clear(); - - for(const JsonNode & frame : group["frames"].Vector()) - { - JsonNode toAdd(JsonNode::JsonType::DATA_STRUCT); - JsonUtils::inherit(toAdd, base); - toAdd["file"].String() = basepath + frame.String(); - source[groupID].push_back(toAdd); - } - } - - for(const JsonNode & node : config["images"].Vector()) - { - size_t group = node["group"].Integer(); - size_t frame = node["frame"].Integer(); - - if (source[group].size() <= frame) - source[group].resize(frame+1); - - JsonNode toAdd(JsonNode::JsonType::DATA_STRUCT); - JsonUtils::inherit(toAdd, base); - toAdd["file"].String() = basepath + node["file"].String(); - source[group][frame] = toAdd; - } -} - -void CAnimation::exportBitmaps(const boost::filesystem::path& path) const -{ - if(images.empty()) - { - logGlobal->error("Nothing to export, animation is empty"); - return; - } - - boost::filesystem::path actualPath = path / "SPRITES" / name; - boost::filesystem::create_directories(actualPath); - - size_t counter = 0; - - for(const auto & groupPair : images) - { - size_t group = groupPair.first; - - for(const auto & imagePair : groupPair.second) - { - size_t frame = imagePair.first; - const auto img = imagePair.second; - - boost::format fmt("%d_%d.bmp"); - fmt % group % frame; - - img->exportBitmap(actualPath / fmt.str()); - counter++; - } - } - - logGlobal->info("Exported %d frames to %s", counter, actualPath.string()); -} - -void CAnimation::init() -{ - if(defFile) - { - const std::map defEntries = defFile->getEntries(); - - for (auto & defEntry : defEntries) - source[defEntry.first].resize(defEntry.second); - } - - ResourceID resID(std::string("SPRITES/") + name, EResType::TEXT); - - if (vstd::contains(graphics->imageLists, resID.getName())) - initFromJson(graphics->imageLists[resID.getName()]); - - auto configList = CResourceHandler::get()->getResourcesWithName(resID); - - for(auto & loader : configList) - { - auto stream = loader->load(resID); - std::unique_ptr textData(new ui8[stream->getSize()]); - stream->read(textData.get(), stream->getSize()); - - const JsonNode config((char*)textData.get(), stream->getSize()); - - initFromJson(config); - } -} - -void CAnimation::printError(size_t frame, size_t group, std::string type) const -{ - logGlobal->error("%s error: Request for frame not present in CAnimation! File name: %s, Group: %d, Frame: %d", type, name, group, frame); -} - -CAnimation::CAnimation(std::string Name): - name(Name), - preloaded(false), - defFile() -{ - size_t dotPos = name.find_last_of('.'); - if ( dotPos!=-1 ) - name.erase(dotPos); - std::transform(name.begin(), name.end(), name.begin(), toupper); - - ResourceID resource(std::string("SPRITES/") + name, EResType::ANIMATION); - - if(CResourceHandler::get()->existsResource(resource)) - defFile = std::make_shared(name); - - init(); - - if(source.empty()) - logAnim->error("Animation %s failed to load", Name); -} - -CAnimation::CAnimation(): - name(""), - preloaded(false), - defFile() -{ - init(); -} - -CAnimation::~CAnimation() = default; - -void CAnimation::duplicateImage(const size_t sourceGroup, const size_t sourceFrame, const size_t targetGroup) -{ - if(!source.count(sourceGroup)) - { - logAnim->error("Group %d missing in %s", sourceGroup, name); - return; - } - - if(source[sourceGroup].size() <= sourceFrame) - { - logAnim->error("Frame [%d %d] missing in %s", sourceGroup, sourceFrame, name); - return; - } - - //todo: clone actual loaded Image object - JsonNode clone(source[sourceGroup][sourceFrame]); - - if(clone.getType() == JsonNode::JsonType::DATA_NULL) - { - std::string temp = name+":"+boost::lexical_cast(sourceGroup)+":"+boost::lexical_cast(sourceFrame); - clone["file"].String() = temp; - } - - source[targetGroup].push_back(clone); - - size_t index = source[targetGroup].size() - 1; - - if(preloaded) - load(index, targetGroup); -} - -void CAnimation::setCustom(std::string filename, size_t frame, size_t group) -{ - if (source[group].size() <= frame) - source[group].resize(frame+1); - source[group][frame]["file"].String() = filename; - //FIXME: update image if already loaded -} - -std::shared_ptr CAnimation::getImage(size_t frame, size_t group, bool verbose) const -{ - auto groupIter = images.find(group); - if (groupIter != images.end()) - { - auto imageIter = groupIter->second.find(frame); - if (imageIter != groupIter->second.end()) - return imageIter->second; - } - if (verbose) - printError(frame, group, "GetImage"); - return nullptr; -} - -void CAnimation::load() -{ - for (auto & elem : source) - for (size_t image=0; image < elem.second.size(); image++) - loadFrame(image, elem.first); -} - -void CAnimation::unload() -{ - for (auto & elem : source) - for (size_t image=0; image < elem.second.size(); image++) - unloadFrame(image, elem.first); - -} - -void CAnimation::preload() -{ - if(!preloaded) - { - preloaded = true; - load(); - } -} - -void CAnimation::loadGroup(size_t group) -{ - if (vstd::contains(source, group)) - for (size_t image=0; image < source[group].size(); image++) - loadFrame(image, group); -} - -void CAnimation::unloadGroup(size_t group) -{ - if (vstd::contains(source, group)) - for (size_t image=0; image < source[group].size(); image++) - unloadFrame(image, group); -} - -void CAnimation::load(size_t frame, size_t group) -{ - loadFrame(frame, group); -} - -void CAnimation::unload(size_t frame, size_t group) -{ - unloadFrame(frame, group); -} - -size_t CAnimation::size(size_t group) const -{ - auto iter = source.find(group); - if (iter != source.end()) - return iter->second.size(); - return 0; -} - -void CAnimation::horizontalFlip() -{ - for(auto & group : images) - for(auto & image : group.second) - image.second->horizontalFlip(); -} - -void CAnimation::verticalFlip() -{ - for(auto & group : images) - for(auto & image : group.second) - image.second->verticalFlip(); -} - -void CAnimation::playerColored(PlayerColor player) -{ - for(auto & group : images) - for(auto & image : group.second) - image.second->playerColored(player); -} - -void CAnimation::createFlippedGroup(const size_t sourceGroup, const size_t targetGroup) -{ - for(size_t frame = 0; frame < size(sourceGroup); ++frame) - { - duplicateImage(sourceGroup, frame, targetGroup); - - auto image = getImage(frame, targetGroup); - image->verticalFlip(); - } -} - -float CFadeAnimation::initialCounter() const -{ - if (fadingMode == EMode::OUT) - return 1.0f; - return 0.0f; -} - -void CFadeAnimation::update() -{ - if (!fading) - return; - - if (fadingMode == EMode::OUT) - fadingCounter -= delta; - else - fadingCounter += delta; - - if (isFinished()) - { - fading = false; - if (shouldFreeSurface) - { - SDL_FreeSurface(fadingSurface); - fadingSurface = nullptr; - } - } -} - -bool CFadeAnimation::isFinished() const -{ - if (fadingMode == EMode::OUT) - return fadingCounter <= 0.0f; - return fadingCounter >= 1.0f; -} - -CFadeAnimation::CFadeAnimation() - : delta(0), fadingSurface(nullptr), fading(false), fadingCounter(0), shouldFreeSurface(false), - fadingMode(EMode::NONE) -{ -} - -CFadeAnimation::~CFadeAnimation() -{ - if (fadingSurface && shouldFreeSurface) - SDL_FreeSurface(fadingSurface); -} - -void CFadeAnimation::init(EMode mode, SDL_Surface * sourceSurface, bool freeSurfaceAtEnd, float animDelta) -{ - if (fading) - { - // in that case, immediately finish the previous fade - // (alternatively, we could just return here to ignore the new fade request until this one finished (but we'd need to free the passed bitmap to avoid leaks)) - logGlobal->warn("Tried to init fading animation that is already running."); - if (fadingSurface && shouldFreeSurface) - SDL_FreeSurface(fadingSurface); - } - if (animDelta <= 0.0f) - { - logGlobal->warn("Fade anim: delta should be positive; %f given.", animDelta); - animDelta = DEFAULT_DELTA; - } - - if (sourceSurface) - fadingSurface = sourceSurface; - - delta = animDelta; - fadingMode = mode; - fadingCounter = initialCounter(); - fading = true; - shouldFreeSurface = freeSurfaceAtEnd; -} - -void CFadeAnimation::draw(SDL_Surface * targetSurface, const Point &targetPoint) -{ - if (!fading || !fadingSurface || fadingMode == EMode::NONE) - { - fading = false; - return; - } - - CSDL_Ext::setAlpha(fadingSurface, (int)(fadingCounter * 255)); - CSDL_Ext::blitSurface(fadingSurface, targetSurface, targetPoint); //FIXME - CSDL_Ext::setAlpha(fadingSurface, 255); -} diff --git a/client/render/SDLImage.h b/client/render/SDLImage.h new file mode 100644 index 000000000..beba79942 --- /dev/null +++ b/client/render/SDLImage.h @@ -0,0 +1,90 @@ +/* + * CAnimation.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include "../../lib/GameConstants.h" + +#ifdef IN +#undef IN +#endif + +#ifdef OUT +#undef OUT +#endif + +VCMI_LIB_NAMESPACE_BEGIN + +class JsonNode; +class Rect; +class Point; + +VCMI_LIB_NAMESPACE_END + +struct SDL_Surface; +struct SDL_Color; +class CDefFile; +class ColorFilter; + +/* + * Wrapper around SDL_Surface + */ +class SDLImage : public IImage +{ +public: + + const static int DEFAULT_PALETTE_COLORS = 256; + + //Surface without empty borders + SDL_Surface * surf; + //size of left and top borders + Point margins; + //total size including borders + Point fullSize; + +public: + //Load image from def file + SDLImage(CDefFile *data, size_t frame, size_t group=0); + //Load from bitmap file + SDLImage(std::string filename); + + SDLImage(const JsonNode & conf); + //Create using existing surface, extraRef will increase refcount on SDL_Surface + SDLImage(SDL_Surface * from, bool extraRef); + ~SDLImage(); + + // Keep the original palette, in order to do color switching operation + void savePalette(); + + void draw(SDL_Surface * where, int posX=0, int posY=0, const Rect *src=nullptr) const override; + void draw(SDL_Surface * where, const Rect * dest, const Rect * src) const override; + std::shared_ptr scaleFast(const Point & size) const override; + void exportBitmap(const boost::filesystem::path & path) const override; + void playerColored(PlayerColor player) override; + void setFlagColor(PlayerColor player) override; + bool isTransparent(const Point & coords) const override; + Point dimensions() const override; + + void horizontalFlip() override; + void verticalFlip() override; + + void shiftPalette(int from, int howMany) override; + void adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) override; + void resetPalette(int colorID) override; + void resetPalette() override; + + void setAlpha(uint8_t value) override; + + void setSpecialPallete(const SpecialPalette & SpecialPalette) override; + + friend class SDLImageLoader; + +private: + SDL_Palette * originalPalette; +}; diff --git a/client/render/SDLImageLoader.cpp b/client/render/SDLImageLoader.cpp index 31a18f5e5..82f287fba 100644 --- a/client/render/SDLImageLoader.cpp +++ b/client/render/SDLImageLoader.cpp @@ -24,472 +24,6 @@ #include -class SDLImageLoader; - -typedef std::map > source_map; -typedef std::map image_map; -typedef std::map group_map; - -/// Class for def loading -/// After loading will store general info (palette and frame offsets) and pointer to file itself -class CDefFile -{ -private: - - PACKED_STRUCT_BEGIN - struct SSpriteDef - { - ui32 size; - ui32 format; /// format in which pixel data is stored - ui32 fullWidth; /// full width and height of frame, including borders - ui32 fullHeight; - ui32 width; /// width and height of pixel data, borders excluded - ui32 height; - si32 leftMargin; - si32 topMargin; - } PACKED_STRUCT_END; - //offset[group][frame] - offset of frame data in file - std::map > offset; - - std::unique_ptr data; - std::unique_ptr palette; - -public: - CDefFile(std::string Name); - ~CDefFile(); - - //load frame as SDL_Surface - template - void loadFrame(size_t frame, size_t group, ImageLoader &loader) const; - - const std::map getEntries() const; -}; - - -/* - * Wrapper around SDL_Surface - */ -class SDLImage : public IImage -{ -public: - - const static int DEFAULT_PALETTE_COLORS = 256; - - //Surface without empty borders - SDL_Surface * surf; - //size of left and top borders - Point margins; - //total size including borders - Point fullSize; - -public: - //Load image from def file - SDLImage(CDefFile *data, size_t frame, size_t group=0); - //Load from bitmap file - SDLImage(std::string filename); - - SDLImage(const JsonNode & conf); - //Create using existing surface, extraRef will increase refcount on SDL_Surface - SDLImage(SDL_Surface * from, bool extraRef); - ~SDLImage(); - - // Keep the original palette, in order to do color switching operation - void savePalette(); - - void draw(SDL_Surface * where, int posX=0, int posY=0, const Rect *src=nullptr) const override; - void draw(SDL_Surface * where, const Rect * dest, const Rect * src) const override; - std::shared_ptr scaleFast(const Point & size) const override; - void exportBitmap(const boost::filesystem::path & path) const override; - void playerColored(PlayerColor player) override; - void setFlagColor(PlayerColor player) override; - bool isTransparent(const Point & coords) const override; - Point dimensions() const override; - - void horizontalFlip() override; - void verticalFlip() override; - - void shiftPalette(int from, int howMany) override; - void adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) override; - void resetPalette(int colorID) override; - void resetPalette() override; - - void setAlpha(uint8_t value) override; - - void setSpecialPallete(const SpecialPalette & SpecialPalette) override; - - friend class SDLImageLoader; - -private: - SDL_Palette * originalPalette; -}; - -class SDLImageLoader -{ - SDLImage * image; - ui8 * lineStart; - ui8 * position; -public: - //load size raw pixels from data - inline void Load(size_t size, const ui8 * data); - //set size pixels to color - inline void Load(size_t size, ui8 color=0); - inline void EndLine(); - //init image with these sizes and palette - inline void init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal); - - SDLImageLoader(SDLImage * Img); - ~SDLImageLoader(); -}; - -std::shared_ptr IImage::createFromFile( const std::string & path ) -{ - return std::shared_ptr(new SDLImage(path)); -} - -std::shared_ptr IImage::createFromSurface( SDL_Surface * source ) -{ - return std::shared_ptr(new SDLImage(source, true)); -} - -// Extremely simple file cache. TODO: smarter, more general solution -class CFileCache -{ - static const int cacheSize = 50; //Max number of cached files - struct FileData - { - ResourceID name; - size_t size; - std::unique_ptr data; - - std::unique_ptr getCopy() - { - auto ret = std::unique_ptr(new ui8[size]); - std::copy(data.get(), data.get() + size, ret.get()); - return ret; - } - FileData(ResourceID name_, size_t size_, std::unique_ptr data_): - name{std::move(name_)}, - size{size_}, - data{std::move(data_)} - {} - }; - - std::deque cache; -public: - std::unique_ptr getCachedFile(ResourceID rid) - { - for(auto & file : cache) - { - if (file.name == rid) - return file.getCopy(); - } - // Still here? Cache miss - if (cache.size() > cacheSize) - cache.pop_front(); - - auto data = CResourceHandler::get()->load(rid)->readAll(); - - cache.emplace_back(std::move(rid), data.second, std::move(data.first)); - - return cache.back().getCopy(); - } -}; - -enum class DefType : uint32_t -{ - SPELL = 0x40, - SPRITE = 0x41, - CREATURE = 0x42, - MAP = 0x43, - MAP_HERO = 0x44, - TERRAIN = 0x45, - CURSOR = 0x46, - INTERFACE = 0x47, - SPRITE_FRAME = 0x48, - BATTLE_HERO = 0x49 -}; - -static CFileCache animationCache; - -/************************************************************************* - * DefFile, class used for def loading * - *************************************************************************/ - -bool operator== (const SDL_Color & lhs, const SDL_Color & rhs) -{ - return (lhs.a == rhs.a) && (lhs.b == rhs.b) &&(lhs.g == rhs.g) &&(lhs.r == rhs.r); -} - -CDefFile::CDefFile(std::string Name): - data(nullptr), - palette(nullptr) -{ - //First 8 colors in def palette used for transparency - static SDL_Color H3Palette[8] = - { - { 0, 0, 0, 0},// transparency ( used in most images ) - { 0, 0, 0, 64},// shadow border ( used in battle, adventure map def's ) - { 0, 0, 0, 64},// shadow border ( used in fog-of-war def's ) - { 0, 0, 0, 128},// shadow body ( used in fog-of-war def's ) - { 0, 0, 0, 128},// shadow body ( used in battle, adventure map def's ) - { 0, 0, 0, 0},// selection ( used in battle def's ) - { 0, 0, 0, 128},// shadow body below selection ( used in battle def's ) - { 0, 0, 0, 64} // shadow border below selection ( used in battle def's ) - }; - data = animationCache.getCachedFile(ResourceID(std::string("SPRITES/") + Name, EResType::ANIMATION)); - - palette = std::unique_ptr(new SDL_Color[256]); - int it = 0; - - ui32 type = read_le_u32(data.get() + it); - it+=4; - //int width = read_le_u32(data + it); it+=4;//not used - //int height = read_le_u32(data + it); it+=4; - it+=8; - ui32 totalBlocks = read_le_u32(data.get() + it); - it+=4; - - for (ui32 i= 0; i<256; i++) - { - palette[i].r = data[it++]; - palette[i].g = data[it++]; - palette[i].b = data[it++]; - palette[i].a = SDL_ALPHA_OPAQUE; - } - - switch(static_cast(type)) - { - case DefType::SPELL: - palette[0] = H3Palette[0]; - break; - case DefType::SPRITE: - case DefType::SPRITE_FRAME: - for(ui32 i= 0; i<8; i++) - palette[i] = H3Palette[i]; - break; - case DefType::CREATURE: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - palette[5] = H3Palette[5]; - palette[6] = H3Palette[6]; - palette[7] = H3Palette[7]; - break; - case DefType::MAP: - case DefType::MAP_HERO: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - //5 = owner flag, handled separately - break; - case DefType::TERRAIN: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[2] = H3Palette[2]; - palette[3] = H3Palette[3]; - palette[4] = H3Palette[4]; - break; - case DefType::CURSOR: - palette[0] = H3Palette[0]; - break; - case DefType::INTERFACE: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - //player colors handled separately - //TODO: disallow colorizing other def types - break; - case DefType::BATTLE_HERO: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - break; - default: - logAnim->error("Unknown def type %d in %s", type, Name); - break; - } - - - for (ui32 i=0; i -void CDefFile::loadFrame(size_t frame, size_t group, ImageLoader &loader) const -{ - std::map >::const_iterator it; - it = offset.find(group); - assert (it != offset.end()); - - const ui8 * FDef = data.get()+it->second[frame]; - - const SSpriteDef sd = * reinterpret_cast(FDef); - SSpriteDef sprite; - - sprite.format = read_le_u32(&sd.format); - sprite.fullWidth = read_le_u32(&sd.fullWidth); - sprite.fullHeight = read_le_u32(&sd.fullHeight); - sprite.width = read_le_u32(&sd.width); - sprite.height = read_le_u32(&sd.height); - sprite.leftMargin = read_le_u32(&sd.leftMargin); - sprite.topMargin = read_le_u32(&sd.topMargin); - - ui32 currentOffset = sizeof(SSpriteDef); - - //special case for some "old" format defs (SGTWMTA.DEF and SGTWMTB.DEF) - - if(sprite.format == 1 && sprite.width > sprite.fullWidth && sprite.height > sprite.fullHeight) - { - sprite.leftMargin = 0; - sprite.topMargin = 0; - sprite.width = sprite.fullWidth; - sprite.height = sprite.fullHeight; - - currentOffset -= 16; - } - - const ui32 BaseOffset = currentOffset; - - loader.init(Point(sprite.width, sprite.height), - Point(sprite.leftMargin, sprite.topMargin), - Point(sprite.fullWidth, sprite.fullHeight), palette.get()); - - switch(sprite.format) - { - case 0: - { - //pixel data is not compressed, copy data to surface - for(ui32 i=0; i(FDef+currentOffset); - currentOffset += sizeof(ui32) * sprite.height; - - for(ui32 i=0; ierror("Error: unsupported format of def file: %d", sprite.format); - break; - } -} - -CDefFile::~CDefFile() = default; - -const std::map CDefFile::getEntries() const -{ - std::map ret; - - for (auto & elem : offset) - ret[elem.first] = elem.second.size(); - return ret; -} - /************************************************************************* * Classes for image loaders - helpers for loading from def files * *************************************************************************/ @@ -549,756 +83,3 @@ SDLImageLoader::~SDLImageLoader() //TODO: RLE if compressed and bpp>1 } -/************************************************************************* - * Classes for images, support loading from file and drawing on surface * - *************************************************************************/ - -IImage::IImage() = default; -IImage::~IImage() = default; - -int IImage::width() const -{ - return dimensions().x; -} - -int IImage::height() const -{ - return dimensions().y; -} - -SDLImage::SDLImage(CDefFile * data, size_t frame, size_t group) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - SDLImageLoader loader(this); - data->loadFrame(frame, group, loader); - - savePalette(); -} - -SDLImage::SDLImage(SDL_Surface * from, bool extraRef) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - surf = from; - if (surf == nullptr) - return; - - savePalette(); - - if (extraRef) - surf->refcount++; - fullSize.x = surf->w; - fullSize.y = surf->h; -} - -SDLImage::SDLImage(const JsonNode & conf) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - std::string filename = conf["file"].String(); - - surf = BitmapHandler::loadBitmap(filename); - - if(surf == nullptr) - return; - - savePalette(); - - const JsonNode & jsonMargins = conf["margins"]; - - margins.x = static_cast(jsonMargins["left"].Integer()); - margins.y = static_cast(jsonMargins["top"].Integer()); - - fullSize.x = static_cast(conf["width"].Integer()); - fullSize.y = static_cast(conf["height"].Integer()); - - if(fullSize.x == 0) - { - fullSize.x = margins.x + surf->w + (int)jsonMargins["right"].Integer(); - } - - if(fullSize.y == 0) - { - fullSize.y = margins.y + surf->h + (int)jsonMargins["bottom"].Integer(); - } -} - -SDLImage::SDLImage(std::string filename) - : surf(nullptr), - margins(0, 0), - fullSize(0, 0), - originalPalette(nullptr) -{ - surf = BitmapHandler::loadBitmap(filename); - - if(surf == nullptr) - { - logGlobal->error("Error: failed to load image %s", filename); - return; - } - else - { - savePalette(); - fullSize.x = surf->w; - fullSize.y = surf->h; - } -} - -void SDLImage::draw(SDL_Surface *where, int posX, int posY, const Rect *src) const -{ - if(!surf) - return; - - Rect destRect(posX, posY, surf->w, surf->h); - draw(where, &destRect, src); -} - -void SDLImage::draw(SDL_Surface* where, const Rect * dest, const Rect* src) const -{ - if (!surf) - return; - - Rect sourceRect(0, 0, surf->w, surf->h); - - Point destShift(0, 0); - - if(src) - { - if(src->x < margins.x) - destShift.x += margins.x - src->x; - - if(src->y < margins.y) - destShift.y += margins.y - src->y; - - sourceRect = Rect(*src).intersect(Rect(margins.x, margins.y, surf->w, surf->h)); - - sourceRect -= margins; - } - else - destShift = margins; - - if(dest) - destShift += dest->topLeft(); - - uint8_t perSurfaceAlpha; - if (SDL_GetSurfaceAlphaMod(surf, &perSurfaceAlpha) != 0) - logGlobal->error("SDL_GetSurfaceAlphaMod faied! %s", SDL_GetError()); - - if(surf->format->BitsPerPixel == 8 && perSurfaceAlpha == SDL_ALPHA_OPAQUE) - { - CSDL_Ext::blit8bppAlphaTo24bpp(surf, sourceRect, where, destShift); - } - else - { - CSDL_Ext::blitSurface(surf, sourceRect, where, destShift); - } -} - -std::shared_ptr SDLImage::scaleFast(const Point & size) const -{ - float scaleX = float(size.x) / width(); - float scaleY = float(size.y) / height(); - - auto scaled = CSDL_Ext::scaleSurfaceFast(surf, (int)(surf->w * scaleX), (int)(surf->h * scaleY)); - - if (scaled->format && scaled->format->palette) // fix color keying, because SDL loses it at this point - CSDL_Ext::setColorKey(scaled, scaled->format->palette->colors[0]); - else if(scaled->format && scaled->format->Amask) - SDL_SetSurfaceBlendMode(scaled, SDL_BLENDMODE_BLEND);//just in case - else - CSDL_Ext::setDefaultColorKey(scaled);//just in case - - SDLImage * ret = new SDLImage(scaled, false); - - ret->fullSize.x = (int) round((float)fullSize.x * scaleX); - ret->fullSize.y = (int) round((float)fullSize.y * scaleY); - - ret->margins.x = (int) round((float)margins.x * scaleX); - ret->margins.y = (int) round((float)margins.y * scaleY); - - return std::shared_ptr(ret); -} - -void SDLImage::exportBitmap(const boost::filesystem::path& path) const -{ - SDL_SaveBMP(surf, path.string().c_str()); -} - -void SDLImage::playerColored(PlayerColor player) -{ - graphics->blueToPlayersAdv(surf, player); -} - -void SDLImage::setAlpha(uint8_t value) -{ - CSDL_Ext::setAlpha (surf, value); - SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_BLEND); -} - -void SDLImage::setFlagColor(PlayerColor player) -{ - if(player < PlayerColor::PLAYER_LIMIT || player==PlayerColor::NEUTRAL) - CSDL_Ext::setPlayerColor(surf, player); -} - -bool SDLImage::isTransparent(const Point & coords) const -{ - return CSDL_Ext::isTransparent(surf, coords.x, coords.y); -} - -Point SDLImage::dimensions() const -{ - return fullSize; -} - -void SDLImage::horizontalFlip() -{ - margins.y = fullSize.y - surf->h - margins.y; - - //todo: modify in-place - SDL_Surface * flipped = CSDL_Ext::horizontalFlip(surf); - SDL_FreeSurface(surf); - surf = flipped; -} - -void SDLImage::verticalFlip() -{ - margins.x = fullSize.x - surf->w - margins.x; - - //todo: modify in-place - SDL_Surface * flipped = CSDL_Ext::verticalFlip(surf); - SDL_FreeSurface(surf); - surf = flipped; -} - -// Keep the original palette, in order to do color switching operation -void SDLImage::savePalette() -{ - // For some images that don't have palette, skip this - if(surf->format->palette == nullptr) - return; - - if(originalPalette == nullptr) - originalPalette = SDL_AllocPalette(DEFAULT_PALETTE_COLORS); - - SDL_SetPaletteColors(originalPalette, surf->format->palette->colors, 0, DEFAULT_PALETTE_COLORS); -} - -void SDLImage::shiftPalette(int from, int howMany) -{ - //works with at most 16 colors, if needed more -> increase values - assert(howMany < 16); - - if(surf->format->palette) - { - SDL_Color palette[16]; - - for(int i=0; iformat->palette->colors[from + i]; - } - CSDL_Ext::setColors(surf, palette, from, howMany); - } -} - -void SDLImage::adjustPalette(const ColorFilter & shifter, size_t colorsToSkip) -{ - if(originalPalette == nullptr) - return; - - SDL_Palette* palette = surf->format->palette; - - // Note: here we skip first colors in the palette that are predefined in H3 images - for(int i = colorsToSkip; i < palette->ncolors; i++) - { - palette->colors[i] = shifter.shiftColor(originalPalette->colors[i]); - } -} - -void SDLImage::resetPalette() -{ - if(originalPalette == nullptr) - return; - - // Always keept the original palette not changed, copy a new palette to assign to surface - SDL_SetPaletteColors(surf->format->palette, originalPalette->colors, 0, originalPalette->ncolors); -} - -void SDLImage::resetPalette( int colorID ) -{ - if(originalPalette == nullptr) - return; - - // Always keept the original palette not changed, copy a new palette to assign to surface - SDL_SetPaletteColors(surf->format->palette, originalPalette->colors + colorID, colorID, 1); -} - -void SDLImage::setSpecialPallete(const IImage::SpecialPalette & SpecialPalette) -{ - if(surf->format->palette) - { - CSDL_Ext::setColors(surf, const_cast(SpecialPalette.data()), 1, 7); - } -} - -SDLImage::~SDLImage() -{ - SDL_FreeSurface(surf); - - if(originalPalette != nullptr) - { - SDL_FreePalette(originalPalette); - originalPalette = nullptr; - } -} - -std::shared_ptr CAnimation::getFromExtraDef(std::string filename) -{ - size_t pos = filename.find(':'); - if (pos == -1) - return nullptr; - CAnimation anim(filename.substr(0, pos)); - pos++; - size_t frame = atoi(filename.c_str()+pos); - size_t group = 0; - pos = filename.find(':', pos); - if (pos != -1) - { - pos++; - group = frame; - frame = atoi(filename.c_str()+pos); - } - anim.load(frame ,group); - auto ret = anim.images[group][frame]; - anim.images.clear(); - return ret; -} - -bool CAnimation::loadFrame(size_t frame, size_t group) -{ - if(size(group) <= frame) - { - printError(frame, group, "LoadFrame"); - return false; - } - - auto image = getImage(frame, group, false); - if(image) - { - return true; - } - - //try to get image from def - if(source[group][frame].getType() == JsonNode::JsonType::DATA_NULL) - { - if(defFile) - { - auto frameList = defFile->getEntries(); - - if(vstd::contains(frameList, group) && frameList.at(group) > frame) // frame is present - { - images[group][frame] = std::make_shared(defFile.get(), frame, group); - return true; - } - } - // still here? image is missing - - printError(frame, group, "LoadFrame"); - images[group][frame] = std::make_shared("DEFAULT"); - } - else //load from separate file - { - auto img = getFromExtraDef(source[group][frame]["file"].String()); - if(!img) - img = std::make_shared(source[group][frame]); - - images[group][frame] = img; - return true; - } - return false; -} - -bool CAnimation::unloadFrame(size_t frame, size_t group) -{ - auto image = getImage(frame, group, false); - if(image) - { - images[group].erase(frame); - - if(images[group].empty()) - images.erase(group); - return true; - } - return false; -} - -void CAnimation::initFromJson(const JsonNode & config) -{ - std::string basepath; - basepath = config["basepath"].String(); - - JsonNode base(JsonNode::JsonType::DATA_STRUCT); - base["margins"] = config["margins"]; - base["width"] = config["width"]; - base["height"] = config["height"]; - - for(const JsonNode & group : config["sequences"].Vector()) - { - size_t groupID = group["group"].Integer();//TODO: string-to-value conversion("moving" -> MOVING) - source[groupID].clear(); - - for(const JsonNode & frame : group["frames"].Vector()) - { - JsonNode toAdd(JsonNode::JsonType::DATA_STRUCT); - JsonUtils::inherit(toAdd, base); - toAdd["file"].String() = basepath + frame.String(); - source[groupID].push_back(toAdd); - } - } - - for(const JsonNode & node : config["images"].Vector()) - { - size_t group = node["group"].Integer(); - size_t frame = node["frame"].Integer(); - - if (source[group].size() <= frame) - source[group].resize(frame+1); - - JsonNode toAdd(JsonNode::JsonType::DATA_STRUCT); - JsonUtils::inherit(toAdd, base); - toAdd["file"].String() = basepath + node["file"].String(); - source[group][frame] = toAdd; - } -} - -void CAnimation::exportBitmaps(const boost::filesystem::path& path) const -{ - if(images.empty()) - { - logGlobal->error("Nothing to export, animation is empty"); - return; - } - - boost::filesystem::path actualPath = path / "SPRITES" / name; - boost::filesystem::create_directories(actualPath); - - size_t counter = 0; - - for(const auto & groupPair : images) - { - size_t group = groupPair.first; - - for(const auto & imagePair : groupPair.second) - { - size_t frame = imagePair.first; - const auto img = imagePair.second; - - boost::format fmt("%d_%d.bmp"); - fmt % group % frame; - - img->exportBitmap(actualPath / fmt.str()); - counter++; - } - } - - logGlobal->info("Exported %d frames to %s", counter, actualPath.string()); -} - -void CAnimation::init() -{ - if(defFile) - { - const std::map defEntries = defFile->getEntries(); - - for (auto & defEntry : defEntries) - source[defEntry.first].resize(defEntry.second); - } - - ResourceID resID(std::string("SPRITES/") + name, EResType::TEXT); - - if (vstd::contains(graphics->imageLists, resID.getName())) - initFromJson(graphics->imageLists[resID.getName()]); - - auto configList = CResourceHandler::get()->getResourcesWithName(resID); - - for(auto & loader : configList) - { - auto stream = loader->load(resID); - std::unique_ptr textData(new ui8[stream->getSize()]); - stream->read(textData.get(), stream->getSize()); - - const JsonNode config((char*)textData.get(), stream->getSize()); - - initFromJson(config); - } -} - -void CAnimation::printError(size_t frame, size_t group, std::string type) const -{ - logGlobal->error("%s error: Request for frame not present in CAnimation! File name: %s, Group: %d, Frame: %d", type, name, group, frame); -} - -CAnimation::CAnimation(std::string Name): - name(Name), - preloaded(false), - defFile() -{ - size_t dotPos = name.find_last_of('.'); - if ( dotPos!=-1 ) - name.erase(dotPos); - std::transform(name.begin(), name.end(), name.begin(), toupper); - - ResourceID resource(std::string("SPRITES/") + name, EResType::ANIMATION); - - if(CResourceHandler::get()->existsResource(resource)) - defFile = std::make_shared(name); - - init(); - - if(source.empty()) - logAnim->error("Animation %s failed to load", Name); -} - -CAnimation::CAnimation(): - name(""), - preloaded(false), - defFile() -{ - init(); -} - -CAnimation::~CAnimation() = default; - -void CAnimation::duplicateImage(const size_t sourceGroup, const size_t sourceFrame, const size_t targetGroup) -{ - if(!source.count(sourceGroup)) - { - logAnim->error("Group %d missing in %s", sourceGroup, name); - return; - } - - if(source[sourceGroup].size() <= sourceFrame) - { - logAnim->error("Frame [%d %d] missing in %s", sourceGroup, sourceFrame, name); - return; - } - - //todo: clone actual loaded Image object - JsonNode clone(source[sourceGroup][sourceFrame]); - - if(clone.getType() == JsonNode::JsonType::DATA_NULL) - { - std::string temp = name+":"+boost::lexical_cast(sourceGroup)+":"+boost::lexical_cast(sourceFrame); - clone["file"].String() = temp; - } - - source[targetGroup].push_back(clone); - - size_t index = source[targetGroup].size() - 1; - - if(preloaded) - load(index, targetGroup); -} - -void CAnimation::setCustom(std::string filename, size_t frame, size_t group) -{ - if (source[group].size() <= frame) - source[group].resize(frame+1); - source[group][frame]["file"].String() = filename; - //FIXME: update image if already loaded -} - -std::shared_ptr CAnimation::getImage(size_t frame, size_t group, bool verbose) const -{ - auto groupIter = images.find(group); - if (groupIter != images.end()) - { - auto imageIter = groupIter->second.find(frame); - if (imageIter != groupIter->second.end()) - return imageIter->second; - } - if (verbose) - printError(frame, group, "GetImage"); - return nullptr; -} - -void CAnimation::load() -{ - for (auto & elem : source) - for (size_t image=0; image < elem.second.size(); image++) - loadFrame(image, elem.first); -} - -void CAnimation::unload() -{ - for (auto & elem : source) - for (size_t image=0; image < elem.second.size(); image++) - unloadFrame(image, elem.first); - -} - -void CAnimation::preload() -{ - if(!preloaded) - { - preloaded = true; - load(); - } -} - -void CAnimation::loadGroup(size_t group) -{ - if (vstd::contains(source, group)) - for (size_t image=0; image < source[group].size(); image++) - loadFrame(image, group); -} - -void CAnimation::unloadGroup(size_t group) -{ - if (vstd::contains(source, group)) - for (size_t image=0; image < source[group].size(); image++) - unloadFrame(image, group); -} - -void CAnimation::load(size_t frame, size_t group) -{ - loadFrame(frame, group); -} - -void CAnimation::unload(size_t frame, size_t group) -{ - unloadFrame(frame, group); -} - -size_t CAnimation::size(size_t group) const -{ - auto iter = source.find(group); - if (iter != source.end()) - return iter->second.size(); - return 0; -} - -void CAnimation::horizontalFlip() -{ - for(auto & group : images) - for(auto & image : group.second) - image.second->horizontalFlip(); -} - -void CAnimation::verticalFlip() -{ - for(auto & group : images) - for(auto & image : group.second) - image.second->verticalFlip(); -} - -void CAnimation::playerColored(PlayerColor player) -{ - for(auto & group : images) - for(auto & image : group.second) - image.second->playerColored(player); -} - -void CAnimation::createFlippedGroup(const size_t sourceGroup, const size_t targetGroup) -{ - for(size_t frame = 0; frame < size(sourceGroup); ++frame) - { - duplicateImage(sourceGroup, frame, targetGroup); - - auto image = getImage(frame, targetGroup); - image->verticalFlip(); - } -} - -float CFadeAnimation::initialCounter() const -{ - if (fadingMode == EMode::OUT) - return 1.0f; - return 0.0f; -} - -void CFadeAnimation::update() -{ - if (!fading) - return; - - if (fadingMode == EMode::OUT) - fadingCounter -= delta; - else - fadingCounter += delta; - - if (isFinished()) - { - fading = false; - if (shouldFreeSurface) - { - SDL_FreeSurface(fadingSurface); - fadingSurface = nullptr; - } - } -} - -bool CFadeAnimation::isFinished() const -{ - if (fadingMode == EMode::OUT) - return fadingCounter <= 0.0f; - return fadingCounter >= 1.0f; -} - -CFadeAnimation::CFadeAnimation() - : delta(0), fadingSurface(nullptr), fading(false), fadingCounter(0), shouldFreeSurface(false), - fadingMode(EMode::NONE) -{ -} - -CFadeAnimation::~CFadeAnimation() -{ - if (fadingSurface && shouldFreeSurface) - SDL_FreeSurface(fadingSurface); -} - -void CFadeAnimation::init(EMode mode, SDL_Surface * sourceSurface, bool freeSurfaceAtEnd, float animDelta) -{ - if (fading) - { - // in that case, immediately finish the previous fade - // (alternatively, we could just return here to ignore the new fade request until this one finished (but we'd need to free the passed bitmap to avoid leaks)) - logGlobal->warn("Tried to init fading animation that is already running."); - if (fadingSurface && shouldFreeSurface) - SDL_FreeSurface(fadingSurface); - } - if (animDelta <= 0.0f) - { - logGlobal->warn("Fade anim: delta should be positive; %f given.", animDelta); - animDelta = DEFAULT_DELTA; - } - - if (sourceSurface) - fadingSurface = sourceSurface; - - delta = animDelta; - fadingMode = mode; - fadingCounter = initialCounter(); - fading = true; - shouldFreeSurface = freeSurfaceAtEnd; -} - -void CFadeAnimation::draw(SDL_Surface * targetSurface, const Point &targetPoint) -{ - if (!fading || !fadingSurface || fadingMode == EMode::NONE) - { - fading = false; - return; - } - - CSDL_Ext::setAlpha(fadingSurface, (int)(fadingCounter * 255)); - CSDL_Ext::blitSurface(fadingSurface, targetSurface, targetPoint); //FIXME - CSDL_Ext::setAlpha(fadingSurface, 255); -} diff --git a/client/render/SDLImageLoader.h b/client/render/SDLImageLoader.h new file mode 100644 index 000000000..24ec28f8f --- /dev/null +++ b/client/render/SDLImageLoader.h @@ -0,0 +1,54 @@ +/* + * CAnimation.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include "../../lib/GameConstants.h" + +#ifdef IN +#undef IN +#endif + +#ifdef OUT +#undef OUT +#endif + +VCMI_LIB_NAMESPACE_BEGIN + +class JsonNode; +class Rect; +class Point; + +VCMI_LIB_NAMESPACE_END + +struct SDL_Surface; +struct SDL_Color; +class CDefFile; +class ColorFilter; + + +class SDLImageLoader +{ + SDLImage * image; + ui8 * lineStart; + ui8 * position; +public: + //load size raw pixels from data + inline void Load(size_t size, const ui8 * data); + //set size pixels to color + inline void Load(size_t size, ui8 color=0); + inline void EndLine(); + //init image with these sizes and palette + inline void init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal); + + SDLImageLoader(SDLImage * Img); + ~SDLImageLoader(); +}; + + From 4d8d8863173d8759411bcea56add0d826bf28148 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 16:28:48 +0200 Subject: [PATCH 75/79] Move all created files into better locations --- client/gui/{CursorHandlerBase.cpp => CursorHandler.cpp} | 0 client/gui/{CursorHandlerBase.h => CursorHandler.h} | 0 client/render/{Animation.cpp => CAnimation.cpp} | 0 client/render/{Animation.h => CAnimation.h} | 0 client/{gui => render}/ICursor.h | 0 client/{render => renderSDL}/CBitmapFont.cpp | 0 client/{render => renderSDL}/CBitmapFont.h | 0 client/{render => renderSDL}/CBitmapHanFont.cpp | 0 client/{render => renderSDL}/CBitmapHanFont.h | 0 client/{render => renderSDL}/CTrueTypeFont.cpp | 0 client/{render => renderSDL}/CTrueTypeFont.h | 0 client/{gui => renderSDL}/CursorHardware.cpp | 0 client/{gui => renderSDL}/CursorHardware.h | 0 client/{gui => renderSDL}/CursorSoftware.cpp | 0 client/{gui => renderSDL}/CursorSoftware.h | 0 client/{render => renderSDL}/SDLImage.cpp | 0 client/{render => renderSDL}/SDLImage.h | 0 client/{render => renderSDL}/SDLImageLoader.cpp | 0 client/{render => renderSDL}/SDLImageLoader.h | 0 client/{render => renderSDL}/SDLRWwrapper.cpp | 0 client/{render => renderSDL}/SDLRWwrapper.h | 0 client/{render => renderSDL}/SDL_Extensions.cpp | 0 client/{render => renderSDL}/SDL_Extensions.h | 0 client/{render => renderSDL}/SDL_PixelAccess.h | 0 24 files changed, 0 insertions(+), 0 deletions(-) rename client/gui/{CursorHandlerBase.cpp => CursorHandler.cpp} (100%) rename client/gui/{CursorHandlerBase.h => CursorHandler.h} (100%) rename client/render/{Animation.cpp => CAnimation.cpp} (100%) rename client/render/{Animation.h => CAnimation.h} (100%) rename client/{gui => render}/ICursor.h (100%) rename client/{render => renderSDL}/CBitmapFont.cpp (100%) rename client/{render => renderSDL}/CBitmapFont.h (100%) rename client/{render => renderSDL}/CBitmapHanFont.cpp (100%) rename client/{render => renderSDL}/CBitmapHanFont.h (100%) rename client/{render => renderSDL}/CTrueTypeFont.cpp (100%) rename client/{render => renderSDL}/CTrueTypeFont.h (100%) rename client/{gui => renderSDL}/CursorHardware.cpp (100%) rename client/{gui => renderSDL}/CursorHardware.h (100%) rename client/{gui => renderSDL}/CursorSoftware.cpp (100%) rename client/{gui => renderSDL}/CursorSoftware.h (100%) rename client/{render => renderSDL}/SDLImage.cpp (100%) rename client/{render => renderSDL}/SDLImage.h (100%) rename client/{render => renderSDL}/SDLImageLoader.cpp (100%) rename client/{render => renderSDL}/SDLImageLoader.h (100%) rename client/{render => renderSDL}/SDLRWwrapper.cpp (100%) rename client/{render => renderSDL}/SDLRWwrapper.h (100%) rename client/{render => renderSDL}/SDL_Extensions.cpp (100%) rename client/{render => renderSDL}/SDL_Extensions.h (100%) rename client/{render => renderSDL}/SDL_PixelAccess.h (100%) diff --git a/client/gui/CursorHandlerBase.cpp b/client/gui/CursorHandler.cpp similarity index 100% rename from client/gui/CursorHandlerBase.cpp rename to client/gui/CursorHandler.cpp diff --git a/client/gui/CursorHandlerBase.h b/client/gui/CursorHandler.h similarity index 100% rename from client/gui/CursorHandlerBase.h rename to client/gui/CursorHandler.h diff --git a/client/render/Animation.cpp b/client/render/CAnimation.cpp similarity index 100% rename from client/render/Animation.cpp rename to client/render/CAnimation.cpp diff --git a/client/render/Animation.h b/client/render/CAnimation.h similarity index 100% rename from client/render/Animation.h rename to client/render/CAnimation.h diff --git a/client/gui/ICursor.h b/client/render/ICursor.h similarity index 100% rename from client/gui/ICursor.h rename to client/render/ICursor.h diff --git a/client/render/CBitmapFont.cpp b/client/renderSDL/CBitmapFont.cpp similarity index 100% rename from client/render/CBitmapFont.cpp rename to client/renderSDL/CBitmapFont.cpp diff --git a/client/render/CBitmapFont.h b/client/renderSDL/CBitmapFont.h similarity index 100% rename from client/render/CBitmapFont.h rename to client/renderSDL/CBitmapFont.h diff --git a/client/render/CBitmapHanFont.cpp b/client/renderSDL/CBitmapHanFont.cpp similarity index 100% rename from client/render/CBitmapHanFont.cpp rename to client/renderSDL/CBitmapHanFont.cpp diff --git a/client/render/CBitmapHanFont.h b/client/renderSDL/CBitmapHanFont.h similarity index 100% rename from client/render/CBitmapHanFont.h rename to client/renderSDL/CBitmapHanFont.h diff --git a/client/render/CTrueTypeFont.cpp b/client/renderSDL/CTrueTypeFont.cpp similarity index 100% rename from client/render/CTrueTypeFont.cpp rename to client/renderSDL/CTrueTypeFont.cpp diff --git a/client/render/CTrueTypeFont.h b/client/renderSDL/CTrueTypeFont.h similarity index 100% rename from client/render/CTrueTypeFont.h rename to client/renderSDL/CTrueTypeFont.h diff --git a/client/gui/CursorHardware.cpp b/client/renderSDL/CursorHardware.cpp similarity index 100% rename from client/gui/CursorHardware.cpp rename to client/renderSDL/CursorHardware.cpp diff --git a/client/gui/CursorHardware.h b/client/renderSDL/CursorHardware.h similarity index 100% rename from client/gui/CursorHardware.h rename to client/renderSDL/CursorHardware.h diff --git a/client/gui/CursorSoftware.cpp b/client/renderSDL/CursorSoftware.cpp similarity index 100% rename from client/gui/CursorSoftware.cpp rename to client/renderSDL/CursorSoftware.cpp diff --git a/client/gui/CursorSoftware.h b/client/renderSDL/CursorSoftware.h similarity index 100% rename from client/gui/CursorSoftware.h rename to client/renderSDL/CursorSoftware.h diff --git a/client/render/SDLImage.cpp b/client/renderSDL/SDLImage.cpp similarity index 100% rename from client/render/SDLImage.cpp rename to client/renderSDL/SDLImage.cpp diff --git a/client/render/SDLImage.h b/client/renderSDL/SDLImage.h similarity index 100% rename from client/render/SDLImage.h rename to client/renderSDL/SDLImage.h diff --git a/client/render/SDLImageLoader.cpp b/client/renderSDL/SDLImageLoader.cpp similarity index 100% rename from client/render/SDLImageLoader.cpp rename to client/renderSDL/SDLImageLoader.cpp diff --git a/client/render/SDLImageLoader.h b/client/renderSDL/SDLImageLoader.h similarity index 100% rename from client/render/SDLImageLoader.h rename to client/renderSDL/SDLImageLoader.h diff --git a/client/render/SDLRWwrapper.cpp b/client/renderSDL/SDLRWwrapper.cpp similarity index 100% rename from client/render/SDLRWwrapper.cpp rename to client/renderSDL/SDLRWwrapper.cpp diff --git a/client/render/SDLRWwrapper.h b/client/renderSDL/SDLRWwrapper.h similarity index 100% rename from client/render/SDLRWwrapper.h rename to client/renderSDL/SDLRWwrapper.h diff --git a/client/render/SDL_Extensions.cpp b/client/renderSDL/SDL_Extensions.cpp similarity index 100% rename from client/render/SDL_Extensions.cpp rename to client/renderSDL/SDL_Extensions.cpp diff --git a/client/render/SDL_Extensions.h b/client/renderSDL/SDL_Extensions.h similarity index 100% rename from client/render/SDL_Extensions.h rename to client/renderSDL/SDL_Extensions.h diff --git a/client/render/SDL_PixelAccess.h b/client/renderSDL/SDL_PixelAccess.h similarity index 100% rename from client/render/SDL_PixelAccess.h rename to client/renderSDL/SDL_PixelAccess.h From 84dfcacafdb1f51fe25e85f0f077c53f7069b551 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 16:42:03 +0200 Subject: [PATCH 76/79] Updated CMakeLists and file headers --- client/CMakeLists.txt | 346 ++++++++++-------- .../{CAdvmapInterface.cpp => CAdvMapInt.cpp} | 2 +- .../{CAdvmapInterface.h => CAdvMapInt.h} | 2 +- client/adventureMap/CAdvMapPanel.cpp | 2 +- client/adventureMap/CAdvMapPanel.h | 2 +- client/adventureMap/CAdventureOptions.cpp | 2 +- client/adventureMap/CAdventureOptions.h | 2 +- client/adventureMap/CInGameConsole.cpp | 2 +- client/adventureMap/CInGameConsole.h | 2 +- client/adventureMap/CInfoBar.cpp | 2 +- client/adventureMap/CInfoBar.h | 2 +- client/adventureMap/CList.cpp | 2 +- client/adventureMap/CList.h | 2 +- client/adventureMap/CMinimap.cpp | 2 +- client/adventureMap/CMinimap.h | 2 +- client/adventureMap/CResDataBar.cpp | 2 +- client/adventureMap/CResDataBar.h | 2 +- client/adventureMap/CTerrainRect.cpp | 2 +- client/adventureMap/CTerrainRect.h | 2 +- client/render/CDefFile.cpp | 2 +- client/render/CDefFile.h | 2 +- client/render/CFadeAnimation.cpp | 2 +- client/render/CFadeAnimation.h | 2 +- client/render/ICursor.h | 2 +- client/render/IFont.cpp | 2 +- client/render/IFont.h | 2 +- client/render/IImage.h | 2 +- client/renderSDL/CBitmapFont.cpp | 2 +- client/renderSDL/CBitmapFont.h | 2 +- client/renderSDL/CBitmapHanFont.cpp | 2 +- client/renderSDL/CBitmapHanFont.h | 2 +- client/renderSDL/CTrueTypeFont.cpp | 2 +- client/renderSDL/CTrueTypeFont.h | 2 +- client/renderSDL/CursorHardware.cpp | 2 +- client/renderSDL/CursorHardware.h | 2 +- client/renderSDL/CursorSoftware.cpp | 2 +- client/renderSDL/CursorSoftware.h | 2 +- client/renderSDL/SDLImage.cpp | 2 +- client/renderSDL/SDLImage.h | 2 +- client/renderSDL/SDLImageLoader.cpp | 2 +- client/renderSDL/SDLImageLoader.h | 2 +- 41 files changed, 233 insertions(+), 193 deletions(-) rename client/adventureMap/{CAdvmapInterface.cpp => CAdvMapInt.cpp} (96%) rename client/adventureMap/{CAdvmapInterface.h => CAdvMapInt.h} (96%) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index a9cb657fe..898b6de48 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -1,173 +1,213 @@ set(client_SRCS - StdInc.cpp - ../CCallback.cpp + StdInc.cpp + ../CCallback.cpp - battle/BattleActionsController.cpp - battle/BattleAnimationClasses.cpp - battle/BattleEffectsController.cpp - battle/BattleFieldController.cpp - battle/BattleInterfaceClasses.cpp - battle/BattleInterface.cpp - battle/BattleObstacleController.cpp - battle/BattleProjectileController.cpp - battle/BattleRenderer.cpp - battle/BattleSiegeController.cpp - battle/BattleStacksController.cpp - battle/BattleWindow.cpp - battle/CreatureAnimation.cpp + adventureMap/CAdvMapPanel.cpp + adventureMap/CAdvMapInt.cpp + adventureMap/CAdventureOptions.cpp + adventureMap/CInGameConsole.cpp + adventureMap/CInfoBar.cpp + adventureMap/CList.cpp + adventureMap/CMinimap.cpp + adventureMap/CResDataBar.cpp + adventureMap/CTerrainRect.cpp + adventureMap/mapHandler.cpp - gui/CAnimation.cpp - gui/Canvas.cpp - gui/CursorHandler.cpp - gui/CGuiHandler.cpp - gui/CIntObject.cpp - gui/ColorFilter.cpp - gui/Fonts.cpp - gui/SDL_Extensions.cpp - gui/NotificationHandler.cpp - gui/InterfaceObjectConfigurable.cpp + battle/BattleActionsController.cpp + battle/BattleAnimationClasses.cpp + battle/BattleEffectsController.cpp + battle/BattleFieldController.cpp + battle/BattleInterface.cpp + battle/BattleInterfaceClasses.cpp + battle/BattleObstacleController.cpp + battle/BattleProjectileController.cpp + battle/BattleRenderer.cpp + battle/BattleSiegeController.cpp + battle/BattleStacksController.cpp + battle/BattleWindow.cpp - widgets/AdventureMapClasses.cpp - widgets/Buttons.cpp - widgets/CArtifactHolder.cpp - widgets/CComponent.cpp - widgets/CGarrisonInt.cpp - widgets/Images.cpp - widgets/MiscWidgets.cpp - widgets/ObjectLists.cpp - widgets/TextControls.cpp + gui/CGuiHandler.cpp + gui/CIntObject.cpp + gui/CursorHandler.cpp + gui/InterfaceObjectConfigurable.cpp + gui/NotificationHandler.cpp - windows/CAdvmapInterface.cpp - windows/CCastleInterface.cpp - windows/CCreatureWindow.cpp - windows/CreaturePurchaseCard.cpp - windows/CHeroWindow.cpp - windows/CKingdomInterface.cpp - windows/CQuestLog.cpp - windows/CSpellWindow.cpp - windows/CTradeWindow.cpp - windows/CWindowObject.cpp - windows/GUIClasses.cpp - windows/InfoWindows.cpp - windows/QuickRecruitmentWindow.cpp + lobby/CBonusSelection.cpp + lobby/CCampaignInfoScreen.cpp + lobby/CLobbyScreen.cpp + lobby/CSavingScreen.cpp + lobby/CScenarioInfoScreen.cpp + lobby/CSelectionBase.cpp + lobby/OptionsTab.cpp + lobby/RandomMapTab.cpp + lobby/SelectionTab.cpp - mainmenu/CMainMenu.cpp - mainmenu/CCampaignScreen.cpp - mainmenu/CreditsScreen.cpp - mainmenu/CPrologEpilogVideo.cpp + mainmenu/CCampaignScreen.cpp + mainmenu/CMainMenu.cpp + mainmenu/CPrologEpilogVideo.cpp + mainmenu/CreditsScreen.cpp - lobby/CBonusSelection.cpp - lobby/CSelectionBase.cpp - lobby/CLobbyScreen.cpp - lobby/CSavingScreen.cpp - lobby/CScenarioInfoScreen.cpp - lobby/CCampaignInfoScreen.cpp - lobby/OptionsTab.cpp - lobby/RandomMapTab.cpp - lobby/SelectionTab.cpp + render/CAnimation.cpp + render/CBitmapHandler.cpp + render/CDefFile.cpp + render/CFadeAnimation.cpp + render/Canvas.cpp + render/ColorFilter.cpp + render/Graphics.cpp + render/IFont.cpp - CBitmapHandler.cpp - CreatureCostBox.cpp - CGameInfo.cpp - Client.cpp - CMessage.cpp - CMT.cpp - CMusicHandler.cpp - CPlayerInterface.cpp - CVideoHandler.cpp - CServerHandler.cpp - Graphics.cpp - mapHandler.cpp - NetPacksClient.cpp - NetPacksLobbyClient.cpp - SDLRWwrapper.cpp - ClientCommandManager.cpp + renderSDL/CBitmapFont.cpp + renderSDL/CBitmapHanFont.cpp + renderSDL/CTrueTypeFont.cpp + renderSDL/CursorHardware.cpp + renderSDL/CursorSoftware.cpp + renderSDL/SDLImage.cpp + renderSDL/SDLImageLoader.cpp + renderSDL/SDLRWwrapper.cpp + renderSDL/SDL_Extensions.cpp + + widgets/Buttons.cpp + widgets/CArtifactHolder.cpp + widgets/CComponent.cpp + widgets/CGarrisonInt.cpp + widgets/CreatureCostBox.cpp + widgets/Images.cpp + widgets/MiscWidgets.cpp + widgets/ObjectLists.cpp + widgets/TextControls.cpp + + windows/CCastleInterface.cpp + windows/CCreatureWindow.cpp + windows/CHeroWindow.cpp + windows/CKingdomInterface.cpp + windows/CMessage.cpp + windows/CQuestLog.cpp + windows/CSpellWindow.cpp + windows/CTradeWindow.cpp + windows/CWindowObject.cpp + windows/CreaturePurchaseCard.cpp + windows/GUIClasses.cpp + windows/InfoWindows.cpp + windows/QuickRecruitmentWindow.cpp + + CGameInfo.cpp + CMT.cpp + CMusicHandler.cpp + CPlayerInterface.cpp + CServerHandler.cpp + CVideoHandler.cpp + Client.cpp + ClientCommandManager.cpp + NetPacksClient.cpp + NetPacksLobbyClient.cpp ) set(client_HEADERS - StdInc.h + StdInc.h - battle/BattleActionsController.h - battle/BattleAnimationClasses.h - battle/BattleEffectsController.h - battle/BattleFieldController.h - battle/BattleInterfaceClasses.h - battle/BattleInterface.h - battle/BattleObstacleController.h - battle/BattleProjectileController.h - battle/BattleRenderer.h - battle/BattleSiegeController.h - battle/BattleStacksController.h - battle/BattleWindow.h - battle/CreatureAnimation.h - battle/BattleConstants.h + adventureMap/CAdvMapPanel.h + adventureMap/CAdvMapInt.h + adventureMap/CAdventureOptions.h + adventureMap/CInGameConsole.h + adventureMap/CInfoBar.h + adventureMap/CList.h + adventureMap/CMinimap.h + adventureMap/CResDataBar.h + adventureMap/CTerrainRect.h + adventureMap/mapHandler.h - gui/CAnimation.h - gui/Canvas.h - gui/CursorHandler.h - gui/CGuiHandler.h - gui/ColorFilter.h - gui/CIntObject.h - gui/Fonts.h - gui/TextAlignment.h - gui/SDL_Extensions.h - gui/SDL_PixelAccess.h - gui/NotificationHandler.h - gui/InterfaceObjectConfigurable.h + battle/BattleActionsController.h + battle/BattleAnimationClasses.h + battle/BattleConstants.h + battle/BattleEffectsController.h + battle/BattleFieldController.h + battle/BattleInterface.h + battle/BattleInterfaceClasses.h + battle/BattleObstacleController.h + battle/BattleProjectileController.h + battle/BattleRenderer.h + battle/BattleSiegeController.h + battle/BattleStacksController.h + battle/BattleWindow.h + battle/CreatureAnimation.h - widgets/AdventureMapClasses.h - widgets/Buttons.h - widgets/CArtifactHolder.h - widgets/CComponent.h - widgets/CGarrisonInt.h - widgets/Images.h - widgets/MiscWidgets.h - widgets/ObjectLists.h - widgets/TextControls.h - windows/CAdvmapInterface.h - windows/CCastleInterface.h - windows/CCreatureWindow.h - windows/CreaturePurchaseCard.h - windows/CHeroWindow.h - windows/CKingdomInterface.h - windows/CQuestLog.h - windows/CSpellWindow.h - windows/CTradeWindow.h - windows/CWindowObject.h - windows/GUIClasses.h - windows/InfoWindows.h - windows/QuickRecruitmentWindow.h + gui/CGuiHandler.h + gui/CIntObject.h + gui/CursorHandler.h + gui/InterfaceObjectConfigurable.h + gui/NotificationHandler.h + gui/TextAlignment.h - mainmenu/CMainMenu.h - mainmenu/CCampaignScreen.h - mainmenu/CreditsScreen.h - mainmenu/CPrologEpilogVideo.h + lobby/CBonusSelection.h + lobby/CCampaignInfoScreen.h + lobby/CLobbyScreen.h + lobby/CSavingScreen.h + lobby/CScenarioInfoScreen.h + lobby/CSelectionBase.h + lobby/OptionsTab.h + lobby/RandomMapTab.h + lobby/SelectionTab.h - lobby/CBonusSelection.h - lobby/CSelectionBase.h - lobby/CLobbyScreen.h - lobby/CSavingScreen.h - lobby/CScenarioInfoScreen.h - lobby/CCampaignInfoScreen.h - lobby/OptionsTab.h - lobby/RandomMapTab.h - lobby/SelectionTab.h + mainmenu/CCampaignScreen.h + mainmenu/CMainMenu.h + mainmenu/CPrologEpilogVideo.h + mainmenu/CreditsScreen.h - CBitmapHandler.h - CreatureCostBox.h - CGameInfo.h - Client.h - CMessage.h - CMT.h - CMusicHandler.h - CPlayerInterface.h - CVideoHandler.h - CServerHandler.h - Graphics.h - mapHandler.h - resource.h - SDLRWwrapper.h - ClientCommandManager.h + render/CAnimation.h + render/CBitmapHandler.h + render/CDefFile.h + render/CFadeAnimation.h + render/Canvas.h + render/ColorFilter.h + render/Graphics.h + render/ICursor.h + render/IFont.h + render/IImage.h + + renderSDL/CBitmapFont.h + renderSDL/CBitmapHanFont.h + renderSDL/CTrueTypeFont.h + renderSDL/CursorHardware.h + renderSDL/CursorSoftware.h + renderSDL/SDLImage.h + renderSDL/SDLImageLoader.h + renderSDL/SDLRWwrapper.h + renderSDL/SDL_Extensions.h + renderSDL/SDL_PixelAccess.h + + widgets/Buttons.h + widgets/CArtifactHolder.h + widgets/CComponent.h + widgets/CGarrisonInt.h + widgets/CreatureCostBox.h + widgets/Images.h + widgets/MiscWidgets.h + widgets/ObjectLists.h + widgets/TextControls.h + + windows/CCastleInterface.h + windows/CCreatureWindow.h + windows/CHeroWindow.h + windows/CKingdomInterface.h + windows/CMessage.h + windows/CQuestLog.h + windows/CSpellWindow.h + windows/CTradeWindow.h + windows/CWindowObject.h + windows/CreaturePurchaseCard.h + windows/GUIClasses.h + windows/InfoWindows.h + windows/QuickRecruitmentWindow.h + + CGameInfo.h + CMT.h + CMusicHandler.h + CPlayerInterface.h + CServerHandler.h + CVideoHandler.h + Client.h + ClientCommandManager.h + resource.h ) if(APPLE_IOS) diff --git a/client/adventureMap/CAdvmapInterface.cpp b/client/adventureMap/CAdvMapInt.cpp similarity index 96% rename from client/adventureMap/CAdvmapInterface.cpp rename to client/adventureMap/CAdvMapInt.cpp index 6b5ea8185..e9005bfd0 100644 --- a/client/adventureMap/CAdvmapInterface.cpp +++ b/client/adventureMap/CAdvMapInt.cpp @@ -1,5 +1,5 @@ /* - * CAdvmapInterface.cpp, part of VCMI engine + * CAdvMapInt.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CAdvmapInterface.h b/client/adventureMap/CAdvMapInt.h similarity index 96% rename from client/adventureMap/CAdvmapInterface.h rename to client/adventureMap/CAdvMapInt.h index a009c2833..d3fa66ffc 100644 --- a/client/adventureMap/CAdvmapInterface.h +++ b/client/adventureMap/CAdvMapInt.h @@ -1,5 +1,5 @@ /* - * CAdvmapInterface.h, part of VCMI engine + * CAdvMapInt.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CAdvMapPanel.cpp b/client/adventureMap/CAdvMapPanel.cpp index 3820966ce..986619c90 100644 --- a/client/adventureMap/CAdvMapPanel.cpp +++ b/client/adventureMap/CAdvMapPanel.cpp @@ -1,5 +1,5 @@ /* - * AdventureMapClasses.cpp, part of VCMI engine + * CAdvMapPanel.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CAdvMapPanel.h b/client/adventureMap/CAdvMapPanel.h index b5a1d663d..dae9e7c5a 100644 --- a/client/adventureMap/CAdvMapPanel.h +++ b/client/adventureMap/CAdvMapPanel.h @@ -1,5 +1,5 @@ /* - * AdventureMapClasses.h, part of VCMI engine + * CAdvMapPanel.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CAdventureOptions.cpp b/client/adventureMap/CAdventureOptions.cpp index 50c466066..ffc074d4b 100644 --- a/client/adventureMap/CAdventureOptions.cpp +++ b/client/adventureMap/CAdventureOptions.cpp @@ -1,5 +1,5 @@ /* - * CAdvmapInterface.cpp, part of VCMI engine + * CAdventureOptions.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CAdventureOptions.h b/client/adventureMap/CAdventureOptions.h index b3513650b..498af6a1f 100644 --- a/client/adventureMap/CAdventureOptions.h +++ b/client/adventureMap/CAdventureOptions.h @@ -1,5 +1,5 @@ /* - * CAdvmapInterface.h, part of VCMI engine + * CAdventureOptions.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CInGameConsole.cpp b/client/adventureMap/CInGameConsole.cpp index 7d6b6af1a..c5c3ce32a 100644 --- a/client/adventureMap/CInGameConsole.cpp +++ b/client/adventureMap/CInGameConsole.cpp @@ -1,5 +1,5 @@ /* - * AdventureMapClasses.cpp, part of VCMI engine + * CInGameConsole.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CInGameConsole.h b/client/adventureMap/CInGameConsole.h index 43c625b70..7e08d5abb 100644 --- a/client/adventureMap/CInGameConsole.h +++ b/client/adventureMap/CInGameConsole.h @@ -1,5 +1,5 @@ /* - * AdventureMapClasses.h, part of VCMI engine + * CInGameConsole.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CInfoBar.cpp b/client/adventureMap/CInfoBar.cpp index 98c6a8249..f202b77c7 100644 --- a/client/adventureMap/CInfoBar.cpp +++ b/client/adventureMap/CInfoBar.cpp @@ -1,5 +1,5 @@ /* - * AdventureMapClasses.cpp, part of VCMI engine + * CInfoBar.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CInfoBar.h b/client/adventureMap/CInfoBar.h index 7ec4d3949..ba56c3178 100644 --- a/client/adventureMap/CInfoBar.h +++ b/client/adventureMap/CInfoBar.h @@ -1,5 +1,5 @@ /* - * AdventureMapClasses.h, part of VCMI engine + * CInfoBar.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CList.cpp b/client/adventureMap/CList.cpp index 0e5a4304f..e9d2391e7 100644 --- a/client/adventureMap/CList.cpp +++ b/client/adventureMap/CList.cpp @@ -1,5 +1,5 @@ /* - * AdventureMapClasses.cpp, part of VCMI engine + * CList.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CList.h b/client/adventureMap/CList.h index 6d47188bf..11568779f 100644 --- a/client/adventureMap/CList.h +++ b/client/adventureMap/CList.h @@ -1,5 +1,5 @@ /* - * AdventureMapClasses.h, part of VCMI engine + * CList.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CMinimap.cpp b/client/adventureMap/CMinimap.cpp index f3e5697c0..a52989a57 100644 --- a/client/adventureMap/CMinimap.cpp +++ b/client/adventureMap/CMinimap.cpp @@ -1,5 +1,5 @@ /* - * AdventureMapClasses.cpp, part of VCMI engine + * CMinimap.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CMinimap.h b/client/adventureMap/CMinimap.h index a772ae5e3..5ea772963 100644 --- a/client/adventureMap/CMinimap.h +++ b/client/adventureMap/CMinimap.h @@ -1,5 +1,5 @@ /* - * AdventureMapClasses.h, part of VCMI engine + * CMinimap.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CResDataBar.cpp b/client/adventureMap/CResDataBar.cpp index 2385d5f1c..9e7e75544 100644 --- a/client/adventureMap/CResDataBar.cpp +++ b/client/adventureMap/CResDataBar.cpp @@ -1,5 +1,5 @@ /* - * CAdvmapInterface.cpp, part of VCMI engine + * CResDataBar.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CResDataBar.h b/client/adventureMap/CResDataBar.h index f1e871383..d8a38967c 100644 --- a/client/adventureMap/CResDataBar.h +++ b/client/adventureMap/CResDataBar.h @@ -1,5 +1,5 @@ /* - * CAdvmapInterface.h, part of VCMI engine + * CResDataBar.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CTerrainRect.cpp b/client/adventureMap/CTerrainRect.cpp index 8fde76286..c0ec1bc6b 100644 --- a/client/adventureMap/CTerrainRect.cpp +++ b/client/adventureMap/CTerrainRect.cpp @@ -1,5 +1,5 @@ /* - * CAdvmapInterface.cpp, part of VCMI engine + * CTerrainRect.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/adventureMap/CTerrainRect.h b/client/adventureMap/CTerrainRect.h index 006b03aeb..b439f44d1 100644 --- a/client/adventureMap/CTerrainRect.h +++ b/client/adventureMap/CTerrainRect.h @@ -1,5 +1,5 @@ /* - * CAdvmapInterface.h, part of VCMI engine + * CTerrainRect.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/render/CDefFile.cpp b/client/render/CDefFile.cpp index d42440d73..a88ab0aa5 100644 --- a/client/render/CDefFile.cpp +++ b/client/render/CDefFile.cpp @@ -1,5 +1,5 @@ /* - * CAnimation.cpp, part of VCMI engine + * CDefFile.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/render/CDefFile.h b/client/render/CDefFile.h index 5cdb21fb8..5c5fe8ce8 100644 --- a/client/render/CDefFile.h +++ b/client/render/CDefFile.h @@ -1,5 +1,5 @@ /* - * CAnimation.h, part of VCMI engine + * CDefFile.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/render/CFadeAnimation.cpp b/client/render/CFadeAnimation.cpp index 5e4b998ee..04427b197 100644 --- a/client/render/CFadeAnimation.cpp +++ b/client/render/CFadeAnimation.cpp @@ -1,5 +1,5 @@ /* - * CAnimation.cpp, part of VCMI engine + * CFadeAnimation.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/render/CFadeAnimation.h b/client/render/CFadeAnimation.h index e05bf40f3..76e95b313 100644 --- a/client/render/CFadeAnimation.h +++ b/client/render/CFadeAnimation.h @@ -1,5 +1,5 @@ /* - * CAnimation.h, part of VCMI engine + * CFadeAnimation.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/render/ICursor.h b/client/render/ICursor.h index 8951a18b6..8abbbbef5 100644 --- a/client/render/ICursor.h +++ b/client/render/ICursor.h @@ -1,5 +1,5 @@ /* - * CCursorHandler.h, part of VCMI engine + * ICursor.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/render/IFont.cpp b/client/render/IFont.cpp index 5c99bf020..bea94c076 100644 --- a/client/render/IFont.cpp +++ b/client/render/IFont.cpp @@ -1,5 +1,5 @@ /* - * Fonts.cpp, part of VCMI engine + * IFont.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/render/IFont.h b/client/render/IFont.h index a73c81b1c..bc87fea28 100644 --- a/client/render/IFont.h +++ b/client/render/IFont.h @@ -1,5 +1,5 @@ /* - * Fonts.h, part of VCMI engine + * IFont.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/render/IImage.h b/client/render/IImage.h index d853fec7b..06691db52 100644 --- a/client/render/IImage.h +++ b/client/render/IImage.h @@ -1,5 +1,5 @@ /* - * CAnimation.h, part of VCMI engine + * IImage.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/renderSDL/CBitmapFont.cpp b/client/renderSDL/CBitmapFont.cpp index 345ed7e68..ce600e2bd 100644 --- a/client/renderSDL/CBitmapFont.cpp +++ b/client/renderSDL/CBitmapFont.cpp @@ -1,5 +1,5 @@ /* - * Fonts.cpp, part of VCMI engine + * CBitmapFont.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/renderSDL/CBitmapFont.h b/client/renderSDL/CBitmapFont.h index c4b608a6b..3f1012113 100644 --- a/client/renderSDL/CBitmapFont.h +++ b/client/renderSDL/CBitmapFont.h @@ -1,5 +1,5 @@ /* - * Fonts.h, part of VCMI engine + * CBitmapFont.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/renderSDL/CBitmapHanFont.cpp b/client/renderSDL/CBitmapHanFont.cpp index e474495ee..303299cab 100644 --- a/client/renderSDL/CBitmapHanFont.cpp +++ b/client/renderSDL/CBitmapHanFont.cpp @@ -1,5 +1,5 @@ /* - * Fonts.cpp, part of VCMI engine + * CBitmapHanFont.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/renderSDL/CBitmapHanFont.h b/client/renderSDL/CBitmapHanFont.h index 605415f91..ea61a42b5 100644 --- a/client/renderSDL/CBitmapHanFont.h +++ b/client/renderSDL/CBitmapHanFont.h @@ -1,5 +1,5 @@ /* - * Fonts.h, part of VCMI engine + * CBitmapHanFont.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/renderSDL/CTrueTypeFont.cpp b/client/renderSDL/CTrueTypeFont.cpp index 5b1f2ad4f..98df180c7 100644 --- a/client/renderSDL/CTrueTypeFont.cpp +++ b/client/renderSDL/CTrueTypeFont.cpp @@ -1,5 +1,5 @@ /* - * Fonts.cpp, part of VCMI engine + * CTrueTypeFont.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/renderSDL/CTrueTypeFont.h b/client/renderSDL/CTrueTypeFont.h index d4b67710a..6e65645b8 100644 --- a/client/renderSDL/CTrueTypeFont.h +++ b/client/renderSDL/CTrueTypeFont.h @@ -1,5 +1,5 @@ /* - * Fonts.h, part of VCMI engine + * CTrueTypeFont.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/renderSDL/CursorHardware.cpp b/client/renderSDL/CursorHardware.cpp index a426f06a7..d72a75d28 100644 --- a/client/renderSDL/CursorHardware.cpp +++ b/client/renderSDL/CursorHardware.cpp @@ -1,5 +1,5 @@ /* - * CCursorHandler.cpp, part of VCMI engine + * CursorHardware.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/renderSDL/CursorHardware.h b/client/renderSDL/CursorHardware.h index 7e299130a..41048dcbb 100644 --- a/client/renderSDL/CursorHardware.h +++ b/client/renderSDL/CursorHardware.h @@ -1,5 +1,5 @@ /* - * CCursorHandler.h, part of VCMI engine + * CursorHardware.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/renderSDL/CursorSoftware.cpp b/client/renderSDL/CursorSoftware.cpp index f6ee7f9ac..b2b8019d2 100644 --- a/client/renderSDL/CursorSoftware.cpp +++ b/client/renderSDL/CursorSoftware.cpp @@ -1,5 +1,5 @@ /* - * CCursorHandler.cpp, part of VCMI engine + * CursorSoftware.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/renderSDL/CursorSoftware.h b/client/renderSDL/CursorSoftware.h index f61b5139c..cc450844e 100644 --- a/client/renderSDL/CursorSoftware.h +++ b/client/renderSDL/CursorSoftware.h @@ -1,5 +1,5 @@ /* - * CCursorHandler.h, part of VCMI engine + * CursorSoftware.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/renderSDL/SDLImage.cpp b/client/renderSDL/SDLImage.cpp index c6e609ad4..55c014c61 100644 --- a/client/renderSDL/SDLImage.cpp +++ b/client/renderSDL/SDLImage.cpp @@ -1,5 +1,5 @@ /* - * CAnimation.cpp, part of VCMI engine + * SDLImage.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/renderSDL/SDLImage.h b/client/renderSDL/SDLImage.h index beba79942..850004b51 100644 --- a/client/renderSDL/SDLImage.h +++ b/client/renderSDL/SDLImage.h @@ -1,5 +1,5 @@ /* - * CAnimation.h, part of VCMI engine + * SDLImage.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/renderSDL/SDLImageLoader.cpp b/client/renderSDL/SDLImageLoader.cpp index 82f287fba..1dfbb8e16 100644 --- a/client/renderSDL/SDLImageLoader.cpp +++ b/client/renderSDL/SDLImageLoader.cpp @@ -1,5 +1,5 @@ /* - * CAnimation.cpp, part of VCMI engine + * SDLImageLoader.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * diff --git a/client/renderSDL/SDLImageLoader.h b/client/renderSDL/SDLImageLoader.h index 24ec28f8f..15247b581 100644 --- a/client/renderSDL/SDLImageLoader.h +++ b/client/renderSDL/SDLImageLoader.h @@ -1,5 +1,5 @@ /* - * CAnimation.h, part of VCMI engine + * SDLImageLoader.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * From 108a42e4ba019a06284d6b9ef659a89a54e452c5 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 20:42:06 +0200 Subject: [PATCH 77/79] Reorganized includes for new layout. New class - IImageLoader --- CCallback.cpp | 1 - client/CMT.cpp | 37 ++++----- client/CMakeLists.txt | 2 + client/CMusicHandler.cpp | 4 +- client/CPlayerInterface.cpp | 12 +-- client/CVideoHandler.cpp | 2 +- client/Client.cpp | 4 +- client/ClientCommandManager.cpp | 6 +- client/NetPacksClient.cpp | 24 +++--- client/adventureMap/CAdvMapInt.cpp | 50 ++++------- client/adventureMap/CAdvMapInt.h | 34 ++++---- client/adventureMap/CAdvMapPanel.cpp | 42 ++-------- client/adventureMap/CAdvMapPanel.h | 20 +---- client/adventureMap/CAdventureOptions.cpp | 74 +---------------- client/adventureMap/CAdventureOptions.h | 28 +------ client/adventureMap/CInGameConsole.cpp | 35 ++------ client/adventureMap/CInGameConsole.h | 28 +------ client/adventureMap/CInfoBar.cpp | 36 ++------ client/adventureMap/CInfoBar.h | 15 +--- client/adventureMap/CList.cpp | 39 ++------- client/adventureMap/CList.h | 20 +---- client/adventureMap/CMinimap.cpp | 32 ++----- client/adventureMap/CMinimap.h | 29 +------ client/adventureMap/CResDataBar.cpp | 75 +---------------- client/adventureMap/CResDataBar.h | 27 +----- client/adventureMap/CTerrainRect.cpp | 87 ++++---------------- client/adventureMap/CTerrainRect.h | 21 +---- client/adventureMap/mapHandler.cpp | 42 ++++------ client/adventureMap/mapHandler.h | 6 +- client/battle/BattleEffectsController.cpp | 4 +- client/battle/BattleFieldController.cpp | 6 +- client/battle/BattleInterface.cpp | 5 +- client/battle/BattleInterfaceClasses.cpp | 10 +-- client/battle/BattleObstacleController.cpp | 3 +- client/battle/BattleProjectileController.cpp | 3 +- client/battle/BattleSiegeController.cpp | 4 +- client/battle/BattleStacksController.cpp | 7 +- client/battle/BattleStacksController.h | 2 +- client/battle/BattleWindow.cpp | 8 +- client/battle/CreatureAnimation.cpp | 6 +- client/battle/CreatureAnimation.h | 3 +- client/gui/CGuiHandler.cpp | 7 +- client/gui/CIntObject.cpp | 4 +- client/gui/CIntObject.h | 2 +- client/gui/CursorHandler.cpp | 9 +- client/gui/CursorHandler.h | 10 +-- client/gui/InterfaceObjectConfigurable.cpp | 1 - client/lobby/CBonusSelection.cpp | 6 +- client/lobby/CCampaignInfoScreen.cpp | 2 - client/lobby/CSelectionBase.cpp | 3 +- client/lobby/OptionsTab.cpp | 1 - client/lobby/RandomMapTab.cpp | 1 - client/lobby/SelectionTab.cpp | 3 +- client/mainmenu/CCampaignScreen.cpp | 2 - client/mainmenu/CMainMenu.cpp | 4 - client/render/CAnimation.cpp | 13 +-- client/render/CAnimation.h | 16 +--- client/render/CBitmapHandler.cpp | 8 +- client/render/CDefFile.cpp | 41 ++++----- client/render/CDefFile.h | 26 +----- client/render/CFadeAnimation.cpp | 14 +--- client/render/CFadeAnimation.h | 9 -- client/render/Canvas.cpp | 7 +- client/render/Canvas.h | 2 +- client/render/Graphics.cpp | 10 ++- client/render/Graphics.h | 3 +- client/render/ICursor.h | 10 +-- client/render/IFont.cpp | 11 +-- client/render/IFont.h | 6 -- client/render/IImage.h | 13 +-- client/render/IImageLoader.h | 31 +++++++ client/renderSDL/CBitmapFont.cpp | 9 +- client/renderSDL/CBitmapFont.h | 15 +--- client/renderSDL/CBitmapHanFont.cpp | 10 ++- client/renderSDL/CBitmapHanFont.h | 31 +------ client/renderSDL/CTrueTypeFont.cpp | 18 ++-- client/renderSDL/CTrueTypeFont.h | 11 +-- client/renderSDL/CursorHardware.cpp | 6 +- client/renderSDL/CursorHardware.h | 1 + client/renderSDL/CursorSoftware.cpp | 11 +-- client/renderSDL/CursorSoftware.h | 1 + client/renderSDL/SDLImage.cpp | 14 ++-- client/renderSDL/SDLImage.h | 21 ++--- client/renderSDL/SDLImageLoader.cpp | 25 ++---- client/renderSDL/SDLImageLoader.h | 34 ++------ client/renderSDL/SDLRWwrapper.cpp | 4 +- client/renderSDL/SDL_Extensions.cpp | 31 +++---- client/widgets/Buttons.cpp | 3 +- client/widgets/Buttons.h | 2 +- client/widgets/CComponent.cpp | 10 ++- client/widgets/CreatureCostBox.h | 4 +- client/widgets/Images.cpp | 10 +-- client/widgets/MiscWidgets.cpp | 5 +- client/widgets/TextControls.cpp | 10 ++- client/widgets/TextControls.h | 3 +- client/windows/CCastleInterface.cpp | 13 ++- client/windows/CHeroWindow.cpp | 12 ++- client/windows/CKingdomInterface.cpp | 5 +- client/windows/CMessage.cpp | 17 ++-- client/windows/CMessage.h | 4 +- client/windows/CQuestLog.cpp | 7 +- client/windows/CQuestLog.h | 2 +- client/windows/CSpellWindow.cpp | 7 +- client/windows/CTradeWindow.cpp | 7 +- client/windows/CWindowObject.cpp | 14 ++-- client/windows/CreaturePurchaseCard.cpp | 16 ++-- client/windows/GUIClasses.cpp | 19 ++--- client/windows/InfoWindows.cpp | 14 ++-- client/windows/QuickRecruitmentWindow.cpp | 2 +- 109 files changed, 487 insertions(+), 1109 deletions(-) create mode 100644 client/render/IImageLoader.h diff --git a/CCallback.cpp b/CCallback.cpp index a1fea415c..4e4e3eeee 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -21,7 +21,6 @@ #include "lib/CGeneralTextHandler.h" #include "lib/CHeroHandler.h" #include "lib/NetPacks.h" -#include "client/mapHandler.h" #include "lib/CArtHandler.h" #include "lib/GameConstants.h" #include "lib/CPlayerState.h" diff --git a/client/CMT.cpp b/client/CMT.cpp index 5eb2f6b9a..a7566075e 100644 --- a/client/CMT.cpp +++ b/client/CMT.cpp @@ -11,48 +11,43 @@ // #include "StdInc.h" -#include - -#include "gui/SDL_Extensions.h" #include "CGameInfo.h" -#include "mapHandler.h" - -#include "../lib/filesystem/Filesystem.h" -#include "../lib/filesystem/FileStream.h" #include "mainmenu/CMainMenu.h" #include "lobby/CSelectionBase.h" #include "windows/CCastleInterface.h" -#include "../lib/CConsoleHandler.h" #include "gui/CursorHandler.h" -#include "../lib/CGameState.h" -#include "../CCallback.h" #include "CPlayerInterface.h" -#include "windows/CAdvmapInterface.h" -#include "../lib/CBuildingHandler.h" #include "CVideoHandler.h" +#include "CMusicHandler.h" +#include "Client.h" +#include "gui/CGuiHandler.h" +#include "CServerHandler.h" +#include "gui/NotificationHandler.h" +#include "ClientCommandManager.h" +#include "windows/CMessage.h" +#include "renderSDL/SDL_Extensions.h" + +#include "../lib/filesystem/Filesystem.h" +#include "../lib/filesystem/FileStream.h" +#include "../lib/CConsoleHandler.h" +#include "../lib/CGameState.h" +#include "../lib/CBuildingHandler.h" +#include "../CCallback.h" #include "../lib/CHeroHandler.h" #include "../lib/spells/CSpellHandler.h" -#include "CMusicHandler.h" #include "../lib/CGeneralTextHandler.h" -#include "Graphics.h" -#include "Client.h" #include "../lib/serializer/BinaryDeserializer.h" #include "../lib/serializer/BinarySerializer.h" #include "../lib/VCMIDirs.h" #include "../lib/NetPacks.h" -#include "CMessage.h" #include "../lib/CModHandler.h" #include "../lib/CTownHandler.h" -#include "gui/CGuiHandler.h" #include "../lib/logging/CBasicLogConfigurator.h" #include "../lib/CPlayerState.h" -#include "gui/CAnimation.h" #include "../lib/serializer/Connection.h" -#include "CServerHandler.h" -#include "gui/NotificationHandler.h" -#include "ClientCommandManager.h" #include +#include #include "mainmenu/CPrologEpilogVideo.h" #include diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 898b6de48..fd1e5713d 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -25,6 +25,7 @@ set(client_SRCS battle/BattleSiegeController.cpp battle/BattleStacksController.cpp battle/BattleWindow.cpp + battle/CreatureAnimation.cpp gui/CGuiHandler.cpp gui/CIntObject.cpp @@ -163,6 +164,7 @@ set(client_HEADERS render/ICursor.h render/IFont.h render/IImage.h + render/IImageLoader.h renderSDL/CBitmapFont.h renderSDL/CBitmapHanFont.h diff --git a/client/CMusicHandler.cpp b/client/CMusicHandler.cpp index 4e2f3bdb0..db0478c17 100644 --- a/client/CMusicHandler.cpp +++ b/client/CMusicHandler.cpp @@ -13,7 +13,8 @@ #include "CMusicHandler.h" #include "CGameInfo.h" -#include "SDLRWwrapper.h" +#include "renderSDL/SDLRWwrapper.h" + #include "../lib/JsonNode.h" #include "../lib/GameConstants.h" #include "../lib/filesystem/Filesystem.h" @@ -22,6 +23,7 @@ #include "../lib/VCMIDirs.h" #include "../lib/TerrainHandler.h" + #define VCMI_SOUND_NAME(x) #define VCMI_SOUND_FILE(y) #y, diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 17689f6e0..5fcb149e4 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -11,7 +11,8 @@ #include -#include "windows/CAdvmapInterface.h" +#include "adventureMap/CAdvMapInt.h" +#include "adventureMap/mapHandler.h" #include "battle/BattleInterface.h" #include "battle/BattleEffectsController.h" #include "battle/BattleFieldController.h" @@ -25,15 +26,15 @@ #include "windows/CHeroWindow.h" #include "windows/CCreatureWindow.h" #include "windows/CQuestLog.h" -#include "CMessage.h" #include "CPlayerInterface.h" -#include "gui/SDL_Extensions.h" #include "widgets/CComponent.h" +#include "widgets/Buttons.h" #include "windows/CTradeWindow.h" #include "windows/CSpellWindow.h" #include "../lib/CConfigHandler.h" -#include "Graphics.h" #include "windows/GUIClasses.h" +#include "render/CAnimation.h" +#include "render/IImage.h" #include "../lib/CArtHandler.h" #include "../lib/CGeneralTextHandler.h" #include "../lib/CHeroHandler.h" @@ -51,13 +52,11 @@ #include "../lib/NetPacks.h"//todo: remove #include "../lib/mapping/CMap.h" #include "../lib/VCMIDirs.h" -#include "mapHandler.h" #include "../lib/CStopWatch.h" #include "../lib/StartInfo.h" #include "../lib/CPlayerState.h" #include "../lib/GameConstants.h" #include "gui/CGuiHandler.h" -#include "gui/CAnimation.h" #include "windows/InfoWindows.h" #include "../lib/UnlockGuard.h" #include "../lib/CPathfinder.h" @@ -67,6 +66,7 @@ // FIXME: only needed for CGameState::mutex #include "../lib/CGameState.h" #include "gui/NotificationHandler.h" +#include "adventureMap/CInGameConsole.h" #include diff --git a/client/CVideoHandler.cpp b/client/CVideoHandler.cpp index 22d102021..4fb0fcb1d 100644 --- a/client/CVideoHandler.cpp +++ b/client/CVideoHandler.cpp @@ -11,7 +11,7 @@ #include "CVideoHandler.h" #include "gui/CGuiHandler.h" -#include "gui/SDL_Extensions.h" +#include "renderSDL/SDL_Extensions.h" #include "CPlayerInterface.h" #include "../lib/filesystem/Filesystem.h" diff --git a/client/Client.cpp b/client/Client.cpp index 397c241bb..5add9104a 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -13,6 +13,8 @@ #include "CMusicHandler.h" #include "../lib/mapping/CCampaignHandler.h" #include "../CCallback.h" +#include "adventureMap/CAdvMapInt.h" +#include "adventureMap/mapHandler.h" #include "../lib/CConsoleHandler.h" #include "CGameInfo.h" #include "../lib/CGameState.h" @@ -35,7 +37,6 @@ #include "../lib/mapping/CMap.h" #include "../lib/mapping/CMapService.h" #include "../lib/JsonNode.h" -#include "mapHandler.h" #include "../lib/CConfigHandler.h" #include "mainmenu/CMainMenu.h" #include "mainmenu/CCampaignScreen.h" @@ -46,7 +47,6 @@ #include "gui/CGuiHandler.h" #include "CServerHandler.h" #include "../lib/ScriptHandler.h" -#include "windows/CAdvmapInterface.h" #include #ifdef VCMI_ANDROID diff --git a/client/ClientCommandManager.cpp b/client/ClientCommandManager.cpp index 0fb190826..213c9b2de 100644 --- a/client/ClientCommandManager.cpp +++ b/client/ClientCommandManager.cpp @@ -12,6 +12,8 @@ #include "ClientCommandManager.h" #include "Client.h" +#include "adventureMap/CInGameConsole.h" +#include "adventureMap/CAdvMapInt.h" #include "CPlayerInterface.h" #include "CServerHandler.h" #include "gui/CGuiHandler.h" @@ -20,14 +22,14 @@ #include "../lib/CGameState.h" #include "../lib/CPlayerState.h" #include "../lib/StringConstants.h" -#include "gui/CAnimation.h" -#include "windows/CAdvmapInterface.h" #include "windows/CCastleInterface.h" +#include "render/CAnimation.h" #include "../CCallback.h" #include "../lib/CGeneralTextHandler.h" #include "../lib/CHeroHandler.h" #include "../lib/CModHandler.h" #include "../lib/VCMIDirs.h" +#include "CMT.h" #ifdef SCRIPTING_ENABLED #include "../lib/ScriptHandler.h" diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 30a09d750..1565d95bc 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -10,12 +10,21 @@ #include "StdInc.h" #include "../lib/NetPacks.h" -#include "../lib/filesystem/Filesystem.h" -#include "../lib/filesystem/FileInfo.h" -#include "../CCallback.h" #include "Client.h" #include "CPlayerInterface.h" #include "CGameInfo.h" +#include "windows/GUIClasses.h" +#include "adventureMap/mapHandler.h" +#include "adventureMap/CInGameConsole.h" +#include "battle/BattleInterface.h" +#include "gui/CGuiHandler.h" +#include "widgets/MiscWidgets.h" +#include "CMT.h" +#include "CServerHandler.h" + +#include "../CCallback.h" +#include "../lib/filesystem/Filesystem.h" +#include "../lib/filesystem/FileInfo.h" #include "../lib/serializer/Connection.h" #include "../lib/serializer/BinarySerializer.h" #include "../lib/CGeneralTextHandler.h" @@ -26,22 +35,13 @@ #include "../lib/spells/CSpellHandler.h" #include "../lib/CSoundBase.h" #include "../lib/StartInfo.h" -#include "mapHandler.h" -#include "windows/GUIClasses.h" #include "../lib/CConfigHandler.h" -#include "gui/SDL_Extensions.h" -#include "battle/BattleInterface.h" #include "../lib/mapping/CCampaignHandler.h" #include "../lib/CGameState.h" #include "../lib/CStack.h" #include "../lib/battle/BattleInfo.h" #include "../lib/GameConstants.h" #include "../lib/CPlayerState.h" -#include "gui/CGuiHandler.h" -#include "widgets/MiscWidgets.h" -#include "widgets/AdventureMapClasses.h" -#include "CMT.h" -#include "CServerHandler.h" // TODO: as Tow suggested these template should all be part of CClient // This will require rework spectator interface properly though diff --git a/client/adventureMap/CAdvMapInt.cpp b/client/adventureMap/CAdvMapInt.cpp index e9005bfd0..e7a6139d0 100644 --- a/client/adventureMap/CAdvMapInt.cpp +++ b/client/adventureMap/CAdvMapInt.cpp @@ -8,58 +8,44 @@ * */ #include "StdInc.h" -#include "CAdvmapInterface.h" +#include "CAdvMapInt.h" -#include "CCastleInterface.h" -#include "CHeroWindow.h" -#include "CKingdomInterface.h" -#include "CSpellWindow.h" -#include "CTradeWindow.h" -#include "GUIClasses.h" -#include "InfoWindows.h" +#include "CAdvMapPanel.h" +#include "CAdventureOptions.h" +#include "CInGameConsole.h" +#include "mapHandler.h" -#include "../CBitmapHandler.h" +#include "../windows/CKingdomInterface.h" +#include "../windows/CSpellWindow.h" +#include "../windows/CTradeWindow.h" +#include "../windows/GUIClasses.h" +#include "../windows/InfoWindows.h" #include "../CGameInfo.h" -#include "../CMessage.h" #include "../CMusicHandler.h" #include "../CPlayerInterface.h" -#include "../mainmenu/CMainMenu.h" -#include "../lobby/CSelectionBase.h" -#include "../lobby/CCampaignInfoScreen.h" #include "../lobby/CSavingScreen.h" -#include "../lobby/CScenarioInfoScreen.h" -#include "../Graphics.h" -#include "../mapHandler.h" - -#include "../gui/CAnimation.h" +#include "../render/CAnimation.h" #include "../gui/CursorHandler.h" +#include "../render/IImage.h" #include "../gui/CGuiHandler.h" -#include "../gui/SDL_Extensions.h" -#include "../widgets/MiscWidgets.h" +#include "../widgets/TextControls.h" +#include "../widgets/Buttons.h" #include "../../CCallback.h" - #include "../../lib/CConfigHandler.h" -#include "../../lib/CGameState.h" #include "../../lib/CGeneralTextHandler.h" -#include "../../lib/CHeroHandler.h" -#include "../../lib/CSoundBase.h" #include "../../lib/spells/CSpellHandler.h" -#include "../../lib/CTownHandler.h" -#include "../../lib/JsonNode.h" #include "../../lib/mapObjects/CGHeroInstance.h" +#include "../../lib/mapObjects/CGTownInstance.h" +#include "../../lib/CPathfinder.h" #include "../../lib/mapping/CMap.h" #include "../../lib/UnlockGuard.h" -#include "../../lib/VCMI_Lib.h" -#include "../../lib/StartInfo.h" -#include "../../lib/mapping/CMapInfo.h" #include "../../lib/TerrainHandler.h" #include #include #define ADVOPT (conf.go()->ac) -using namespace CSDL_Ext; std::shared_ptr adventureInt; @@ -630,7 +616,7 @@ void CAdvMapInt::handleMapScrollingUpdate() int scrollSpeed = static_cast(settings["adventure"]["scrollSpeed"].Float()); //if advmap needs updating AND (no dialog is shown OR ctrl is pressed) if((animValHitCount % (4 / scrollSpeed)) == 0 - && ((GH.topInt().get() == this) || isCtrlKeyDown())) + && ((GH.topInt().get() == this) || CSDL_Ext::isCtrlKeyDown())) { if((scrollingDir & LEFT) && (position.x > -CGI->mh->frameW)) position.x--; @@ -994,7 +980,7 @@ void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent ) // adventure map scrolling with mouse // currently disabled in world view mode (as it is in OH3), but should work correctly if mode check is removed // don't scroll if there is no window in focus - these events don't seem to correspond to the actual mouse movement - if(!isCtrlKeyDown() && isActive() && sEvent.windowID != 0 && mode == EAdvMapMode::NORMAL) + if(!CSDL_Ext::isCtrlKeyDown() && isActive() && sEvent.windowID != 0 && mode == EAdvMapMode::NORMAL) { if(sEvent.x<15) { diff --git a/client/adventureMap/CAdvMapInt.h b/client/adventureMap/CAdvMapInt.h index d3fa66ffc..ea7c07e80 100644 --- a/client/adventureMap/CAdvMapInt.h +++ b/client/adventureMap/CAdvMapInt.h @@ -9,35 +9,39 @@ */ #pragma once -#include "../widgets/AdventureMapClasses.h" -#include "CWindowObject.h" +#include "../gui/CIntObject.h" -#include "../widgets/TextControls.h" -#include "../widgets/Buttons.h" +#include "../../lib/int3.h" +#include "../../lib/GameConstants.h" -#include "../../lib/spells/ViewSpellInt.h" +#include "CTerrainRect.h" +#include "CResDataBar.h" +#include "CList.h" +#include "CInfoBar.h" +#include "CMinimap.h" VCMI_LIB_NAMESPACE_BEGIN -struct CGPath; -struct CGPathNode; +class CGObjectInstance; class CGHeroInstance; class CGTownInstance; -class CSpell; +class CArmedInstance; class IShipyard; +struct CGPathNode; +struct ObjectPosInfo; VCMI_LIB_NAMESPACE_END -class CCallback; -class CAdvMapInt; -class CHeroWindow; -enum class EMapAnimRedrawStatus; -class CFadeAnimation; +class CButton; +class IImage; +class CAnimImage; +class CGStatusBar; +class CAdvMapPanel; +class CAdvMapWorldViewPanel; +class CAnimation; struct MapDrawingInfo; -/*****************************/ - enum class EAdvMapMode { NORMAL, diff --git a/client/adventureMap/CAdvMapPanel.cpp b/client/adventureMap/CAdvMapPanel.cpp index 986619c90..027afc273 100644 --- a/client/adventureMap/CAdvMapPanel.cpp +++ b/client/adventureMap/CAdvMapPanel.cpp @@ -7,45 +7,15 @@ * Full text of license available in license.txt file, in main folder * */ + #include "StdInc.h" -#include "AdventureMapClasses.h" - -#include - -#include "MiscWidgets.h" -#include "CComponent.h" -#include "Images.h" - -#include "../CGameInfo.h" -#include "../CMusicHandler.h" -#include "../CPlayerInterface.h" -#include "../mainmenu/CMainMenu.h" +#include "CAdvMapPanel.h" +#include "../widgets/Buttons.h" +#include "../widgets/Images.h" +#include "../render/CAnimation.h" +#include "../render/IImage.h" #include "../gui/CGuiHandler.h" -#include "../gui/SDL_PixelAccess.h" -#include "../gui/CAnimation.h" - -#include "../windows/InfoWindows.h" -#include "../windows/CAdvmapInterface.h" - -#include "../battle/BattleInterfaceClasses.h" -#include "../battle/BattleInterface.h" - -#include "../../CCallback.h" -#include "../../lib/StartInfo.h" -#include "../../lib/CGameState.h" -#include "../../lib/CGeneralTextHandler.h" -#include "../../lib/CHeroHandler.h" -#include "../../lib/CModHandler.h" -#include "../../lib/CTownHandler.h" -#include "../../lib/TerrainHandler.h" -#include "../../lib/mapObjects/CGHeroInstance.h" -#include "../../lib/mapping/CMap.h" -#include "ClientCommandManager.h" - -#include -#include -#include CAdvMapPanel::CAdvMapPanel(std::shared_ptr bg, Point position) : CIntObject() diff --git a/client/adventureMap/CAdvMapPanel.h b/client/adventureMap/CAdvMapPanel.h index dae9e7c5a..0f4ef172f 100644 --- a/client/adventureMap/CAdvMapPanel.h +++ b/client/adventureMap/CAdvMapPanel.h @@ -9,32 +9,16 @@ */ #pragma once -#include "ObjectLists.h" -#include "../../lib/FunctionList.h" +#include "../gui/CIntObject.h" VCMI_LIB_NAMESPACE_BEGIN - -class CArmedInstance; -class CGGarrison; -class CGObjectInstance; -class CGHeroInstance; -class CGTownInstance; -struct Component; -struct InfoAboutArmy; -struct InfoAboutHero; -struct InfoAboutTown; - +class PlayerColor; VCMI_LIB_NAMESPACE_END class CAnimation; class CAnimImage; -class CShowableAnim; class CFilledTexture; class CButton; -class CComponent; -class CHeroTooltip; -class CTownTooltip; -class CTextBox; class IImage; /// simple panel that contains other displayable elements; used to separate groups of controls diff --git a/client/adventureMap/CAdventureOptions.cpp b/client/adventureMap/CAdventureOptions.cpp index ffc074d4b..7e96ac4b0 100644 --- a/client/adventureMap/CAdventureOptions.cpp +++ b/client/adventureMap/CAdventureOptions.cpp @@ -7,87 +7,21 @@ * Full text of license available in license.txt file, in main folder * */ + #include "StdInc.h" -#include "CAdvmapInterface.h" +#include "CAdventureOptions.h" -#include "CCastleInterface.h" -#include "CHeroWindow.h" -#include "CKingdomInterface.h" -#include "CSpellWindow.h" -#include "CTradeWindow.h" -#include "GUIClasses.h" -#include "InfoWindows.h" +#include "CAdvMapInt.h" -#include "../CBitmapHandler.h" #include "../CGameInfo.h" -#include "../CMessage.h" -#include "../CMusicHandler.h" #include "../CPlayerInterface.h" -#include "../mainmenu/CMainMenu.h" -#include "../lobby/CSelectionBase.h" #include "../lobby/CCampaignInfoScreen.h" -#include "../lobby/CSavingScreen.h" #include "../lobby/CScenarioInfoScreen.h" -#include "../Graphics.h" -#include "../mapHandler.h" - -#include "../gui/CAnimation.h" -#include "../gui/CursorHandler.h" #include "../gui/CGuiHandler.h" -#include "../gui/SDL_Extensions.h" -#include "../widgets/MiscWidgets.h" +#include "../widgets/Buttons.h" #include "../../CCallback.h" - -#include "../../lib/CConfigHandler.h" -#include "../../lib/CGameState.h" -#include "../../lib/CGeneralTextHandler.h" -#include "../../lib/CHeroHandler.h" -#include "../../lib/CSoundBase.h" -#include "../../lib/spells/CSpellHandler.h" -#include "../../lib/CTownHandler.h" -#include "../../lib/JsonNode.h" -#include "../../lib/mapObjects/CGHeroInstance.h" -#include "../../lib/mapping/CMap.h" -#include "../../lib/UnlockGuard.h" -#include "../../lib/VCMI_Lib.h" #include "../../lib/StartInfo.h" -#include "../../lib/mapping/CMapInfo.h" -#include "../../lib/TerrainHandler.h" - -#include -#include - -#define ADVOPT (conf.go()->ac) -using namespace CSDL_Ext; - -std::shared_ptr adventureInt; - -static void setScrollingCursor(ui8 direction) -{ - if(direction & CAdvMapInt::RIGHT) - { - if(direction & CAdvMapInt::UP) - CCS->curh->set(Cursor::Map::SCROLL_NORTHEAST); - else if(direction & CAdvMapInt::DOWN) - CCS->curh->set(Cursor::Map::SCROLL_SOUTHEAST); - else - CCS->curh->set(Cursor::Map::SCROLL_EAST); - } - else if(direction & CAdvMapInt::LEFT) - { - if(direction & CAdvMapInt::UP) - CCS->curh->set(Cursor::Map::SCROLL_NORTHWEST); - else if(direction & CAdvMapInt::DOWN) - CCS->curh->set(Cursor::Map::SCROLL_SOUTHWEST); - else - CCS->curh->set(Cursor::Map::SCROLL_WEST); - } - else if(direction & CAdvMapInt::UP) - CCS->curh->set(Cursor::Map::SCROLL_NORTH); - else if(direction & CAdvMapInt::DOWN) - CCS->curh->set(Cursor::Map::SCROLL_SOUTH); -} CAdventureOptions::CAdventureOptions() : CWindowObject(PLAYER_COLORED, "ADVOPTS") diff --git a/client/adventureMap/CAdventureOptions.h b/client/adventureMap/CAdventureOptions.h index 498af6a1f..aa651ce77 100644 --- a/client/adventureMap/CAdventureOptions.h +++ b/client/adventureMap/CAdventureOptions.h @@ -9,33 +9,9 @@ */ #pragma once -#include "../widgets/AdventureMapClasses.h" -#include "CWindowObject.h" - -#include "../widgets/TextControls.h" -#include "../widgets/Buttons.h" - -#include "../../lib/spells/ViewSpellInt.h" - -VCMI_LIB_NAMESPACE_BEGIN - -struct CGPath; -struct CGPathNode; -class CGHeroInstance; -class CGTownInstance; -class CSpell; -class IShipyard; - -VCMI_LIB_NAMESPACE_END - -class CCallback; -class CAdvMapInt; -class CHeroWindow; -enum class EMapAnimRedrawStatus; -class CFadeAnimation; - -struct MapDrawingInfo; +#include "../windows/CWindowObject.h" +class CButton; /// Adventure options dialog where you can view the world, dig, play the replay of the last turn,... class CAdventureOptions : public CWindowObject diff --git a/client/adventureMap/CInGameConsole.cpp b/client/adventureMap/CInGameConsole.cpp index c5c3ce32a..bda566a30 100644 --- a/client/adventureMap/CInGameConsole.cpp +++ b/client/adventureMap/CInGameConsole.cpp @@ -7,44 +7,23 @@ * Full text of license available in license.txt file, in main folder * */ + #include "StdInc.h" -#include "AdventureMapClasses.h" - -#include - -#include "MiscWidgets.h" -#include "CComponent.h" -#include "Images.h" +#include "CInGameConsole.h" +#include "../renderSDL/SDL_Extensions.h" #include "../CGameInfo.h" #include "../CMusicHandler.h" #include "../CPlayerInterface.h" -#include "../mainmenu/CMainMenu.h" - #include "../gui/CGuiHandler.h" -#include "../gui/SDL_PixelAccess.h" -#include "../gui/CAnimation.h" - -#include "../windows/InfoWindows.h" -#include "../windows/CAdvmapInterface.h" - -#include "../battle/BattleInterfaceClasses.h" -#include "../battle/BattleInterface.h" +#include "../ClientCommandManager.h" #include "../../CCallback.h" -#include "../../lib/StartInfo.h" -#include "../../lib/CGameState.h" +#include "../../lib/CConfigHandler.h" #include "../../lib/CGeneralTextHandler.h" -#include "../../lib/CHeroHandler.h" -#include "../../lib/CModHandler.h" -#include "../../lib/CTownHandler.h" -#include "../../lib/TerrainHandler.h" -#include "../../lib/mapObjects/CGHeroInstance.h" -#include "../../lib/mapping/CMap.h" -#include "ClientCommandManager.h" +#include "../../lib/mapObjects/CArmedInstance.h" -#include -#include +#include #include CInGameConsole::CInGameConsole() diff --git a/client/adventureMap/CInGameConsole.h b/client/adventureMap/CInGameConsole.h index 7e08d5abb..6f0f9851e 100644 --- a/client/adventureMap/CInGameConsole.h +++ b/client/adventureMap/CInGameConsole.h @@ -9,33 +9,7 @@ */ #pragma once -#include "ObjectLists.h" -#include "../../lib/FunctionList.h" - -VCMI_LIB_NAMESPACE_BEGIN - -class CArmedInstance; -class CGGarrison; -class CGObjectInstance; -class CGHeroInstance; -class CGTownInstance; -struct Component; -struct InfoAboutArmy; -struct InfoAboutHero; -struct InfoAboutTown; - -VCMI_LIB_NAMESPACE_END - -class CAnimation; -class CAnimImage; -class CShowableAnim; -class CFilledTexture; -class CButton; -class CComponent; -class CHeroTooltip; -class CTownTooltip; -class CTextBox; -class IImage; +#include "../gui/CIntObject.h" class CInGameConsole : public CIntObject { diff --git a/client/adventureMap/CInfoBar.cpp b/client/adventureMap/CInfoBar.cpp index f202b77c7..ec6611bac 100644 --- a/client/adventureMap/CInfoBar.cpp +++ b/client/adventureMap/CInfoBar.cpp @@ -7,45 +7,25 @@ * Full text of license available in license.txt file, in main folder * */ + #include "StdInc.h" -#include "AdventureMapClasses.h" +#include "CInfoBar.h" -#include - -#include "MiscWidgets.h" -#include "CComponent.h" -#include "Images.h" +#include "CAdvMapInt.h" +#include "../widgets/CComponent.h" +#include "../widgets/Images.h" +#include "../widgets/TextControls.h" +#include "../widgets/MiscWidgets.h" #include "../CGameInfo.h" #include "../CMusicHandler.h" #include "../CPlayerInterface.h" -#include "../mainmenu/CMainMenu.h" - #include "../gui/CGuiHandler.h" -#include "../gui/SDL_PixelAccess.h" -#include "../gui/CAnimation.h" - -#include "../windows/InfoWindows.h" -#include "../windows/CAdvmapInterface.h" - -#include "../battle/BattleInterfaceClasses.h" -#include "../battle/BattleInterface.h" #include "../../CCallback.h" -#include "../../lib/StartInfo.h" -#include "../../lib/CGameState.h" #include "../../lib/CGeneralTextHandler.h" -#include "../../lib/CHeroHandler.h" -#include "../../lib/CModHandler.h" -#include "../../lib/CTownHandler.h" -#include "../../lib/TerrainHandler.h" #include "../../lib/mapObjects/CGHeroInstance.h" -#include "../../lib/mapping/CMap.h" -#include "ClientCommandManager.h" - -#include -#include -#include +#include "../../lib/mapObjects/CGTownInstance.h" CInfoBar::CVisibleInfo::CVisibleInfo() : CIntObject(0, Point(8, 12)) diff --git a/client/adventureMap/CInfoBar.h b/client/adventureMap/CInfoBar.h index ba56c3178..0c6106011 100644 --- a/client/adventureMap/CInfoBar.h +++ b/client/adventureMap/CInfoBar.h @@ -9,33 +9,24 @@ */ #pragma once -#include "ObjectLists.h" -#include "../../lib/FunctionList.h" +#include "../gui/CIntObject.h" VCMI_LIB_NAMESPACE_BEGIN -class CArmedInstance; -class CGGarrison; -class CGObjectInstance; class CGHeroInstance; class CGTownInstance; struct Component; -struct InfoAboutArmy; -struct InfoAboutHero; -struct InfoAboutTown; +class PlayerColor; VCMI_LIB_NAMESPACE_END -class CAnimation; class CAnimImage; class CShowableAnim; -class CFilledTexture; -class CButton; class CComponent; class CHeroTooltip; class CTownTooltip; +class CLabel; class CTextBox; -class IImage; /// Info box which shows next week/day information, hold the current date class CInfoBar : public CIntObject diff --git a/client/adventureMap/CList.cpp b/client/adventureMap/CList.cpp index e9d2391e7..b35918c99 100644 --- a/client/adventureMap/CList.cpp +++ b/client/adventureMap/CList.cpp @@ -7,45 +7,24 @@ * Full text of license available in license.txt file, in main folder * */ + #include "StdInc.h" -#include "AdventureMapClasses.h" +#include "CList.h" -#include - -#include "MiscWidgets.h" -#include "CComponent.h" -#include "Images.h" - -#include "../CGameInfo.h" -#include "../CMusicHandler.h" -#include "../CPlayerInterface.h" -#include "../mainmenu/CMainMenu.h" - -#include "../gui/CGuiHandler.h" -#include "../gui/SDL_PixelAccess.h" -#include "../gui/CAnimation.h" +#include "CAdvMapInt.h" +#include "../widgets/Images.h" +#include "../widgets/Buttons.h" #include "../windows/InfoWindows.h" -#include "../windows/CAdvmapInterface.h" +#include "../CGameInfo.h" +#include "../CPlayerInterface.h" +#include "../gui/CGuiHandler.h" -#include "../battle/BattleInterfaceClasses.h" -#include "../battle/BattleInterface.h" - -#include "../../CCallback.h" -#include "../../lib/StartInfo.h" -#include "../../lib/CGameState.h" #include "../../lib/CGeneralTextHandler.h" #include "../../lib/CHeroHandler.h" #include "../../lib/CModHandler.h" -#include "../../lib/CTownHandler.h" -#include "../../lib/TerrainHandler.h" #include "../../lib/mapObjects/CGHeroInstance.h" -#include "../../lib/mapping/CMap.h" -#include "ClientCommandManager.h" - -#include -#include -#include +#include "../../lib/mapObjects/CGTownInstance.h" CList::CListItem::CListItem(CList * Parent) : CIntObject(LCLICK | RCLICK | HOVER), diff --git a/client/adventureMap/CList.h b/client/adventureMap/CList.h index 11568779f..494c4d19b 100644 --- a/client/adventureMap/CList.h +++ b/client/adventureMap/CList.h @@ -9,33 +9,19 @@ */ #pragma once -#include "ObjectLists.h" +#include "../gui/CIntObject.h" + +#include "../widgets/ObjectLists.h" #include "../../lib/FunctionList.h" VCMI_LIB_NAMESPACE_BEGIN -class CArmedInstance; -class CGGarrison; -class CGObjectInstance; class CGHeroInstance; class CGTownInstance; -struct Component; -struct InfoAboutArmy; -struct InfoAboutHero; -struct InfoAboutTown; VCMI_LIB_NAMESPACE_END -class CAnimation; -class CAnimImage; -class CShowableAnim; -class CFilledTexture; class CButton; -class CComponent; -class CHeroTooltip; -class CTownTooltip; -class CTextBox; -class IImage; /// Base UI Element for hero\town lists class CList : public CIntObject diff --git a/client/adventureMap/CMinimap.cpp b/client/adventureMap/CMinimap.cpp index a52989a57..9e0f41c5e 100644 --- a/client/adventureMap/CMinimap.cpp +++ b/client/adventureMap/CMinimap.cpp @@ -7,45 +7,25 @@ * Full text of license available in license.txt file, in main folder * */ + #include "StdInc.h" -#include "AdventureMapClasses.h" +#include "CMinimap.h" -#include - -#include "MiscWidgets.h" -#include "CComponent.h" -#include "Images.h" +#include "CAdvMapInt.h" +#include "../widgets/Images.h" #include "../CGameInfo.h" -#include "../CMusicHandler.h" #include "../CPlayerInterface.h" -#include "../mainmenu/CMainMenu.h" - #include "../gui/CGuiHandler.h" -#include "../gui/SDL_PixelAccess.h" -#include "../gui/CAnimation.h" - -#include "../windows/InfoWindows.h" -#include "../windows/CAdvmapInterface.h" - -#include "../battle/BattleInterfaceClasses.h" -#include "../battle/BattleInterface.h" +#include "../renderSDL/SDL_PixelAccess.h" #include "../../CCallback.h" -#include "../../lib/StartInfo.h" -#include "../../lib/CGameState.h" #include "../../lib/CGeneralTextHandler.h" -#include "../../lib/CHeroHandler.h" -#include "../../lib/CModHandler.h" -#include "../../lib/CTownHandler.h" #include "../../lib/TerrainHandler.h" #include "../../lib/mapObjects/CGHeroInstance.h" -#include "../../lib/mapping/CMap.h" -#include "ClientCommandManager.h" +#include "../../lib/mapping/CMapDefines.h" #include -#include -#include const SDL_Color & CMinimapInstance::getTileColor(const int3 & pos) { diff --git a/client/adventureMap/CMinimap.h b/client/adventureMap/CMinimap.h index 5ea772963..f7df33b2f 100644 --- a/client/adventureMap/CMinimap.h +++ b/client/adventureMap/CMinimap.h @@ -9,34 +9,11 @@ */ #pragma once -#include "ObjectLists.h" -#include "../../lib/FunctionList.h" +#include "../gui/CIntObject.h" +#include "../../lib/GameConstants.h" -VCMI_LIB_NAMESPACE_BEGIN - -class CArmedInstance; -class CGGarrison; -class CGObjectInstance; -class CGHeroInstance; -class CGTownInstance; -struct Component; -struct InfoAboutArmy; -struct InfoAboutHero; -struct InfoAboutTown; - -VCMI_LIB_NAMESPACE_END - -class CAnimation; -class CAnimImage; -class CShowableAnim; -class CFilledTexture; -class CButton; -class CComponent; -class CHeroTooltip; -class CTownTooltip; -class CTextBox; -class IImage; +struct SDL_Color; class CMinimap; class CMinimapInstance : public CIntObject diff --git a/client/adventureMap/CResDataBar.cpp b/client/adventureMap/CResDataBar.cpp index 9e7e75544..aaa627297 100644 --- a/client/adventureMap/CResDataBar.cpp +++ b/client/adventureMap/CResDataBar.cpp @@ -8,86 +8,19 @@ * */ #include "StdInc.h" -#include "CAdvmapInterface.h" +#include "CResDataBar.h" -#include "CCastleInterface.h" -#include "CHeroWindow.h" -#include "CKingdomInterface.h" -#include "CSpellWindow.h" -#include "CTradeWindow.h" -#include "GUIClasses.h" -#include "InfoWindows.h" - -#include "../CBitmapHandler.h" #include "../CGameInfo.h" -#include "../CMessage.h" -#include "../CMusicHandler.h" #include "../CPlayerInterface.h" -#include "../mainmenu/CMainMenu.h" -#include "../lobby/CSelectionBase.h" -#include "../lobby/CCampaignInfoScreen.h" -#include "../lobby/CSavingScreen.h" -#include "../lobby/CScenarioInfoScreen.h" -#include "../Graphics.h" -#include "../mapHandler.h" - -#include "../gui/CAnimation.h" -#include "../gui/CursorHandler.h" +#include "../renderSDL/SDL_Extensions.h" #include "../gui/CGuiHandler.h" -#include "../gui/SDL_Extensions.h" -#include "../widgets/MiscWidgets.h" +#include "../widgets/Images.h" #include "../../CCallback.h" - #include "../../lib/CConfigHandler.h" -#include "../../lib/CGameState.h" #include "../../lib/CGeneralTextHandler.h" -#include "../../lib/CHeroHandler.h" -#include "../../lib/CSoundBase.h" -#include "../../lib/spells/CSpellHandler.h" -#include "../../lib/CTownHandler.h" -#include "../../lib/JsonNode.h" -#include "../../lib/mapObjects/CGHeroInstance.h" -#include "../../lib/mapping/CMap.h" -#include "../../lib/UnlockGuard.h" -#include "../../lib/VCMI_Lib.h" -#include "../../lib/StartInfo.h" -#include "../../lib/mapping/CMapInfo.h" -#include "../../lib/TerrainHandler.h" - -#include -#include #define ADVOPT (conf.go()->ac) -using namespace CSDL_Ext; - -std::shared_ptr adventureInt; - -static void setScrollingCursor(ui8 direction) -{ - if(direction & CAdvMapInt::RIGHT) - { - if(direction & CAdvMapInt::UP) - CCS->curh->set(Cursor::Map::SCROLL_NORTHEAST); - else if(direction & CAdvMapInt::DOWN) - CCS->curh->set(Cursor::Map::SCROLL_SOUTHEAST); - else - CCS->curh->set(Cursor::Map::SCROLL_EAST); - } - else if(direction & CAdvMapInt::LEFT) - { - if(direction & CAdvMapInt::UP) - CCS->curh->set(Cursor::Map::SCROLL_NORTHWEST); - else if(direction & CAdvMapInt::DOWN) - CCS->curh->set(Cursor::Map::SCROLL_SOUTHWEST); - else - CCS->curh->set(Cursor::Map::SCROLL_WEST); - } - else if(direction & CAdvMapInt::UP) - CCS->curh->set(Cursor::Map::SCROLL_NORTH); - else if(direction & CAdvMapInt::DOWN) - CCS->curh->set(Cursor::Map::SCROLL_SOUTH); -} void CResDataBar::clickRight(tribool down, bool previousState) { @@ -156,7 +89,7 @@ void CResDataBar::draw(SDL_Surface * to) temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::WEEK))); temp.push_back(boost::lexical_cast(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK))); - graphics->fonts[FONT_SMALL]->renderTextLeft(to, processStr(datetext,temp), Colors::WHITE, Point(txtpos[7].first,txtpos[7].second)); + graphics->fonts[FONT_SMALL]->renderTextLeft(to, CSDL_Ext::processStr(datetext,temp), Colors::WHITE, Point(txtpos[7].first,txtpos[7].second)); } void CResDataBar::show(SDL_Surface * to) diff --git a/client/adventureMap/CResDataBar.h b/client/adventureMap/CResDataBar.h index d8a38967c..98598451e 100644 --- a/client/adventureMap/CResDataBar.h +++ b/client/adventureMap/CResDataBar.h @@ -9,32 +9,7 @@ */ #pragma once -#include "../widgets/AdventureMapClasses.h" -#include "CWindowObject.h" - -#include "../widgets/TextControls.h" -#include "../widgets/Buttons.h" - -#include "../../lib/spells/ViewSpellInt.h" - -VCMI_LIB_NAMESPACE_BEGIN - -struct CGPath; -struct CGPathNode; -class CGHeroInstance; -class CGTownInstance; -class CSpell; -class IShipyard; - -VCMI_LIB_NAMESPACE_END - -class CCallback; -class CAdvMapInt; -class CHeroWindow; -enum class EMapAnimRedrawStatus; -class CFadeAnimation; - -struct MapDrawingInfo; +#include "../gui/CIntObject.h" /// Resources bar which shows information about how many gold, crystals,... you have /// Current date is displayed too diff --git a/client/adventureMap/CTerrainRect.cpp b/client/adventureMap/CTerrainRect.cpp index c0ec1bc6b..1bf788967 100644 --- a/client/adventureMap/CTerrainRect.cpp +++ b/client/adventureMap/CTerrainRect.cpp @@ -8,86 +8,29 @@ * */ #include "StdInc.h" -#include "CAdvmapInterface.h" +#include "CTerrainRect.h" -#include "CCastleInterface.h" -#include "CHeroWindow.h" -#include "CKingdomInterface.h" -#include "CSpellWindow.h" -#include "CTradeWindow.h" -#include "GUIClasses.h" -#include "InfoWindows.h" +#include "mapHandler.h" +#include "CAdvMapInt.h" -#include "../CBitmapHandler.h" #include "../CGameInfo.h" -#include "../CMessage.h" -#include "../CMusicHandler.h" #include "../CPlayerInterface.h" -#include "../mainmenu/CMainMenu.h" -#include "../lobby/CSelectionBase.h" -#include "../lobby/CCampaignInfoScreen.h" -#include "../lobby/CSavingScreen.h" -#include "../lobby/CScenarioInfoScreen.h" -#include "../Graphics.h" -#include "../mapHandler.h" - -#include "../gui/CAnimation.h" #include "../gui/CursorHandler.h" #include "../gui/CGuiHandler.h" -#include "../gui/SDL_Extensions.h" -#include "../widgets/MiscWidgets.h" +#include "../render/CAnimation.h" +#include "../render/CFadeAnimation.h" +#include "../render/IImage.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../widgets/TextControls.h" #include "../../CCallback.h" - #include "../../lib/CConfigHandler.h" -#include "../../lib/CGameState.h" -#include "../../lib/CGeneralTextHandler.h" -#include "../../lib/CHeroHandler.h" -#include "../../lib/CSoundBase.h" -#include "../../lib/spells/CSpellHandler.h" -#include "../../lib/CTownHandler.h" -#include "../../lib/JsonNode.h" -#include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapping/CMap.h" -#include "../../lib/UnlockGuard.h" -#include "../../lib/VCMI_Lib.h" -#include "../../lib/StartInfo.h" -#include "../../lib/mapping/CMapInfo.h" -#include "../../lib/TerrainHandler.h" +#include "../../lib/CPathfinder.h" -#include #include #define ADVOPT (conf.go()->ac) -using namespace CSDL_Ext; - -std::shared_ptr adventureInt; - -static void setScrollingCursor(ui8 direction) -{ - if(direction & CAdvMapInt::RIGHT) - { - if(direction & CAdvMapInt::UP) - CCS->curh->set(Cursor::Map::SCROLL_NORTHEAST); - else if(direction & CAdvMapInt::DOWN) - CCS->curh->set(Cursor::Map::SCROLL_SOUTHEAST); - else - CCS->curh->set(Cursor::Map::SCROLL_EAST); - } - else if(direction & CAdvMapInt::LEFT) - { - if(direction & CAdvMapInt::UP) - CCS->curh->set(Cursor::Map::SCROLL_NORTHWEST); - else if(direction & CAdvMapInt::DOWN) - CCS->curh->set(Cursor::Map::SCROLL_SOUTHWEST); - else - CCS->curh->set(Cursor::Map::SCROLL_WEST); - } - else if(direction & CAdvMapInt::UP) - CCS->curh->set(Cursor::Map::SCROLL_NORTH); - else if(direction & CAdvMapInt::DOWN) - CCS->curh->set(Cursor::Map::SCROLL_SOUTH); -} CTerrainRect::CTerrainRect() : fadeSurface(nullptr), @@ -334,17 +277,17 @@ void CTerrainRect::showPath(const Rect & extRect, SDL_Surface * to) } else if(hvx<0) { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width(), 0, 0); + Rect srcRect = CSDL_Ext::genRect(arrow->height() - hvy, arrow->width(), 0, 0); arrow->draw(to, x + moveX, y + moveY, &srcRect); } else if (hvy<0) { - Rect srcRect = genRect(arrow->height(), arrow->width() - hvx, 0, 0); + Rect srcRect = CSDL_Ext::genRect(arrow->height(), arrow->width() - hvx, 0, 0); arrow->draw(to, x + moveX, y + moveY, &srcRect); } else { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); + Rect srcRect = CSDL_Ext::genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); arrow->draw(to, x + moveX, y + moveY, &srcRect); } } @@ -356,17 +299,17 @@ void CTerrainRect::showPath(const Rect & extRect, SDL_Surface * to) } else if(hvx<0) { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width(), 0, 0); + Rect srcRect = CSDL_Ext::genRect(arrow->height() - hvy, arrow->width(), 0, 0); arrow->draw(to, x, y, &srcRect); } else if (hvy<0) { - Rect srcRect = genRect(arrow->height(), arrow->width() - hvx, 0, 0); + Rect srcRect = CSDL_Ext::genRect(arrow->height(), arrow->width() - hvx, 0, 0); arrow->draw(to, x, y, &srcRect); } else { - Rect srcRect = genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); + Rect srcRect = CSDL_Ext::genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0); arrow->draw(to, x, y, &srcRect); } } diff --git a/client/adventureMap/CTerrainRect.h b/client/adventureMap/CTerrainRect.h index b439f44d1..4945f905f 100644 --- a/client/adventureMap/CTerrainRect.h +++ b/client/adventureMap/CTerrainRect.h @@ -9,33 +9,16 @@ */ #pragma once -#include "../widgets/AdventureMapClasses.h" -#include "CWindowObject.h" - -#include "../widgets/TextControls.h" -#include "../widgets/Buttons.h" - -#include "../../lib/spells/ViewSpellInt.h" +#include "../gui/CIntObject.h" +#include "../../lib/int3.h" VCMI_LIB_NAMESPACE_BEGIN - struct CGPath; -struct CGPathNode; -class CGHeroInstance; -class CGTownInstance; -class CSpell; -class IShipyard; - VCMI_LIB_NAMESPACE_END -class CCallback; -class CAdvMapInt; -class CHeroWindow; enum class EMapAnimRedrawStatus; class CFadeAnimation; -struct MapDrawingInfo; - /// Holds information about which tiles of the terrain are shown/not shown at the screen class CTerrainRect : public CIntObject { diff --git a/client/adventureMap/mapHandler.cpp b/client/adventureMap/mapHandler.cpp index 3c0c053f9..e4413ea99 100644 --- a/client/adventureMap/mapHandler.cpp +++ b/client/adventureMap/mapHandler.cpp @@ -11,30 +11,24 @@ #include "StdInc.h" #include "mapHandler.h" -#include "CBitmapHandler.h" -#include "gui/CAnimation.h" -#include "gui/SDL_Extensions.h" -#include "CGameInfo.h" -#include "../lib/mapObjects/CGHeroInstance.h" -#include "../lib/mapObjects/CObjectClassesHandler.h" -#include "../lib/CGameState.h" -#include "../lib/CHeroHandler.h" -#include "../lib/CTownHandler.h" -#include "../lib/CModHandler.h" -#include "Graphics.h" -#include "../lib/mapping/CMap.h" -#include "../lib/CConfigHandler.h" -#include "../lib/CGeneralTextHandler.h" -#include "../lib/GameConstants.h" -#include "../lib/CStopWatch.h" -#include "CMT.h" -#include "CMusicHandler.h" -#include "../lib/CRandomGenerator.h" -#include "../lib/RoadHandler.h" -#include "../lib/RiverHandler.h" -#include "../lib/TerrainHandler.h" -#include "../lib/filesystem/ResourceID.h" -#include "../lib/JsonDetail.h" +#include "../render/CAnimation.h" +#include "../render/CFadeAnimation.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../CGameInfo.h" +#include "../render/Graphics.h" +#include "../render/IImage.h" +#include "../CMusicHandler.h" + +#include "../../lib/mapObjects/CGHeroInstance.h" +#include "../../lib/mapObjects/CObjectClassesHandler.h" +#include "../../lib/mapping/CMap.h" +#include "../../lib/CConfigHandler.h" +#include "../../lib/CGeneralTextHandler.h" +#include "../../lib/CStopWatch.h" +#include "../../lib/CRandomGenerator.h" +#include "../../lib/RoadHandler.h" +#include "../../lib/RiverHandler.h" +#include "../../lib/TerrainHandler.h" #define ADVOPT (conf.go()->ac) diff --git a/client/adventureMap/mapHandler.h b/client/adventureMap/mapHandler.h index b1c2ff839..4b23e711b 100644 --- a/client/adventureMap/mapHandler.h +++ b/client/adventureMap/mapHandler.h @@ -10,9 +10,9 @@ #pragma once -#include "../lib/int3.h" -#include "../lib/spells/ViewSpellInt.h" -#include "../lib/Rect.h" +#include "../../lib/int3.h" +#include "../../lib/spells/ViewSpellInt.h" +#include "../../lib/Rect.h" #ifdef IN #undef IN diff --git a/client/battle/BattleEffectsController.cpp b/client/battle/BattleEffectsController.cpp index fddb27be0..9453673e2 100644 --- a/client/battle/BattleEffectsController.cpp +++ b/client/battle/BattleEffectsController.cpp @@ -21,8 +21,8 @@ #include "../CMusicHandler.h" #include "../CGameInfo.h" #include "../CPlayerInterface.h" -#include "../gui/CAnimation.h" -#include "../gui/Canvas.h" +#include "../render/Canvas.h" +#include "../render/CAnimation.h" #include "../../CCallback.h" #include "../../lib/battle/BattleAction.h" diff --git a/client/battle/BattleFieldController.cpp b/client/battle/BattleFieldController.cpp index 2f4d3bb12..46bd6aa5e 100644 --- a/client/battle/BattleFieldController.cpp +++ b/client/battle/BattleFieldController.cpp @@ -22,11 +22,11 @@ #include "../CGameInfo.h" #include "../CPlayerInterface.h" -#include "../widgets/AdventureMapClasses.h" -#include "../gui/CAnimation.h" -#include "../gui/Canvas.h" +#include "../render/Canvas.h" +#include "../render/IImage.h" #include "../gui/CGuiHandler.h" #include "../gui/CursorHandler.h" +#include "../adventureMap/CInGameConsole.h" #include "../../CCallback.h" #include "../../lib/BattleFieldHandler.h" diff --git a/client/battle/BattleInterface.cpp b/client/battle/BattleInterface.cpp index 6a6e435a4..e78df4e56 100644 --- a/client/battle/BattleInterface.cpp +++ b/client/battle/BattleInterface.cpp @@ -24,13 +24,12 @@ #include "BattleRenderer.h" #include "../CGameInfo.h" -#include "../CMessage.h" #include "../CMusicHandler.h" #include "../CPlayerInterface.h" -#include "../gui/Canvas.h" #include "../gui/CursorHandler.h" #include "../gui/CGuiHandler.h" -#include "../windows/CAdvmapInterface.h" +#include "../render/Canvas.h" +#include "../adventureMap/CAdvMapInt.h" #include "../../CCallback.h" #include "../../lib/CStack.h" diff --git a/client/battle/BattleInterfaceClasses.cpp b/client/battle/BattleInterfaceClasses.cpp index 69b5f54cd..7ee7707ff 100644 --- a/client/battle/BattleInterfaceClasses.cpp +++ b/client/battle/BattleInterfaceClasses.cpp @@ -19,21 +19,21 @@ #include "BattleWindow.h" #include "../CGameInfo.h" -#include "../CMessage.h" #include "../CMusicHandler.h" #include "../CPlayerInterface.h" #include "../CVideoHandler.h" -#include "../Graphics.h" -#include "../gui/CAnimation.h" -#include "../gui/Canvas.h" #include "../gui/CursorHandler.h" #include "../gui/CGuiHandler.h" -#include "../widgets/AdventureMapClasses.h" +#include "../render/Canvas.h" +#include "../render/IImage.h" #include "../widgets/Buttons.h" #include "../widgets/Images.h" #include "../widgets/TextControls.h" +#include "../windows/CMessage.h" #include "../windows/CCreatureWindow.h" #include "../windows/CSpellWindow.h" +#include "../render/CAnimation.h" +#include "../adventureMap/CInGameConsole.h" #include "../../CCallback.h" #include "../../lib/CStack.h" diff --git a/client/battle/BattleObstacleController.cpp b/client/battle/BattleObstacleController.cpp index ba2485d13..5e3eb2cd8 100644 --- a/client/battle/BattleObstacleController.cpp +++ b/client/battle/BattleObstacleController.cpp @@ -20,9 +20,8 @@ #include "../CMusicHandler.h" #include "../CGameInfo.h" #include "../CPlayerInterface.h" -#include "../gui/CAnimation.h" -#include "../gui/Canvas.h" #include "../gui/CGuiHandler.h" +#include "../render/Canvas.h" #include "../../CCallback.h" #include "../../lib/battle/CObstacleInstance.h" diff --git a/client/battle/BattleProjectileController.cpp b/client/battle/BattleProjectileController.cpp index c89e25e57..eb9d8b6fe 100644 --- a/client/battle/BattleProjectileController.cpp +++ b/client/battle/BattleProjectileController.cpp @@ -15,8 +15,7 @@ #include "BattleStacksController.h" #include "CreatureAnimation.h" -#include "../gui/CAnimation.h" -#include "../gui/Canvas.h" +#include "../render/Canvas.h" #include "../gui/CGuiHandler.h" #include "../CGameInfo.h" diff --git a/client/battle/BattleSiegeController.cpp b/client/battle/BattleSiegeController.cpp index 6d23c5ffd..602912807 100644 --- a/client/battle/BattleSiegeController.cpp +++ b/client/battle/BattleSiegeController.cpp @@ -20,8 +20,8 @@ #include "../CMusicHandler.h" #include "../CGameInfo.h" #include "../CPlayerInterface.h" -#include "../gui/CAnimation.h" -#include "../gui/Canvas.h" +#include "../render/Canvas.h" +#include "../render/IImage.h" #include "../../CCallback.h" #include "../../lib/NetPacks.h" diff --git a/client/battle/BattleStacksController.cpp b/client/battle/BattleStacksController.cpp index 369554ed1..8e3add970 100644 --- a/client/battle/BattleStacksController.cpp +++ b/client/battle/BattleStacksController.cpp @@ -25,13 +25,12 @@ #include "../CPlayerInterface.h" #include "../CMusicHandler.h" #include "../CGameInfo.h" -#include "../gui/CAnimation.h" #include "../gui/CGuiHandler.h" -#include "../gui/Canvas.h" -#include "../gui/SDL_Extensions.h" -#include "../../lib/spells/ISpellMechanics.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../render/Canvas.h" #include "../../CCallback.h" +#include "../../lib/spells/ISpellMechanics.h" #include "../../lib/battle/BattleHex.h" #include "../../lib/CGameState.h" #include "../../lib/CStack.h" diff --git a/client/battle/BattleStacksController.h b/client/battle/BattleStacksController.h index 92ffdaae0..7963c8c23 100644 --- a/client/battle/BattleStacksController.h +++ b/client/battle/BattleStacksController.h @@ -9,7 +9,7 @@ */ #pragma once -#include "../gui/ColorFilter.h" +#include "../render/ColorFilter.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/client/battle/BattleWindow.cpp b/client/battle/BattleWindow.cpp index 7c711ef8c..4279352bc 100644 --- a/client/battle/BattleWindow.cpp +++ b/client/battle/BattleWindow.cpp @@ -17,17 +17,17 @@ #include "BattleActionsController.h" #include "../CGameInfo.h" -#include "../CMessage.h" #include "../CPlayerInterface.h" #include "../CMusicHandler.h" -#include "../gui/Canvas.h" #include "../gui/CursorHandler.h" #include "../gui/CGuiHandler.h" -#include "../gui/CAnimation.h" #include "../windows/CSpellWindow.h" -#include "../widgets/AdventureMapClasses.h" #include "../widgets/Buttons.h" #include "../widgets/Images.h" +#include "../windows/CMessage.h" +#include "../render/CAnimation.h" +#include "../render/Canvas.h" +#include "../adventureMap/CInGameConsole.h" #include "../../CCallback.h" #include "../../lib/CGeneralTextHandler.h" diff --git a/client/battle/CreatureAnimation.cpp b/client/battle/CreatureAnimation.cpp index 4db83af3e..f6a827468 100644 --- a/client/battle/CreatureAnimation.cpp +++ b/client/battle/CreatureAnimation.cpp @@ -13,9 +13,9 @@ #include "../../lib/CConfigHandler.h" #include "../../lib/CCreatureHandler.h" -#include "../gui/Canvas.h" -#include "../gui/ColorFilter.h" -#include "../gui/SDL_Extensions.h" +#include "../render/Canvas.h" +#include "../render/ColorFilter.h" +#include "../renderSDL/SDL_Extensions.h" static const SDL_Color creatureBlueBorder = { 0, 255, 255, 255 }; static const SDL_Color creatureGoldBorder = { 255, 255, 0, 255 }; diff --git a/client/battle/CreatureAnimation.h b/client/battle/CreatureAnimation.h index e4c1a9d67..12eebef0d 100644 --- a/client/battle/CreatureAnimation.h +++ b/client/battle/CreatureAnimation.h @@ -11,7 +11,8 @@ #include "../../lib/FunctionList.h" #include "../widgets/Images.h" -#include "../gui/CAnimation.h" +#include "../render/CAnimation.h" +#include "../render/IImage.h" #include diff --git a/client/gui/CGuiHandler.cpp b/client/gui/CGuiHandler.cpp index 12bfe6ed0..ae9b0624f 100644 --- a/client/gui/CGuiHandler.cpp +++ b/client/gui/CGuiHandler.cpp @@ -13,15 +13,16 @@ #include "CIntObject.h" #include "CursorHandler.h" -#include "SDL_Extensions.h" #include "../CGameInfo.h" -#include "../../lib/CThreadHelper.h" -#include "../../lib/CConfigHandler.h" +#include "../renderSDL/SDL_Extensions.h" #include "../CMT.h" #include "../CPlayerInterface.h" #include "../battle/BattleInterface.h" +#include "../../lib/CThreadHelper.h" +#include "../../lib/CConfigHandler.h" + #include #include #include diff --git a/client/gui/CIntObject.cpp b/client/gui/CIntObject.cpp index 9a1c00794..334771b56 100644 --- a/client/gui/CIntObject.cpp +++ b/client/gui/CIntObject.cpp @@ -11,8 +11,8 @@ #include "CIntObject.h" #include "CGuiHandler.h" -#include "SDL_Extensions.h" -#include "../CMessage.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../windows/CMessage.h" #include #include diff --git a/client/gui/CIntObject.h b/client/gui/CIntObject.h index e4836c544..a61fe5d6f 100644 --- a/client/gui/CIntObject.h +++ b/client/gui/CIntObject.h @@ -10,7 +10,7 @@ #pragma once #include "../../lib/Rect.h" -#include "../Graphics.h" +#include "../render/Graphics.h" struct SDL_Surface; class CGuiHandler; diff --git a/client/gui/CursorHandler.cpp b/client/gui/CursorHandler.cpp index 4d1760f7a..2d9ba31db 100644 --- a/client/gui/CursorHandler.cpp +++ b/client/gui/CursorHandler.cpp @@ -11,9 +11,14 @@ #include "StdInc.h" #include "CursorHandler.h" -#include "SDL_Extensions.h" #include "CGuiHandler.h" -#include "CAnimation.h" +#include "../renderSDL/CursorSoftware.h" +#include "../renderSDL/CursorHardware.h" +#include "../render/CAnimation.h" +#include "../render/IImage.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../CMT.h" + #include "../../lib/CConfigHandler.h" #include diff --git a/client/gui/CursorHandler.h b/client/gui/CursorHandler.h index 807f90164..1b5cede0b 100644 --- a/client/gui/CursorHandler.h +++ b/client/gui/CursorHandler.h @@ -9,14 +9,12 @@ */ #pragma once -class CAnimation; -class IImage; -struct SDL_Surface; -struct SDL_Texture; -struct SDL_Cursor; - #include "../../lib/Point.h" +class ICursor; +class IImage; +class CAnimation; + namespace Cursor { enum class Type { diff --git a/client/gui/InterfaceObjectConfigurable.cpp b/client/gui/InterfaceObjectConfigurable.cpp index cb9b6854e..fd138dc8d 100644 --- a/client/gui/InterfaceObjectConfigurable.cpp +++ b/client/gui/InterfaceObjectConfigurable.cpp @@ -14,7 +14,6 @@ #include "../CGameInfo.h" #include "../CPlayerInterface.h" -#include "../gui/CAnimation.h" #include "../gui/CGuiHandler.h" #include "../widgets/CComponent.h" #include "../widgets/Buttons.h" diff --git a/client/lobby/CBonusSelection.cpp b/client/lobby/CBonusSelection.cpp index d3a6d7505..9bcf406ae 100644 --- a/client/lobby/CBonusSelection.cpp +++ b/client/lobby/CBonusSelection.cpp @@ -17,13 +17,10 @@ #include "CSelectionBase.h" #include "../CGameInfo.h" -#include "../CMessage.h" #include "../CMusicHandler.h" #include "../CVideoHandler.h" #include "../CPlayerInterface.h" #include "../CServerHandler.h" -#include "../gui/CAnimation.h" -#include "../gui/CGuiHandler.h" #include "../mainmenu/CMainMenu.h" #include "../mainmenu/CPrologEpilogVideo.h" #include "../widgets/CComponent.h" @@ -33,6 +30,9 @@ #include "../widgets/TextControls.h" #include "../windows/GUIClasses.h" #include "../windows/InfoWindows.h" +#include "../render/IImage.h" +#include "../render/CAnimation.h" +#include "../gui/CGuiHandler.h" #include "../../lib/filesystem/Filesystem.h" #include "../../lib/CGeneralTextHandler.h" diff --git a/client/lobby/CCampaignInfoScreen.cpp b/client/lobby/CCampaignInfoScreen.cpp index ce45bf45c..f84cb6101 100644 --- a/client/lobby/CCampaignInfoScreen.cpp +++ b/client/lobby/CCampaignInfoScreen.cpp @@ -15,10 +15,8 @@ #include "../../lib/CGeneralTextHandler.h" #include "../../lib/StartInfo.h" #include "../../lib/mapping/CMapInfo.h" -#include "../gui/CAnimation.h" #include "../gui/CGuiHandler.h" #include "../CGameInfo.h" -#include "../CMessage.h" #include "../CPlayerInterface.h" CCampaignInfoScreen::CCampaignInfoScreen() diff --git a/client/lobby/CSelectionBase.cpp b/client/lobby/CSelectionBase.cpp index b35598316..0cfb4a661 100644 --- a/client/lobby/CSelectionBase.cpp +++ b/client/lobby/CSelectionBase.cpp @@ -20,12 +20,10 @@ #include "../CGameInfo.h" #include "../CPlayerInterface.h" -#include "../CMessage.h" #include "../CMusicHandler.h" #include "../CVideoHandler.h" #include "../CPlayerInterface.h" #include "../CServerHandler.h" -#include "../gui/CAnimation.h" #include "../gui/CGuiHandler.h" #include "../mainmenu/CMainMenu.h" #include "../widgets/CComponent.h" @@ -35,6 +33,7 @@ #include "../widgets/TextControls.h" #include "../windows/GUIClasses.h" #include "../windows/InfoWindows.h" +#include "../render/CAnimation.h" #include "../../lib/NetPacksLobby.h" #include "../../lib/CGeneralTextHandler.h" diff --git a/client/lobby/OptionsTab.cpp b/client/lobby/OptionsTab.cpp index 199788093..31c8b4d28 100644 --- a/client/lobby/OptionsTab.cpp +++ b/client/lobby/OptionsTab.cpp @@ -14,7 +14,6 @@ #include "../CGameInfo.h" #include "../CServerHandler.h" -#include "../gui/CAnimation.h" #include "../gui/CGuiHandler.h" #include "../widgets/CComponent.h" #include "../widgets/Buttons.h" diff --git a/client/lobby/RandomMapTab.cpp b/client/lobby/RandomMapTab.cpp index bcefe0c23..285e9e355 100644 --- a/client/lobby/RandomMapTab.cpp +++ b/client/lobby/RandomMapTab.cpp @@ -14,7 +14,6 @@ #include "../CGameInfo.h" #include "../CServerHandler.h" -#include "../gui/CAnimation.h" #include "../gui/CGuiHandler.h" #include "../widgets/CComponent.h" #include "../widgets/Buttons.h" diff --git a/client/lobby/SelectionTab.cpp b/client/lobby/SelectionTab.cpp index f33d7413e..a280e7ed4 100644 --- a/client/lobby/SelectionTab.cpp +++ b/client/lobby/SelectionTab.cpp @@ -14,10 +14,8 @@ #include "CLobbyScreen.h" #include "../CGameInfo.h" -#include "../CMessage.h" #include "../CPlayerInterface.h" #include "../CServerHandler.h" -#include "../gui/CAnimation.h" #include "../gui/CGuiHandler.h" #include "../widgets/CComponent.h" #include "../widgets/Buttons.h" @@ -26,6 +24,7 @@ #include "../widgets/TextControls.h" #include "../windows/GUIClasses.h" #include "../windows/InfoWindows.h" +#include "../render/CAnimation.h" #include "../../CCallback.h" diff --git a/client/mainmenu/CCampaignScreen.cpp b/client/mainmenu/CCampaignScreen.cpp index 6cb1d500c..e89128b1e 100644 --- a/client/mainmenu/CCampaignScreen.cpp +++ b/client/mainmenu/CCampaignScreen.cpp @@ -14,12 +14,10 @@ #include "CMainMenu.h" #include "../CGameInfo.h" -#include "../CMessage.h" #include "../CMusicHandler.h" #include "../CVideoHandler.h" #include "../CPlayerInterface.h" #include "../CServerHandler.h" -#include "../gui/CAnimation.h" #include "../gui/CGuiHandler.h" #include "../widgets/CComponent.h" #include "../widgets/Buttons.h" diff --git a/client/mainmenu/CMainMenu.cpp b/client/mainmenu/CMainMenu.cpp index 88ec3e949..0ff17fe3c 100644 --- a/client/mainmenu/CMainMenu.cpp +++ b/client/mainmenu/CMainMenu.cpp @@ -20,7 +20,6 @@ #include "../../lib/filesystem/Filesystem.h" #include "../../lib/filesystem/CCompressedStream.h" -#include "../gui/SDL_Extensions.h" #include "../gui/CursorHandler.h" #include "../CGameInfo.h" @@ -28,7 +27,6 @@ #include "../../lib/JsonNode.h" #include "../CMusicHandler.h" #include "../CVideoHandler.h" -#include "../Graphics.h" #include "../../lib/serializer/Connection.h" #include "../../lib/serializer/CTypeList.h" #include "../../lib/VCMIDirs.h" @@ -36,10 +34,8 @@ #include "../windows/GUIClasses.h" #include "../CPlayerInterface.h" #include "../../CCallback.h" -#include "../CMessage.h" #include "../Client.h" #include "../gui/CGuiHandler.h" -#include "../gui/CAnimation.h" #include "../widgets/CComponent.h" #include "../widgets/Buttons.h" #include "../widgets/MiscWidgets.h" diff --git a/client/render/CAnimation.cpp b/client/render/CAnimation.cpp index 6fa584767..2f884fdff 100644 --- a/client/render/CAnimation.cpp +++ b/client/render/CAnimation.cpp @@ -10,19 +10,12 @@ #include "StdInc.h" #include "CAnimation.h" -#include "SDL_Extensions.h" -#include "ColorFilter.h" - -#include "../CBitmapHandler.h" -#include "../Graphics.h" +#include "CDefFile.h" +#include "Graphics.h" #include "../../lib/filesystem/Filesystem.h" -#include "../../lib/filesystem/ISimpleResourceLoader.h" #include "../../lib/JsonNode.h" -#include "../../lib/CRandomGenerator.h" -#include "../../lib/vcmi_endian.h" - -#include +#include "../renderSDL/SDLImage.h" std::shared_ptr CAnimation::getFromExtraDef(std::string filename) { diff --git a/client/render/CAnimation.h b/client/render/CAnimation.h index 88ff80415..7e26d13cd 100644 --- a/client/render/CAnimation.h +++ b/client/render/CAnimation.h @@ -11,26 +11,12 @@ #include "../../lib/GameConstants.h" -#ifdef IN -#undef IN -#endif - -#ifdef OUT -#undef OUT -#endif - VCMI_LIB_NAMESPACE_BEGIN - class JsonNode; -class Rect; -class Point; - VCMI_LIB_NAMESPACE_END -struct SDL_Surface; -struct SDL_Color; class CDefFile; -class ColorFilter; +class IImage; /// Class for handling animation class CAnimation diff --git a/client/render/CBitmapHandler.cpp b/client/render/CBitmapHandler.cpp index c13f2381f..1d096fe08 100644 --- a/client/render/CBitmapHandler.cpp +++ b/client/render/CBitmapHandler.cpp @@ -8,13 +8,15 @@ * */ #include "StdInc.h" +#include "CBitmapHandler.h" + +#include "../renderSDL/SDL_Extensions.h" #include "../lib/filesystem/Filesystem.h" -#include -#include "CBitmapHandler.h" -#include "gui/SDL_Extensions.h" #include "../lib/vcmi_endian.h" +#include + namespace BitmapHandler { SDL_Surface * loadH3PCX(ui8 * data, size_t size); diff --git a/client/render/CDefFile.cpp b/client/render/CDefFile.cpp index a88ab0aa5..190da28f6 100644 --- a/client/render/CDefFile.cpp +++ b/client/render/CDefFile.cpp @@ -7,22 +7,16 @@ * Full text of license available in license.txt file, in main folder * */ + #include "StdInc.h" -#include "CAnimation.h" +#include "CDefFile.h" -#include "SDL_Extensions.h" -#include "ColorFilter.h" - -#include "../CBitmapHandler.h" -#include "../Graphics.h" +#include "IImageLoader.h" #include "../../lib/filesystem/Filesystem.h" -#include "../../lib/filesystem/ISimpleResourceLoader.h" -#include "../../lib/JsonNode.h" -#include "../../lib/CRandomGenerator.h" -#include "../../lib/vcmi_endian.h" +#include "../../lib/Point.h" -#include +#include // Extremely simple file cache. TODO: smarter, more general solution class CFileCache @@ -203,8 +197,7 @@ CDefFile::CDefFile(std::string Name): } } -template -void CDefFile::loadFrame(size_t frame, size_t group, ImageLoader &loader) const +void CDefFile::loadFrame(size_t frame, size_t group, IImageLoader &loader) const { std::map >::const_iterator it; it = offset.find(group); @@ -250,9 +243,9 @@ void CDefFile::loadFrame(size_t frame, size_t group, ImageLoader &loader) const //pixel data is not compressed, copy data to surface for(ui32 i=0; i - void loadFrame(size_t frame, size_t group, ImageLoader &loader) const; + void loadFrame(size_t frame, size_t group, IImageLoader &loader) const; const std::map getEntries() const; }; diff --git a/client/render/CFadeAnimation.cpp b/client/render/CFadeAnimation.cpp index 04427b197..d2e5c9e10 100644 --- a/client/render/CFadeAnimation.cpp +++ b/client/render/CFadeAnimation.cpp @@ -8,19 +8,9 @@ * */ #include "StdInc.h" -#include "CAnimation.h" +#include "CFadeAnimation.h" -#include "SDL_Extensions.h" -#include "ColorFilter.h" - -#include "../CBitmapHandler.h" -#include "../Graphics.h" - -#include "../../lib/filesystem/Filesystem.h" -#include "../../lib/filesystem/ISimpleResourceLoader.h" -#include "../../lib/JsonNode.h" -#include "../../lib/CRandomGenerator.h" -#include "../../lib/vcmi_endian.h" +#include "../renderSDL/SDL_Extensions.h" #include diff --git a/client/render/CFadeAnimation.h b/client/render/CFadeAnimation.h index 76e95b313..b253ce828 100644 --- a/client/render/CFadeAnimation.h +++ b/client/render/CFadeAnimation.h @@ -9,8 +9,6 @@ */ #pragma once -#include "../../lib/GameConstants.h" - #ifdef IN #undef IN #endif @@ -20,17 +18,10 @@ #endif VCMI_LIB_NAMESPACE_BEGIN - -class JsonNode; -class Rect; class Point; - VCMI_LIB_NAMESPACE_END struct SDL_Surface; -struct SDL_Color; -class CDefFile; -class ColorFilter; const float DEFAULT_DELTA = 0.05f; diff --git a/client/render/Canvas.cpp b/client/render/Canvas.cpp index 95d2f555c..82ccd447f 100644 --- a/client/render/Canvas.cpp +++ b/client/render/Canvas.cpp @@ -10,10 +10,9 @@ #include "StdInc.h" #include "Canvas.h" -#include "SDL_Extensions.h" -#include "CAnimation.h" - -#include "../Graphics.h" +#include "../renderSDL/SDL_Extensions.h" +#include "IImage.h" +#include "Graphics.h" #include diff --git a/client/render/Canvas.h b/client/render/Canvas.h index 39a4df9fa..73f795f2c 100644 --- a/client/render/Canvas.h +++ b/client/render/Canvas.h @@ -9,7 +9,7 @@ */ #pragma once -#include "TextAlignment.h" +#include "../gui/TextAlignment.h" #include "../../lib/Rect.h" #include "../../lib/Color.h" diff --git a/client/render/Graphics.cpp b/client/render/Graphics.cpp index 54c9baf2a..527a5f70a 100644 --- a/client/render/Graphics.cpp +++ b/client/render/Graphics.cpp @@ -18,11 +18,15 @@ #include #include +#include "../renderSDL/SDL_Extensions.h" +#include "../renderSDL/CBitmapFont.h" +#include "../renderSDL/CBitmapHanFont.h" +#include "../renderSDL/CTrueTypeFont.h" +#include "../render/CAnimation.h" +#include "../render/IImage.h" + #include "../lib/filesystem/Filesystem.h" #include "../lib/filesystem/CBinaryReader.h" -#include "gui/SDL_Extensions.h" -#include "gui/CAnimation.h" -#include "../lib/CThreadHelper.h" #include "../lib/CModHandler.h" #include "CGameInfo.h" #include "../lib/VCMI_Lib.h" diff --git a/client/render/Graphics.h b/client/render/Graphics.h index 0b539d396..83b3bc198 100644 --- a/client/render/Graphics.h +++ b/client/render/Graphics.h @@ -9,7 +9,7 @@ */ #pragma once -#include "gui/Fonts.h" +#include "IFont.h" #include "../lib/GameConstants.h" VCMI_LIB_NAMESPACE_BEGIN @@ -22,6 +22,7 @@ struct InfoAboutTown; class CGObjectInstance; class ObjectTemplate; class EntityService; +class JsonNode; VCMI_LIB_NAMESPACE_END diff --git a/client/render/ICursor.h b/client/render/ICursor.h index 8abbbbef5..6d37b3e37 100644 --- a/client/render/ICursor.h +++ b/client/render/ICursor.h @@ -9,13 +9,11 @@ */ #pragma once -class CAnimation; -class IImage; -struct SDL_Surface; -struct SDL_Texture; -struct SDL_Cursor; +VCMI_LIB_NAMESPACE_BEGIN +class Point; +VCMI_LIB_NAMESPACE_END -#include "../../lib/Point.h" +class IImage; class ICursor { diff --git a/client/render/IFont.cpp b/client/render/IFont.cpp index bea94c076..0086cd9ee 100644 --- a/client/render/IFont.cpp +++ b/client/render/IFont.cpp @@ -7,16 +7,13 @@ * Full text of license available in license.txt file, in main folder * */ + #include "StdInc.h" -#include "Fonts.h" +#include "IFont.h" -#include - -#include "SDL_Extensions.h" -#include "../../lib/JsonNode.h" -#include "../../lib/vcmi_endian.h" -#include "../../lib/filesystem/Filesystem.h" +#include "../../lib/Point.h" #include "../../lib/CGeneralTextHandler.h" +// size_t IFont::getStringWidth(const std::string & data) const { diff --git a/client/render/IFont.h b/client/render/IFont.h index bc87fea28..933b85db5 100644 --- a/client/render/IFont.h +++ b/client/render/IFont.h @@ -11,7 +11,6 @@ VCMI_LIB_NAMESPACE_BEGIN -class JsonNode; class Point; VCMI_LIB_NAMESPACE_END @@ -19,11 +18,6 @@ VCMI_LIB_NAMESPACE_END struct SDL_Surface; struct SDL_Color; -typedef struct _TTF_Font TTF_Font; - -class CBitmapFont; -class CBitmapHanFont; - class IFont { protected: diff --git a/client/render/IImage.h b/client/render/IImage.h index 06691db52..64cdfffec 100644 --- a/client/render/IImage.h +++ b/client/render/IImage.h @@ -9,19 +9,9 @@ */ #pragma once -#include "../../lib/GameConstants.h" - -#ifdef IN -#undef IN -#endif - -#ifdef OUT -#undef OUT -#endif - VCMI_LIB_NAMESPACE_BEGIN -class JsonNode; +class PlayerColor; class Rect; class Point; @@ -29,7 +19,6 @@ VCMI_LIB_NAMESPACE_END struct SDL_Surface; struct SDL_Color; -class CDefFile; class ColorFilter; /* diff --git a/client/render/IImageLoader.h b/client/render/IImageLoader.h new file mode 100644 index 000000000..fd3a72045 --- /dev/null +++ b/client/render/IImageLoader.h @@ -0,0 +1,31 @@ +/* + * IImageLoader.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#pragma once + +class SDLImage; +class Point; + +struct SDL_Color; + +class IImageLoader +{ +public: + //load size raw pixels from data + virtual void load(size_t size, const ui8 * data) = 0; + //set size pixels to color + virtual void load(size_t size, ui8 color=0) = 0; + + virtual void endLine() = 0; + //init image with these sizes and palette + virtual void init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal) = 0; + + virtual ~IImageLoader() = default; +}; diff --git a/client/renderSDL/CBitmapFont.cpp b/client/renderSDL/CBitmapFont.cpp index ce600e2bd..f2eb49d00 100644 --- a/client/renderSDL/CBitmapFont.cpp +++ b/client/renderSDL/CBitmapFont.cpp @@ -8,15 +8,16 @@ * */ #include "StdInc.h" -#include "Fonts.h" - -#include +#include "CBitmapFont.h" #include "SDL_Extensions.h" -#include "../../lib/JsonNode.h" + #include "../../lib/vcmi_endian.h" #include "../../lib/filesystem/Filesystem.h" #include "../../lib/CGeneralTextHandler.h" +#include "../../lib/Rect.h" + +#include std::array CBitmapFont::loadChars() const { diff --git a/client/renderSDL/CBitmapFont.h b/client/renderSDL/CBitmapFont.h index 3f1012113..8da10b4d4 100644 --- a/client/renderSDL/CBitmapFont.h +++ b/client/renderSDL/CBitmapFont.h @@ -9,20 +9,7 @@ */ #pragma once -VCMI_LIB_NAMESPACE_BEGIN - -class JsonNode; -class Point; - -VCMI_LIB_NAMESPACE_END - -struct SDL_Surface; -struct SDL_Color; - -typedef struct _TTF_Font TTF_Font; - -class CBitmapFont; -class CBitmapHanFont; +#include "../render/IFont.h" class CBitmapFont : public IFont { diff --git a/client/renderSDL/CBitmapHanFont.cpp b/client/renderSDL/CBitmapHanFont.cpp index 303299cab..bcaa94d59 100644 --- a/client/renderSDL/CBitmapHanFont.cpp +++ b/client/renderSDL/CBitmapHanFont.cpp @@ -8,15 +8,17 @@ * */ #include "StdInc.h" -#include "Fonts.h" - -#include +#include "CBitmapHanFont.h" +#include "CBitmapFont.h" #include "SDL_Extensions.h" + #include "../../lib/JsonNode.h" -#include "../../lib/vcmi_endian.h" #include "../../lib/filesystem/Filesystem.h" #include "../../lib/CGeneralTextHandler.h" +#include "../../lib/Rect.h" + +#include size_t CBitmapHanFont::getCharacterDataOffset(size_t index) const { diff --git a/client/renderSDL/CBitmapHanFont.h b/client/renderSDL/CBitmapHanFont.h index ea61a42b5..32b7e081f 100644 --- a/client/renderSDL/CBitmapHanFont.h +++ b/client/renderSDL/CBitmapHanFont.h @@ -9,20 +9,13 @@ */ #pragma once +#include "../render/IFont.h" + VCMI_LIB_NAMESPACE_BEGIN - class JsonNode; -class Point; - VCMI_LIB_NAMESPACE_END -struct SDL_Surface; -struct SDL_Color; - -typedef struct _TTF_Font TTF_Font; - class CBitmapFont; -class CBitmapHanFont; /// supports multi-byte characters for such languages like Chinese class CBitmapHanFont : public IFont @@ -45,23 +38,3 @@ public: size_t getLineHeight() const override; size_t getGlyphWidth(const char * data) const override; }; - -class CTrueTypeFont : public IFont -{ - const std::pair, ui64> data; - - const std::unique_ptr font; - const bool blended; - - std::pair, ui64> loadData(const JsonNode & config); - TTF_Font * loadFont(const JsonNode & config); - int getFontStyle(const JsonNode & config); - - void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const override; -public: - CTrueTypeFont(const JsonNode & fontConfig); - - size_t getLineHeight() const override; - size_t getGlyphWidth(const char * data) const override; - size_t getStringWidth(const std::string & data) const override; -}; diff --git a/client/renderSDL/CTrueTypeFont.cpp b/client/renderSDL/CTrueTypeFont.cpp index 98df180c7..4788e4636 100644 --- a/client/renderSDL/CTrueTypeFont.cpp +++ b/client/renderSDL/CTrueTypeFont.cpp @@ -8,15 +8,21 @@ * */ #include "StdInc.h" -#include "Fonts.h" +#include "CTrueTypeFont.h" + +#include "SDL_Extensions.h" + +#include "../../lib/JsonNode.h" +#include "../../lib/CGeneralTextHandler.h" +#include "../../lib/filesystem/Filesystem.h" #include -#include "SDL_Extensions.h" -#include "../../lib/JsonNode.h" -#include "../../lib/vcmi_endian.h" -#include "../../lib/filesystem/Filesystem.h" -#include "../../lib/CGeneralTextHandler.h" +std::pair, ui64> CTrueTypeFont::loadData(const JsonNode & config) +{ + std::string filename = "Data/" + config["file"].String(); + return CResourceHandler::get()->load(ResourceID(filename, EResType::TTF_FONT))->readAll(); +} TTF_Font * CTrueTypeFont::loadFont(const JsonNode &config) { diff --git a/client/renderSDL/CTrueTypeFont.h b/client/renderSDL/CTrueTypeFont.h index 6e65645b8..eb834b40c 100644 --- a/client/renderSDL/CTrueTypeFont.h +++ b/client/renderSDL/CTrueTypeFont.h @@ -9,21 +9,14 @@ */ #pragma once +#include "../render/IFont.h" + VCMI_LIB_NAMESPACE_BEGIN - class JsonNode; -class Point; - VCMI_LIB_NAMESPACE_END -struct SDL_Surface; -struct SDL_Color; - typedef struct _TTF_Font TTF_Font; -class CBitmapFont; -class CBitmapHanFont; - class CTrueTypeFont : public IFont { const std::pair, ui64> data; diff --git a/client/renderSDL/CursorHardware.cpp b/client/renderSDL/CursorHardware.cpp index d72a75d28..a2c7e728e 100644 --- a/client/renderSDL/CursorHardware.cpp +++ b/client/renderSDL/CursorHardware.cpp @@ -9,12 +9,10 @@ */ #include "StdInc.h" -#include "CursorHandler.h" +#include "CursorHardware.h" #include "SDL_Extensions.h" -#include "CGuiHandler.h" -#include "CAnimation.h" -#include "../../lib/CConfigHandler.h" +#include "../render/IImage.h" #include #include diff --git a/client/renderSDL/CursorHardware.h b/client/renderSDL/CursorHardware.h index 41048dcbb..8f0aa2f19 100644 --- a/client/renderSDL/CursorHardware.h +++ b/client/renderSDL/CursorHardware.h @@ -16,6 +16,7 @@ struct SDL_Texture; struct SDL_Cursor; #include "../../lib/Point.h" +#include "../render/ICursor.h" class CursorHardware : public ICursor { diff --git a/client/renderSDL/CursorSoftware.cpp b/client/renderSDL/CursorSoftware.cpp index b2b8019d2..a143b7d98 100644 --- a/client/renderSDL/CursorSoftware.cpp +++ b/client/renderSDL/CursorSoftware.cpp @@ -9,20 +9,15 @@ */ #include "StdInc.h" -#include "CursorHandler.h" +#include "CursorSoftware.h" #include "SDL_Extensions.h" -#include "CGuiHandler.h" -#include "CAnimation.h" -#include "../../lib/CConfigHandler.h" + +#include "../render/IImage.h" #include #include -#ifdef VCMI_APPLE -#include -#endif - void CursorSoftware::render() { //texture must be updated in the main (renderer) thread, but changes to cursor type may come from other threads diff --git a/client/renderSDL/CursorSoftware.h b/client/renderSDL/CursorSoftware.h index cc450844e..f33add2f6 100644 --- a/client/renderSDL/CursorSoftware.h +++ b/client/renderSDL/CursorSoftware.h @@ -16,6 +16,7 @@ struct SDL_Texture; struct SDL_Cursor; #include "../../lib/Point.h" +#include "../render/ICursor.h" class CursorSoftware : public ICursor { diff --git a/client/renderSDL/SDLImage.cpp b/client/renderSDL/SDLImage.cpp index 55c014c61..386058026 100644 --- a/client/renderSDL/SDLImage.cpp +++ b/client/renderSDL/SDLImage.cpp @@ -8,19 +8,17 @@ * */ #include "StdInc.h" -#include "CAnimation.h" +#include "SDLImage.h" +#include "SDLImageLoader.h" #include "SDL_Extensions.h" -#include "ColorFilter.h" -#include "../CBitmapHandler.h" -#include "../Graphics.h" +#include "../render/ColorFilter.h" +#include "../render/CBitmapHandler.h" +#include "../render/CDefFile.h" +#include "../render/Graphics.h" -#include "../../lib/filesystem/Filesystem.h" -#include "../../lib/filesystem/ISimpleResourceLoader.h" #include "../../lib/JsonNode.h" -#include "../../lib/CRandomGenerator.h" -#include "../../lib/vcmi_endian.h" #include diff --git a/client/renderSDL/SDLImage.h b/client/renderSDL/SDLImage.h index 850004b51..86f14e48d 100644 --- a/client/renderSDL/SDLImage.h +++ b/client/renderSDL/SDLImage.h @@ -9,28 +9,17 @@ */ #pragma once -#include "../../lib/GameConstants.h" - -#ifdef IN -#undef IN -#endif - -#ifdef OUT -#undef OUT -#endif +#include "../render/IImage.h" +#include "../../lib/Point.h" VCMI_LIB_NAMESPACE_BEGIN - class JsonNode; -class Rect; -class Point; - VCMI_LIB_NAMESPACE_END -struct SDL_Surface; -struct SDL_Color; class CDefFile; -class ColorFilter; + +struct SDL_Surface; +struct SDL_Palette; /* * Wrapper around SDL_Surface diff --git a/client/renderSDL/SDLImageLoader.cpp b/client/renderSDL/SDLImageLoader.cpp index 1dfbb8e16..c951dcc2d 100644 --- a/client/renderSDL/SDLImageLoader.cpp +++ b/client/renderSDL/SDLImageLoader.cpp @@ -7,27 +7,16 @@ * Full text of license available in license.txt file, in main folder * */ + #include "StdInc.h" -#include "CAnimation.h" +#include "SDLImageLoader.h" -#include "SDL_Extensions.h" -#include "ColorFilter.h" +#include "SDLImage.h" -#include "../CBitmapHandler.h" -#include "../Graphics.h" - -#include "../../lib/filesystem/Filesystem.h" -#include "../../lib/filesystem/ISimpleResourceLoader.h" -#include "../../lib/JsonNode.h" -#include "../../lib/CRandomGenerator.h" -#include "../../lib/vcmi_endian.h" +#include "../../lib/Point.h" #include -/************************************************************************* - * Classes for image loaders - helpers for loading from def files * - *************************************************************************/ - SDLImageLoader::SDLImageLoader(SDLImage * Img): image(Img), lineStart(nullptr), @@ -52,7 +41,7 @@ void SDLImageLoader::init(Point SpriteSize, Point Margins, Point FullSize, SDL_C lineStart = position = (ui8*)image->surf->pixels; } -inline void SDLImageLoader::Load(size_t size, const ui8 * data) +inline void SDLImageLoader::load(size_t size, const ui8 * data) { if (size) { @@ -61,7 +50,7 @@ inline void SDLImageLoader::Load(size_t size, const ui8 * data) } } -inline void SDLImageLoader::Load(size_t size, ui8 color) +inline void SDLImageLoader::load(size_t size, ui8 color) { if (size) { @@ -70,7 +59,7 @@ inline void SDLImageLoader::Load(size_t size, ui8 color) } } -inline void SDLImageLoader::EndLine() +inline void SDLImageLoader::endLine() { lineStart += image->surf->pitch; position = lineStart; diff --git a/client/renderSDL/SDLImageLoader.h b/client/renderSDL/SDLImageLoader.h index 15247b581..5a5b6e97f 100644 --- a/client/renderSDL/SDLImageLoader.h +++ b/client/renderSDL/SDLImageLoader.h @@ -9,43 +9,21 @@ */ #pragma once -#include "../../lib/GameConstants.h" +#include "../render/IImageLoader.h" -#ifdef IN -#undef IN -#endif - -#ifdef OUT -#undef OUT -#endif - -VCMI_LIB_NAMESPACE_BEGIN - -class JsonNode; -class Rect; -class Point; - -VCMI_LIB_NAMESPACE_END - -struct SDL_Surface; -struct SDL_Color; -class CDefFile; -class ColorFilter; - - -class SDLImageLoader +class SDLImageLoader : public IImageLoader { SDLImage * image; ui8 * lineStart; ui8 * position; public: //load size raw pixels from data - inline void Load(size_t size, const ui8 * data); + void load(size_t size, const ui8 * data); //set size pixels to color - inline void Load(size_t size, ui8 color=0); - inline void EndLine(); + void load(size_t size, ui8 color=0); + void endLine(); //init image with these sizes and palette - inline void init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal); + void init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal); SDLImageLoader(SDLImage * Img); ~SDLImageLoader(); diff --git a/client/renderSDL/SDLRWwrapper.cpp b/client/renderSDL/SDLRWwrapper.cpp index 6e1a98b7a..379d94de5 100644 --- a/client/renderSDL/SDLRWwrapper.cpp +++ b/client/renderSDL/SDLRWwrapper.cpp @@ -10,7 +10,9 @@ #include "StdInc.h" #include "SDLRWwrapper.h" -#include "../lib/filesystem/CInputStream.h" + +#include "../../lib/filesystem/CInputStream.h" + #include static inline CInputStream* get_stream(SDL_RWops* context) diff --git a/client/renderSDL/SDL_Extensions.cpp b/client/renderSDL/SDL_Extensions.cpp index b4403a477..2e66eb4bd 100644 --- a/client/renderSDL/SDL_Extensions.cpp +++ b/client/renderSDL/SDL_Extensions.cpp @@ -9,25 +9,26 @@ */ #include "StdInc.h" #include "SDL_Extensions.h" + #include "SDL_PixelAccess.h" - -#include "../CGameInfo.h" -#include "../CMessage.h" -#include "../Graphics.h" -#include "../CMT.h" - -#include +// +//#include "../CGameInfo.h" +//#include "../CMessage.h" +#include "../render/Graphics.h" +//#include "../CMT.h" +// +//#include #include #include #include - -#ifdef VCMI_APPLE -#include -#endif - -#ifdef VCMI_IOS -#include "ios/utils.h" -#endif +// +//#ifdef VCMI_APPLE +//#include +//#endif +// +//#ifdef VCMI_IOS +//#include "ios/utils.h" +//#endif const SDL_Color Colors::YELLOW = { 229, 215, 123, SDL_ALPHA_OPAQUE }; const SDL_Color Colors::WHITE = { 255, 243, 222, SDL_ALPHA_OPAQUE }; diff --git a/client/widgets/Buttons.cpp b/client/widgets/Buttons.cpp index 30965e53d..514d62cea 100644 --- a/client/widgets/Buttons.cpp +++ b/client/widgets/Buttons.cpp @@ -18,9 +18,10 @@ #include "../CPlayerInterface.h" #include "../battle/BattleInterface.h" #include "../battle/BattleInterfaceClasses.h" -#include "../gui/CAnimation.h" #include "../gui/CGuiHandler.h" #include "../windows/InfoWindows.h" +#include "../render/CAnimation.h" + #include "../../lib/CConfigHandler.h" #include "../../lib/CGeneralTextHandler.h" diff --git a/client/widgets/Buttons.h b/client/widgets/Buttons.h index 74e6ad690..33f0533ce 100644 --- a/client/widgets/Buttons.h +++ b/client/widgets/Buttons.h @@ -10,7 +10,7 @@ #pragma once #include "../gui/CIntObject.h" -#include "../gui/SDL_Extensions.h" +#include "../renderSDL/SDL_Extensions.h" #include "../../lib/FunctionList.h" #include diff --git a/client/widgets/CComponent.cpp b/client/widgets/CComponent.cpp index 5017781ed..05f316b25 100644 --- a/client/widgets/CComponent.cpp +++ b/client/widgets/CComponent.cpp @@ -18,18 +18,20 @@ #include "../gui/CGuiHandler.h" #include "../gui/CursorHandler.h" - -#include "../CMessage.h" +#include "../gui/TextAlignment.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../adventureMap/CAdvMapInt.h" +#include "../windows/CMessage.h" +#include "../widgets/TextControls.h" #include "../CGameInfo.h" -#include "../windows/CAdvmapInterface.h" -#include "../../lib/CArtHandler.h" #include "../../lib/CTownHandler.h" #include "../../lib/spells/CSpellHandler.h" #include "../../lib/CCreatureHandler.h" #include "../../lib/CSkillHandler.h" #include "../../lib/CGeneralTextHandler.h" #include "../../lib/NetPacksBase.h" +#include "../../lib/CArtHandler.h" CComponent::CComponent(Etype Type, int Subtype, int Val, ESize imageSize) : perDay(false) diff --git a/client/widgets/CreatureCostBox.h b/client/widgets/CreatureCostBox.h index 908b74508..338101ebc 100644 --- a/client/widgets/CreatureCostBox.h +++ b/client/widgets/CreatureCostBox.h @@ -9,8 +9,8 @@ */ #pragma once -#include "../lib/ResourceSet.h" -#include "gui/CIntObject.h" +#include "../../lib/ResourceSet.h" +#include "../gui/CIntObject.h" class CLabel; class CAnimImage; diff --git a/client/widgets/Images.cpp b/client/widgets/Images.cpp index 56ed3b65d..61017edf9 100644 --- a/client/widgets/Images.cpp +++ b/client/widgets/Images.cpp @@ -12,21 +12,17 @@ #include "MiscWidgets.h" -#include "../gui/CAnimation.h" #include "../gui/CGuiHandler.h" -#include "../gui/CursorHandler.h" -#include "../gui/ColorFilter.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../render/IImage.h" +#include "../render/CAnimation.h" #include "../battle/BattleInterface.h" #include "../battle/BattleInterfaceClasses.h" -#include "../CBitmapHandler.h" -#include "../Graphics.h" #include "../CGameInfo.h" #include "../CPlayerInterface.h" -#include "../CMessage.h" #include "../CMusicHandler.h" -#include "../windows/CAdvmapInterface.h" #include "../../CCallback.h" diff --git a/client/widgets/MiscWidgets.cpp b/client/widgets/MiscWidgets.cpp index 7dcbe272f..e82109ce3 100644 --- a/client/widgets/MiscWidgets.cpp +++ b/client/widgets/MiscWidgets.cpp @@ -16,11 +16,12 @@ #include "../gui/CursorHandler.h" #include "../CPlayerInterface.h" -#include "../CMessage.h" #include "../CGameInfo.h" -#include "../windows/CAdvmapInterface.h" +#include "../widgets/TextControls.h" #include "../windows/CCastleInterface.h" #include "../windows/InfoWindows.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../adventureMap/CAdvMapInt.h" #include "../../CCallback.h" diff --git a/client/widgets/TextControls.cpp b/client/widgets/TextControls.cpp index bb3ad318e..ecff24ca7 100644 --- a/client/widgets/TextControls.cpp +++ b/client/widgets/TextControls.cpp @@ -13,12 +13,11 @@ #include "Buttons.h" #include "Images.h" -#include "../CMessage.h" #include "../CPlayerInterface.h" #include "../gui/CGuiHandler.h" -#include "../widgets/AdventureMapClasses.h" - -#include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff +#include "../windows/CMessage.h" +#include "../adventureMap/CInGameConsole.h" +#include "../../lib/CGeneralTextHandler.h" #ifdef VCMI_ANDROID #include "lib/CAndroidVMHelper.h" @@ -26,6 +25,9 @@ #include +std::list CFocusable::focusables; +CFocusable * CFocusable::inputWithFocus; + std::string CLabel::visibleText() { return text; diff --git a/client/widgets/TextControls.h b/client/widgets/TextControls.h index d1a5b3e67..a5f7cab4b 100644 --- a/client/widgets/TextControls.h +++ b/client/widgets/TextControls.h @@ -11,7 +11,8 @@ #include "../gui/CIntObject.h" #include "../gui/TextAlignment.h" -#include "../gui/SDL_Extensions.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../render/Graphics.h" #include "../../lib/FunctionList.h" #include diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index fc6e41ec7..9de836afb 100644 --- a/client/windows/CCastleInterface.cpp +++ b/client/windows/CCastleInterface.cpp @@ -10,25 +10,24 @@ #include "StdInc.h" #include "CCastleInterface.h" -#include "CAdvmapInterface.h" #include "CHeroWindow.h" #include "CTradeWindow.h" #include "InfoWindows.h" #include "GUIClasses.h" #include "QuickRecruitmentWindow.h" -#include "../CBitmapHandler.h" #include "../CGameInfo.h" -#include "../CMessage.h" #include "../CMusicHandler.h" #include "../CPlayerInterface.h" -#include "../Graphics.h" #include "../gui/CGuiHandler.h" -#include "../gui/CAnimation.h" -#include "../gui/ColorFilter.h" -#include "../gui/SDL_Extensions.h" #include "../widgets/MiscWidgets.h" #include "../widgets/CComponent.h" +#include "../widgets/Buttons.h" +#include "../widgets/TextControls.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../render/IImage.h" +#include "../render/ColorFilter.h" +#include "../adventureMap/CAdvMapInt.h" #include "../../CCallback.h" #include "../../lib/CArtHandler.h" diff --git a/client/windows/CHeroWindow.cpp b/client/windows/CHeroWindow.cpp index afc4ed853..1b37d9ede 100644 --- a/client/windows/CHeroWindow.cpp +++ b/client/windows/CHeroWindow.cpp @@ -10,22 +10,22 @@ #include "StdInc.h" #include "CHeroWindow.h" -#include "CAdvmapInterface.h" #include "CCreatureWindow.h" #include "CKingdomInterface.h" #include "GUIClasses.h" #include "../CGameInfo.h" -#include "../CMessage.h" #include "../CMT.h" #include "../CPlayerInterface.h" -#include "../Graphics.h" -#include "../gui/SDL_Extensions.h" #include "../gui/CGuiHandler.h" -#include "../gui/CAnimation.h" +#include "../gui/TextAlignment.h" #include "../widgets/MiscWidgets.h" #include "../widgets/CComponent.h" +#include "../widgets/TextControls.h" +#include "../widgets/Buttons.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../render/CAnimation.h" #include "../../CCallback.h" @@ -36,8 +36,6 @@ #include "../lib/CSkillHandler.h" #include "../lib/mapObjects/CGHeroInstance.h" #include "../lib/NetPacksBase.h" -#include "../mapHandler.h" - TConstBonusListPtr CHeroWithMaybePickedArtifact::getAllBonuses(const CSelector & selector, const CSelector & limit, const CBonusSystemNode * root, const std::string & cachingStr) const { diff --git a/client/windows/CKingdomInterface.cpp b/client/windows/CKingdomInterface.cpp index 9511a3cc6..6da92c6d0 100644 --- a/client/windows/CKingdomInterface.cpp +++ b/client/windows/CKingdomInterface.cpp @@ -10,7 +10,6 @@ #include "StdInc.h" #include "CKingdomInterface.h" -#include "CAdvmapInterface.h" #include "CCastleInterface.h" #include "InfoWindows.h" @@ -19,7 +18,11 @@ #include "../CPlayerInterface.h" #include "../gui/CGuiHandler.h" #include "../widgets/CComponent.h" +#include "../widgets/TextControls.h" #include "../widgets/MiscWidgets.h" +#include "../widgets/Buttons.h" +#include "../adventureMap/CAdvMapInt.h" +#include "../renderSDL/SDL_Extensions.h" #include "../../CCallback.h" diff --git a/client/windows/CMessage.cpp b/client/windows/CMessage.cpp index 9559045be..abb9fe26b 100644 --- a/client/windows/CMessage.cpp +++ b/client/windows/CMessage.cpp @@ -11,16 +11,15 @@ #include "StdInc.h" #include "CMessage.h" -#include "CGameInfo.h" -#include "gui/SDL_Extensions.h" -#include "../lib/CGeneralTextHandler.h" -#include "CBitmapHandler.h" -#include "gui/CAnimation.h" +#include "../CGameInfo.h" +#include "../../lib/CGeneralTextHandler.h" -#include "widgets/CComponent.h" -#include "windows/InfoWindows.h" -#include "widgets/Buttons.h" -#include "widgets/TextControls.h" +#include "../windows/InfoWindows.h" +#include "../widgets/Buttons.h" +#include "../widgets/CComponent.h" +#include "../widgets/TextControls.h" +#include "../render/CAnimation.h" +#include "../render/IImage.h" #include diff --git a/client/windows/CMessage.h b/client/windows/CMessage.h index 8eac68881..f41c5d01a 100644 --- a/client/windows/CMessage.h +++ b/client/windows/CMessage.h @@ -9,12 +9,14 @@ */ #pragma once -#include "Graphics.h" +#include "../render/Graphics.h" +#include "../../lib/GameConstants.h" struct SDL_Surface; class CInfoWindow; class CComponent; + /// Class which draws formatted text messages and generates chat windows class CMessage { diff --git a/client/windows/CQuestLog.cpp b/client/windows/CQuestLog.cpp index e3ef8a562..7ee5c35fc 100644 --- a/client/windows/CQuestLog.cpp +++ b/client/windows/CQuestLog.cpp @@ -10,15 +10,14 @@ #include "StdInc.h" #include "CQuestLog.h" -#include "CAdvmapInterface.h" - #include "../CGameInfo.h" #include "../CPlayerInterface.h" -#include "../Graphics.h" #include "../gui/CGuiHandler.h" -#include "../gui/SDL_Extensions.h" #include "../widgets/CComponent.h" +#include "../adventureMap/CAdvMapInt.h" +#include "../widgets/Buttons.h" +#include "../adventureMap/CMinimap.h" #include "../../CCallback.h" #include "../../lib/CArtHandler.h" diff --git a/client/windows/CQuestLog.h b/client/windows/CQuestLog.h index c1446a2c8..9654d0481 100644 --- a/client/windows/CQuestLog.h +++ b/client/windows/CQuestLog.h @@ -9,10 +9,10 @@ */ #pragma once -#include "../widgets/AdventureMapClasses.h" #include "../widgets/TextControls.h" #include "../widgets/MiscWidgets.h" #include "../widgets/Images.h" +#include "../adventureMap/CMinimap.h" #include "CWindowObject.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/client/windows/CSpellWindow.cpp b/client/windows/CSpellWindow.cpp index 2cc5b6c78..0c055823a 100644 --- a/client/windows/CSpellWindow.cpp +++ b/client/windows/CSpellWindow.cpp @@ -12,25 +12,22 @@ #include "../../lib/ScopeGuard.h" -#include "CAdvmapInterface.h" #include "GUIClasses.h" #include "InfoWindows.h" #include "CCastleInterface.h" #include "../CGameInfo.h" -#include "../CMessage.h" #include "../CMT.h" #include "../CPlayerInterface.h" #include "../CVideoHandler.h" -#include "../Graphics.h" #include "../battle/BattleInterface.h" -#include "../gui/CAnimation.h" #include "../gui/CGuiHandler.h" -#include "../gui/SDL_Extensions.h" #include "../widgets/MiscWidgets.h" #include "../widgets/CComponent.h" #include "../widgets/TextControls.h" +#include "../adventureMap/CAdvMapInt.h" +#include "../render/CAnimation.h" #include "../../CCallback.h" diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index d12bbf7c6..c1e7ca1e3 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -10,11 +10,14 @@ #include "StdInc.h" #include "CTradeWindow.h" -#include "CAdvmapInterface.h" - #include "../gui/CGuiHandler.h" #include "../gui/CursorHandler.h" #include "../widgets/Images.h" +#include "../adventureMap/CAdvMapInt.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../gui/TextAlignment.h" +#include "../widgets/Buttons.h" +#include "../widgets/TextControls.h" #include "../CGameInfo.h" #include "../CPlayerInterface.h" diff --git a/client/windows/CWindowObject.cpp b/client/windows/CWindowObject.cpp index dca6b6e5b..86ad26bb6 100644 --- a/client/windows/CWindowObject.cpp +++ b/client/windows/CWindowObject.cpp @@ -10,24 +10,20 @@ #include "StdInc.h" #include "CWindowObject.h" -#include "CAdvmapInterface.h" - #include "../widgets/MiscWidgets.h" #include "../widgets/Images.h" - -#include "../gui/SDL_PixelAccess.h" -#include "../gui/SDL_Extensions.h" +#include "../widgets/TextControls.h" #include "../gui/CGuiHandler.h" #include "../gui/CursorHandler.h" -#include "../gui/CAnimation.h" - #include "../battle/BattleInterface.h" #include "../battle/BattleInterfaceClasses.h" +#include "../windows/CMessage.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../renderSDL/SDL_PixelAccess.h" +#include "../render/IImage.h" -#include "../Graphics.h" #include "../CGameInfo.h" #include "../CPlayerInterface.h" -#include "../CMessage.h" #include "../CMusicHandler.h" #include "../../CCallback.h" diff --git a/client/windows/CreaturePurchaseCard.cpp b/client/windows/CreaturePurchaseCard.cpp index 9a0b72ca3..b880146d3 100644 --- a/client/windows/CreaturePurchaseCard.cpp +++ b/client/windows/CreaturePurchaseCard.cpp @@ -9,16 +9,20 @@ */ #include "StdInc.h" #include "CreaturePurchaseCard.h" -#include "CAdvmapInterface.h" + #include "CHeroWindow.h" -#include "../widgets/Buttons.h" -#include "../../CCallback.h" -#include "../CreatureCostBox.h" #include "QuickRecruitmentWindow.h" -#include "../gui/CGuiHandler.h" -#include "../../lib/CCreatureHandler.h" #include "CCreatureWindow.h" +#include "../gui/CGuiHandler.h" +#include "../gui/TextAlignment.h" +#include "../widgets/Buttons.h" +#include "../widgets/TextControls.h" +#include "../widgets/CreatureCostBox.h" + +#include "../../CCallback.h" +#include "../../lib/CCreatureHandler.h" + void CreaturePurchaseCard::initButtons() { initMaxButton(); diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 50fefaa2a..bdd3a9eec 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -10,34 +10,36 @@ #include "StdInc.h" #include "GUIClasses.h" -#include "CAdvmapInterface.h" #include "CCastleInterface.h" #include "CCreatureWindow.h" #include "CHeroWindow.h" -#include "CreatureCostBox.h" #include "InfoWindows.h" #include "../CGameInfo.h" -#include "../CMessage.h" #include "../CMusicHandler.h" #include "../CPlayerInterface.h" #include "../CVideoHandler.h" -#include "../Graphics.h" -#include "../mapHandler.h" #include "../CServerHandler.h" +#include "../adventureMap/mapHandler.h" +#include "../adventureMap/CResDataBar.h" #include "../battle/BattleInterfaceClasses.h" #include "../battle/BattleInterface.h" -#include "../gui/CAnimation.h" #include "../gui/CGuiHandler.h" -#include "../gui/SDL_Extensions.h" #include "../gui/CursorHandler.h" +#include "../gui/TextAlignment.h" #include "../widgets/CComponent.h" #include "../widgets/MiscWidgets.h" +#include "../widgets/CreatureCostBox.h" +#include "../widgets/Buttons.h" +#include "../widgets/TextControls.h" +#include "../widgets/ObjectLists.h" #include "../lobby/CSavingScreen.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../render/CAnimation.h" #include "../../CCallback.h" @@ -65,9 +67,6 @@ using namespace CSDL_Ext; -std::list CFocusable::focusables; -CFocusable * CFocusable::inputWithFocus; - CRecruitmentWindow::CCreatureCard::CCreatureCard(CRecruitmentWindow * window, const CCreature * crea, int totalAmount) : CIntObject(LCLICK | RCLICK), parent(window), diff --git a/client/windows/InfoWindows.cpp b/client/windows/InfoWindows.cpp index 6f1bc6d46..4fe1b9b04 100644 --- a/client/windows/InfoWindows.cpp +++ b/client/windows/InfoWindows.cpp @@ -10,23 +10,21 @@ #include "StdInc.h" #include "InfoWindows.h" -#include "CAdvmapInterface.h" - -#include "../Graphics.h" #include "../CGameInfo.h" #include "../CPlayerInterface.h" -#include "../CMessage.h" #include "../CMusicHandler.h" #include "../widgets/CComponent.h" #include "../widgets/MiscWidgets.h" - -#include "../gui/SDL_Extensions.h" +#include "../widgets/Buttons.h" +#include "../widgets/TextControls.h" #include "../gui/CGuiHandler.h" -#include "../gui/CursorHandler.h" - #include "../battle/BattleInterface.h" #include "../battle/BattleInterfaceClasses.h" +#include "../adventureMap/CAdvMapInt.h" +#include "../windows/CMessage.h" +#include "../renderSDL/SDL_Extensions.h" +#include "../gui/CursorHandler.h" #include "../../CCallback.h" diff --git a/client/windows/QuickRecruitmentWindow.cpp b/client/windows/QuickRecruitmentWindow.cpp index 07751d314..17c61a2c0 100644 --- a/client/windows/QuickRecruitmentWindow.cpp +++ b/client/windows/QuickRecruitmentWindow.cpp @@ -12,9 +12,9 @@ #include "../../lib/mapObjects/CGTownInstance.h" #include "../CPlayerInterface.h" #include "../widgets/Buttons.h" +#include "../widgets/CreatureCostBox.h" #include "../gui/CGuiHandler.h" #include "../../CCallback.h" -#include "../CreatureCostBox.h" #include "../../lib/ResourceSet.h" #include "../../lib/CCreatureHandler.h" #include "CreaturePurchaseCard.h" From 19925c2c2502471e0aeb4a13a8cafef65777f997 Mon Sep 17 00:00:00 2001 From: Dydzio Date: Wed, 1 Feb 2023 20:25:09 +0100 Subject: [PATCH 78/79] VcmiLua builds properly now --- include/vcmi/Skill.h | 3 ++- include/vcmi/SkillService.h | 4 ++-- lib/CSkillHandler.h | 6 +++--- scripting/lua/api/Artifact.cpp | 6 +++--- scripting/lua/api/BattleCb.cpp | 2 +- scripting/lua/api/Creature.cpp | 6 +++--- scripting/lua/api/Faction.cpp | 2 +- scripting/lua/api/HeroClass.cpp | 2 +- scripting/lua/api/HeroType.cpp | 2 +- scripting/lua/api/Skill.cpp | 2 +- scripting/lua/api/Spell.cpp | 4 ++-- 11 files changed, 20 insertions(+), 19 deletions(-) diff --git a/include/vcmi/Skill.h b/include/vcmi/Skill.h index 363e67869..16ce88767 100644 --- a/include/vcmi/Skill.h +++ b/include/vcmi/Skill.h @@ -19,7 +19,8 @@ class SecondarySkill; class DLL_LINKAGE Skill : public EntityT { public: - + virtual std::string getDescriptionTextID(int level) const = 0; + virtual std::string getDescriptionTranslated(int level) const = 0; }; diff --git a/include/vcmi/SkillService.h b/include/vcmi/SkillService.h index ce0fa8b12..6e8618898 100644 --- a/include/vcmi/SkillService.h +++ b/include/vcmi/SkillService.h @@ -15,9 +15,9 @@ VCMI_LIB_NAMESPACE_BEGIN class SecondarySkill; -class CSkill; +class Skill; -class DLL_LINKAGE SkillService : public EntityServiceT +class DLL_LINKAGE SkillService : public EntityServiceT { public: }; diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index bf48b18f4..ec3b87ca5 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -63,8 +63,8 @@ public: std::string getNameTextID() const override; std::string getNameTranslated() const override; - std::string getDescriptionTextID(int level) const; - std::string getDescriptionTranslated(int level) const; + std::string getDescriptionTextID(int level) const override; + std::string getDescriptionTranslated(int level) const override; const LevelInfo & at(int level) const; LevelInfo & at(int level); @@ -89,7 +89,7 @@ public: friend DLL_LINKAGE std::ostream & operator<<(std::ostream & out, const CSkill::LevelInfo & info); }; -class DLL_LINKAGE CSkillHandler: public CHandlerBase +class DLL_LINKAGE CSkillHandler: public CHandlerBase { public: CSkillHandler(); diff --git a/scripting/lua/api/Artifact.cpp b/scripting/lua/api/Artifact.cpp index 405e03ca0..0fe72a1c9 100644 --- a/scripting/lua/api/Artifact.cpp +++ b/scripting/lua/api/Artifact.cpp @@ -31,13 +31,13 @@ const std::vector ArtifactProxy::REGISTER_CUSTOM = {"getIconIndex", LuaMethodWrapper::invoke, false}, {"getIndex", LuaMethodWrapper::invoke, false}, {"getJsonKey", LuaMethodWrapper::invoke, false}, - {"getName", LuaMethodWrapper::invoke, false}, + {"getName", LuaMethodWrapper::invoke, false}, {"getId", LuaMethodWrapper::getId), &EntityT::getId>::invoke, false}, {"accessBonuses", LuaMethodWrapper::accessBonuses), &EntityWithBonuses::accessBonuses>::invoke, false}, - {"getDescription", LuaMethodWrapper::invoke, false}, - {"getEventText", LuaMethodWrapper::invoke, false}, + {"getDescription", LuaMethodWrapper::invoke, false}, + {"getEventText", LuaMethodWrapper::invoke, false}, {"isBig", LuaMethodWrapper::invoke, false}, {"isTradable", LuaMethodWrapper::invoke, false}, {"getPrice", LuaMethodWrapper::invoke, false}, diff --git a/scripting/lua/api/BattleCb.cpp b/scripting/lua/api/BattleCb.cpp index 222e6403c..de4e87a83 100644 --- a/scripting/lua/api/BattleCb.cpp +++ b/scripting/lua/api/BattleCb.cpp @@ -88,7 +88,7 @@ int BattleCbProxy::getTerrainType(lua_State * L) if(!S.tryGet(1, object)) return S.retVoid(); - return LuaStack::quickRetInt(L, object->battleTerrainType()); + return LuaStack::quickRetInt(L, object->battleTerrainType().getNum()); } int BattleCbProxy::getUnitByPos(lua_State * L) diff --git a/scripting/lua/api/Creature.cpp b/scripting/lua/api/Creature.cpp index 0b4713a83..bf6ed9e9c 100644 --- a/scripting/lua/api/Creature.cpp +++ b/scripting/lua/api/Creature.cpp @@ -31,12 +31,12 @@ const std::vector CreatureProxy::REGISTER_CUSTOM = {"getIconIndex", LuaMethodWrapper::invoke, false}, {"getIndex", LuaMethodWrapper::invoke, false}, {"getJsonKey", LuaMethodWrapper::invoke, false}, - {"getName", LuaMethodWrapper::invoke, false}, + {"getName", LuaMethodWrapper::invoke, false}, {"accessBonuses", LuaMethodWrapper::accessBonuses), &EntityWithBonuses::accessBonuses>::invoke, false}, {"getMaxHealth", LuaMethodWrapper::invoke, false}, - {"getPluralName", LuaMethodWrapper::invoke, false}, - {"getSingularName", LuaMethodWrapper::invoke, false}, + {"getPluralName", LuaMethodWrapper::invoke, false}, + {"getSingularName", LuaMethodWrapper::invoke, false}, {"getAdvMapAmountMin", LuaMethodWrapper::invoke, false}, {"getAdvMapAmountMax", LuaMethodWrapper::invoke, false}, diff --git a/scripting/lua/api/Faction.cpp b/scripting/lua/api/Faction.cpp index 358c43dcb..07cce7462 100644 --- a/scripting/lua/api/Faction.cpp +++ b/scripting/lua/api/Faction.cpp @@ -30,7 +30,7 @@ const std::vector FactionProxy::REGISTER_CUSTOM = {"getIconIndex", LuaMethodWrapper::invoke, false}, {"getIndex", LuaMethodWrapper::invoke, false}, {"getJsonKey", LuaMethodWrapper::invoke, false}, - {"getName", LuaMethodWrapper::invoke, false}, + {"getName", LuaMethodWrapper::invoke, false}, {"hasTown", LuaMethodWrapper::invoke, false}, }; diff --git a/scripting/lua/api/HeroClass.cpp b/scripting/lua/api/HeroClass.cpp index 03835c4e5..31f0c88bf 100644 --- a/scripting/lua/api/HeroClass.cpp +++ b/scripting/lua/api/HeroClass.cpp @@ -29,7 +29,7 @@ const std::vector HeroClassProxy::REGISTER_CUSTOM {"getIconIndex", LuaMethodWrapper::invoke, false}, {"getIndex", LuaMethodWrapper::invoke, false}, {"getJsonKey", LuaMethodWrapper::invoke, false}, - {"getName", LuaMethodWrapper::invoke, false}, + {"getName", LuaMethodWrapper::invoke, false}, }; } diff --git a/scripting/lua/api/HeroType.cpp b/scripting/lua/api/HeroType.cpp index c48ee8f48..87a4d8410 100644 --- a/scripting/lua/api/HeroType.cpp +++ b/scripting/lua/api/HeroType.cpp @@ -30,7 +30,7 @@ const std::vector HeroTypeProxy::REGISTER_CUSTOM = {"getIconIndex", LuaMethodWrapper::invoke, false}, {"getIndex", LuaMethodWrapper::invoke, false}, {"getJsonKey", LuaMethodWrapper::invoke, false}, - {"getName", LuaMethodWrapper::invoke, false}, + {"getName", LuaMethodWrapper::invoke, false}, }; diff --git a/scripting/lua/api/Skill.cpp b/scripting/lua/api/Skill.cpp index bf00a0cca..eb08e3832 100644 --- a/scripting/lua/api/Skill.cpp +++ b/scripting/lua/api/Skill.cpp @@ -29,7 +29,7 @@ const std::vector SkillProxy::REGISTER_CUSTOM = {"getIconIndex", LuaMethodWrapper::invoke, false}, {"getIndex", LuaMethodWrapper::invoke, false}, {"getJsonKey", LuaMethodWrapper::invoke, false}, - {"getName", LuaMethodWrapper::invoke, false}, + {"getName", LuaMethodWrapper::invoke, false}, }; } diff --git a/scripting/lua/api/Spell.cpp b/scripting/lua/api/Spell.cpp index cd3eb9a3f..4460b2deb 100644 --- a/scripting/lua/api/Spell.cpp +++ b/scripting/lua/api/Spell.cpp @@ -33,7 +33,7 @@ const std::vector SpellProxy::REGISTER_CUSTOM = {"getIconIndex", LuaMethodWrapper::invoke, false}, {"getIndex", LuaMethodWrapper::invoke, false}, {"getJsonKey", LuaMethodWrapper::invoke, false}, - {"getName", LuaMethodWrapper::invoke, false}, + {"getName", LuaMethodWrapper::invoke, false}, {"isAdventure", LuaMethodWrapper::invoke, false}, {"isCombat", LuaMethodWrapper::invoke, false}, @@ -48,7 +48,7 @@ const std::vector SpellProxy::REGISTER_CUSTOM = {"getCost", LuaMethodWrapper::invoke, false}, {"getBasePower", LuaMethodWrapper::invoke, false}, {"getLevelPower", LuaMethodWrapper::invoke, false}, - {"getLevelDescription", LuaMethodWrapper::invoke, false}, + {"getLevelDescription", LuaMethodWrapper::invoke, false}, }; } From 34772ef830b5bf09542fde7a9b06339789c5890b Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 1 Feb 2023 21:11:10 +0200 Subject: [PATCH 79/79] Fixed includes --- CCallback.cpp | 1 - client/render/IFont.h | 2 -- client/render/IImageLoader.h | 5 ++++- client/renderSDL/SDL_Extensions.cpp | 24 ++++++++++-------------- lib/mapObjects/CObjectHandler.h | 1 - 5 files changed, 14 insertions(+), 19 deletions(-) diff --git a/CCallback.cpp b/CCallback.cpp index 4e4e3eeee..6805cb936 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -11,7 +11,6 @@ #include "CCallback.h" #include "lib/CCreatureHandler.h" -#include "client/CGameInfo.h" #include "lib/CGameState.h" #include "client/CPlayerInterface.h" #include "client/Client.h" diff --git a/client/render/IFont.h b/client/render/IFont.h index 933b85db5..4a1b92863 100644 --- a/client/render/IFont.h +++ b/client/render/IFont.h @@ -10,9 +10,7 @@ #pragma once VCMI_LIB_NAMESPACE_BEGIN - class Point; - VCMI_LIB_NAMESPACE_END struct SDL_Surface; diff --git a/client/render/IImageLoader.h b/client/render/IImageLoader.h index fd3a72045..966a5be26 100644 --- a/client/render/IImageLoader.h +++ b/client/render/IImageLoader.h @@ -10,8 +10,11 @@ #pragma once -class SDLImage; +VCMI_LIB_NAMESPACE_BEGIN class Point; +VCMI_LIB_NAMESPACE_END + +class SDLImage; struct SDL_Color; diff --git a/client/renderSDL/SDL_Extensions.cpp b/client/renderSDL/SDL_Extensions.cpp index 2e66eb4bd..0e0753bee 100644 --- a/client/renderSDL/SDL_Extensions.cpp +++ b/client/renderSDL/SDL_Extensions.cpp @@ -11,24 +11,20 @@ #include "SDL_Extensions.h" #include "SDL_PixelAccess.h" -// -//#include "../CGameInfo.h" -//#include "../CMessage.h" + #include "../render/Graphics.h" -//#include "../CMT.h" -// -//#include + #include #include #include -// -//#ifdef VCMI_APPLE -//#include -//#endif -// -//#ifdef VCMI_IOS -//#include "ios/utils.h" -//#endif + +#ifdef VCMI_APPLE +#include +#endif + +#ifdef VCMI_IOS +#include "ios/utils.h" +#endif const SDL_Color Colors::YELLOW = { 229, 215, 123, SDL_ALPHA_OPAQUE }; const SDL_Color Colors::WHITE = { 255, 243, 222, SDL_ALPHA_OPAQUE }; diff --git a/lib/mapObjects/CObjectHandler.h b/lib/mapObjects/CObjectHandler.h index 387020f72..07df7e3d5 100644 --- a/lib/mapObjects/CObjectHandler.h +++ b/lib/mapObjects/CObjectHandler.h @@ -11,7 +11,6 @@ #include "ObjectTemplate.h" -//#include "../IGameCallback.h" #include "../int3.h" #include "../HeroBonus.h"