1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +02:00

Merge remote-tracking branch 'origin/develop' into settings-rework

This commit is contained in:
Dydzio 2023-02-12 11:55:21 +01:00
commit fc7d2b9778
157 changed files with 3204 additions and 1968 deletions

View File

@ -173,6 +173,18 @@ set(CMAKE_XCODE_ATTRIBUTE_MARKETING_VERSION ${APP_SHORT_VERSION})
set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH NO)
set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH[variant=Debug] YES)
#Check for endian
if(${CMAKE_VERSION} VERSION_LESS "3.20.0")
include(TestBigEndian)
test_big_endian(VCMI_ENDIAN_BIG)
if(VCMI_ENDIAN_BIG)
add_definitions(-DVCMI_ENDIAN_BIG)
endif()
elseif(${CMAKE_CXX_BYTE_ORDER} EQUAL "BIG_ENDIAN")
add_definitions(-DVCMI_ENDIAN_BIG)
endif()
if(ENABLE_LAUNCHER)
add_definitions(-DENABLE_LAUNCHER)
endif()

View File

@ -1,3 +1,160 @@
# 1.1.1 -> 1.2.0
(unreleased, changes for 1.1.1..9c59025)
### GENERAL:
* Implemented hardware cursor support
* Heroes III language can now be detected automatically
* Increased targeted framerate from 48 to 60
* Fixed bonus values of heroes who specialize in secondary skills
* Fixed bonus values of heroes who specialize in creatures
* Fixed damage increase from Adela's Bless specialty
* Fixed missing obstacles in battles on subterranean terrain
* Added vcmifaerie, vcmiazure, vcmiarmy, vcmiexp cheats
* Video files now play at correct speed
### MAP EDITOR:
* Added translations to German, Polish, Russian, Ukrainian
* Implemented cut/copy/paste operations
* Implemented lasso brush for terrain editing
### LAUNCHER:
* Icons now have higher resolution, to prevent upscaling artifacts
* Added translations to German, Polish, Russian, Ukrainian
* Mods tab layout has been adjusted based on feedback from players
* Settings tab layout has been redesigned to support longer texts
* Added button to start map editor directly from Launcher
### ADVENTURE MAP:
* Implemented different hero movement sounds for offroad movement
* Cartographers now reveal terrain in the same way as in H3
* Holding ALT will now show movement points information in status bar
* It is now not possible to receive rewards from School of War without required gold amount
* Owned objects, like Mines and Dwellings will always show their owner in status bar
* It is now possible to interact with on-map Shipyard when no hero is selected
## INTERFACE
* Fixed white status bar on server connection screen
* Buttons in battle window now correctly show tooltip in status bar
* Fixed cursor image during enemy turn in combat
* Fixed cases of incorrect artifact slot highlighting
* Game will no longer promt to assemble artifacts if they fall into backpack
* It is now possible to use in-game console for vcmi commands
* Stacks sized 1000-9999 units will not be displayed as "1k"
* It is now possible to select destination town for Town Portal via double-click
### TOWN SCREEN
* Fixed gradual fade-in of a newly built building
* Fixed duration of building fade-in to match H3
* Fixed rendering of Shipyard in Castle
### BATTLES:
* All effects will now wait for battle opening sound before playing
* Hex highlighting will now be disabled during enemy turn
* Fixed incorrect log message when casting spell that kills zero units
* Implemented animated cursor for spellcasting
* Fixed multiple issues related to ordering of creature animations
* Fixed missing flags from hero animations when opening menus
* Fixed rendering order of moat and grid shadow
* Jousting bonus from Champions will now be correctly accounted for in damage estimation
* Building Castle building will now provide walls with additional health point
* Speed of all battle animations should now match H3
* Fixed missing obstacles on subterranean terrain
* Ballistics mechanics now matches H3 logic
* Arrow Tower base damage should now match H3
* Destruction of wall segments will now remove ranged attack penalty
* Force Field cast in front of drawbridge will now block it as in H3
* Fixed computations for Behemoth defense reduction ability
* Bad luck (if enabled) will now multiple all damage by 50%, in line with other damage reducing mechanics
* Fixed highlighting of movement range for creatures standing on a corpse
* All battle animations now have same duration/speed as in H3
* Added missing combat log message on resurrecting creatures
* Fixed visibility of blue border around targeted creature when spellcaster is making turn
* Fixed selection highlight when in targeted creature spellcasting mode
* Hovering over hero now correctly shows hero cursor
* Creature currently making turn is now highlighted in the Battle Queue
* Hovering over creature icon in Battle Queue will highlight this creature in the battlefield
### SPELLS:
* Hero casting animation will play before spell effect
* Fire Shield: added sound effect
* Fire Shield: effect now correctly plays on defending creature
* Earthquake: added sound effect
* Earthquake: spell will not select sections that were already destroyed before cast
* Remove Obstacles: fixed error message when casting on maps without obstacles
* All area-effect spells (e.g. Fireball) will play their effect animation on top
* Summoning spells: added fade-in effect for summoned creatures
* Fixed timing of hit animation for damage-dealing spells
* Obstacle-creating spells: UI is now locked during effect animation
* Obstacle-creating spells: added sound effect
* Added reverse death animation for spells that bring stack back to life
* Bloodlust: implemented visual effect
* Teleport: implemented visual fade-out and fade-in effect for teleporting
* Berserk: Fixed duration of effect
* Frost Ring: Fixed spell effect range
* Fixed several cases where multiple different effects could play at the same time
* All spells that can affecte multiple targets will now highlight affected stacks
* Bless and Curse now provide +1 or -1 to base damage on Advanced & Expert levels
### ABILITIES:
* Rebirth (Phoenix): Sound will now play in the same time as animation effect
* Master Genie spellcasting: Sound will now play in the same time as animation effect
* Power Lich, Magogs: Sound will now play in the same time as attack animation effect
* Dragon Breath attack now correctly uses different attack animation if multiple targets are hit
* Petrification: implemented visual effect
* Paralyze: added visual effect
* Blind: Stacks will no longer retailate on attack that blinds them
* Demon Summon: Added animation effect for summoning
* Fire shield will no longer trigger on non-adjacent attacks, e.g. from Dragon Breath
* Weakness now has correct visual effect
* Added damage bonus for opposite elements for Elementals
* Added damage reduction for Magic Elemental attacks against creatures immune to magic
* Added incoming damage reduction to Petrify
* Added counter-attack damage reduction for Paralyze
### MODDING:
* All configurable objects from H3 now have their configuration in json
* Improvements to functionality of configurable objects
* It is now possible to define new hero movement sounds in terrains
* Implemented translation support for mods
* Files with new Terrains, Roads and Rivers are now validated by game
* Parameters controlling effect of attack and defences stats on damage are now configurable in defaultMods.json
* New bonus: LIMITED_SHOOTING_RANGE. Creatures with this bonus can only use ranged attack within specified range
* Battle window and Random Map Tab now have their layout defined in json file
* Implemented code support for alternative actions mod
* Implemented code support for improved random map dialog
# 1.1.0 -> 1.1.1
### GENERAL:
* Fixed missing sound in Polish version from gog.com
* Fixed positioning of main menu buttons in localized versions of H3
* Fixed crash on transferring artifact to commander
* Fixed game freeze on receiving multiple artifact assembly dialogs after combat
* Fixed potential game freeze on end of music playback
* macOS/iOS: fixed sound glitches
* Android: upgraded version of SDL library
* Android: reworked right click gesture and relative pointer mode
* Improved map loading speed
* Ubuntu PPA: game will no longer crash on assertion failure
### ADVENTURE MAP:
* Fixed hero movement lag in single-player games
* Fixed number of drowned troops on visiting Sirens to match H3
* iOS: pinch gesture visits current object (Spacebar behavior) instead of activating in-game console
### TOWNS:
* Fixed displaying growth bonus from Statue of Legion
* Growth bonus tooltip ordering now matches H3
* Buy All Units dialog will now buy units starting from the highest level
### LAUNCHER:
* Local mods can be disabled or uninstalled
* Fixed styling of Launcher interface
### MAP EDITOR:
* Fixed saving of roads and rivers
* Fixed placement of heroes on map
# 1.0.0 -> 1.1.0
### GENERAL:

View File

@ -725,7 +725,27 @@ namespace vstd
return a + (b - a) * f;
}
using boost::math::round;
/// converts number into string using metric system prefixes, e.g. 'k' or 'M' to keep resulting strings within specified size
/// Note that resulting string may have more symbols than digits: minus sign and prefix symbol
template<typename Arithmetic>
std::string formatMetric(Arithmetic number, int maxDigits)
{
Arithmetic max = std::pow(10, maxDigits);
if (std::abs(number) < max)
return std::to_string(number);
std::string symbols = " kMGTPE";
auto iter = symbols.begin();
while (std::abs(number) >= max)
{
number /= 1000;
iter++;
assert(iter != symbols.end());//should be enough even for int64
}
return std::to_string(number) + *iter;
}
}
using vstd::operator-=;

View File

@ -93,7 +93,7 @@
"core.bonus.ATTACKS_ALL_ADJACENT.name": "Attack all around",
"core.bonus.ATTACKS_ALL_ADJACENT.description": "Attacks all adjacent enemies",
"core.bonus.BLOCKS_RETALIATION.name": "No retaliation",
"core.bonus.BLOCKS_RETALIATION.description": "Enemy cannot Retaliate",
"core.bonus.BLOCKS_RETALIATION.description": "Enemy cannot retaliate",
"core.bonus.BLOCKS_RANGED_RETALIATION.name": "No ranged retaliation",
"core.bonus.BLOCKS_RANGED_RETALIATION.description": "Enemy cannot Retaliate by shooting",
"core.bonus.CATAPULT.name": "Catapult",
@ -143,7 +143,7 @@
"core.bonus.FREE_SHOOTING.name": "Shoot Close",
"core.bonus.FREE_SHOOTING.description": "Can shoot in Close Combat",
"core.bonus.FULL_HP_REGENERATION.name": "Regeneration",
"core.bonus.FULL_HP_REGENERATION.description": "May Regenerate to full Health",
"core.bonus.FULL_HP_REGENERATION.description": "May regenerate to full health",
"core.bonus.GARGOYLE.name": "Gargoyle",
"core.bonus.GARGOYLE.description": "Cannot be rised or healed",
"core.bonus.GENERAL_DAMAGE_REDUCTION.name": "Reduce Damage (${val}%)",
@ -165,7 +165,7 @@
"core.bonus.LEVEL_SPELL_IMMUNITY.name": "Spell immunity 1-${val}",
"core.bonus.LEVEL_SPELL_IMMUNITY.description": "Immune to spells of levels 1-${val}",
"core.bonus.LIMITED_SHOOTING_RANGE.name" : "Limited shooting range",
"core.bonus.LIMITED_SHOOTING_RANGE.description" : "",
"core.bonus.LIMITED_SHOOTING_RANGE.description" : "Cannot shoot targets beyond ${val} hexes away",
"core.bonus.LIFE_DRAIN.name": "Drain life (${val}%)",
"core.bonus.LIFE_DRAIN.description": "Drains ${val}% of damage dealt",
"core.bonus.MANA_CHANNELING.name": "Magic Channel ${val}%",
@ -221,7 +221,7 @@
"core.bonus.SPELL_LIKE_ATTACK.name": "Spell-like attack",
"core.bonus.SPELL_LIKE_ATTACK.description": "Attacks with ${subtype.spell}",
"core.bonus.SPELL_RESISTANCE_AURA.name": "Aura of Resistance",
"core.bonus.SPELL_RESISTANCE_AURA.description": "Nearby stacks get ${val}% resistance",
"core.bonus.SPELL_RESISTANCE_AURA.description": "Nearby stacks get ${val}% magic resistance",
"core.bonus.SUMMON_GUARDIANS.name": "Summon guardians",
"core.bonus.SUMMON_GUARDIANS.description": "At battle start summons ${subtype.creature} (${val}%)",
"core.bonus.SYNERGY_TARGET.name": "Synergizable",

View File

@ -1,5 +1,5 @@
{
"vcmi.adventureMap.monsterThreat.title" : "\n\n Poziom zagrożenia: ",
"vcmi.adventureMap.monsterThreat.title" : "\n\n Zagrożenie: ",
"vcmi.adventureMap.monsterThreat.levels.0" : "Zerowy",
"vcmi.adventureMap.monsterThreat.levels.1" : "Bardzo słaby",
"vcmi.adventureMap.monsterThreat.levels.2" : "Słaby",
@ -13,11 +13,13 @@
"vcmi.adventureMap.monsterThreat.levels.10" : "Śmiertelny",
"vcmi.adventureMap.monsterThreat.levels.11" : "Nie do pokonania",
"vcmi.adventureMap.confirmRestartGame" : "Czy na pewno chcesz zrestartować grę?",
"vcmi.adventureMap.noTownWithMarket" : "Brak dostępnego targowiska!",
"vcmi.adventureMap.noTownWithTavern" : "Brak dostępnego miasta z karczmą!",
"vcmi.adventureMap.spellUnknownProblem" : "Nieznany problem z zaklęciem, brak dodatkowych informacji.",
"vcmi.adventureMap.playerAttacked" : "Gracz został zaatakowany: %s",
"vcmi.adventureMap.confirmRestartGame" : "Czy na pewno chcesz zrestartować grę?",
"vcmi.adventureMap.noTownWithMarket" : "Brak dostępnego targowiska!",
"vcmi.adventureMap.noTownWithTavern" : "Brak dostępnego miasta z karczmą!",
"vcmi.adventureMap.spellUnknownProblem" : "Nieznany problem z zaklęciem, brak dodatkowych informacji.",
"vcmi.adventureMap.playerAttacked" : "Gracz został zaatakowany: %s",
"vcmi.adventureMap.moveCostDetails" : "Punkty ruchu - Koszt: %TURNS tury + %POINTS punkty, Pozostałe punkty: %REMAINING",
"vcmi.adventureMap.moveCostDetailsNoTurns" : "Punkty ruchu - Koszt: %POINTS punkty, Pozostałe punkty: %REMAINING",
"vcmi.server.errors.existingProcess" : "Inny proces vcmiserver został już uruchomiony, zakończ go nim przejdziesz dalej",
"vcmi.server.errors.modsIncompatibility" : "Mody wymagane do wczytania gry:",
@ -66,5 +68,162 @@
"vcmi.randomMapTab.widgets.defaultTemplate" : "domyślny",
"vcmi.randomMapTab.widgets.templateLabel" : "Szablon",
"vcmi.randomMapTab.widgets.teamAlignmentsButton" : "Ustaw...",
"vcmi.randomMapTab.widgets.teamAlignmentsLabel" : "Sojusze"
"vcmi.randomMapTab.widgets.teamAlignmentsLabel" : "Sojusze",
"core.bonus.ADDITIONAL_ATTACK.name": "Podwójne Uderzenie",
"core.bonus.ADDITIONAL_ATTACK.description": "Atakuje podwójnie",
"core.bonus.ADDITIONAL_RETALIATION.name": "Dodatkowe kontrataki",
"core.bonus.ADDITIONAL_RETALIATION.description": "Może kontratakować ${val} dodatkowych razy",
"core.bonus.AIR_IMMUNITY.name": "Odporność na powietrze",
"core.bonus.AIR_IMMUNITY.description": "Odporny na wszystkie czary szkoły powietrza",
"core.bonus.ATTACKS_ALL_ADJACENT.name": "Atakuje wszystko dookoła",
"core.bonus.ATTACKS_ALL_ADJACENT.description": "Atakuje wszystkich sąsiadujących wrogów",
"core.bonus.BLOCKS_RETALIATION.name": "Bez kontrataku",
"core.bonus.BLOCKS_RETALIATION.description": "Wróg nie może kontratakować",
"core.bonus.BLOCKS_RANGED_RETALIATION.name": "Brak kontrataku dystansowego",
"core.bonus.BLOCKS_RANGED_RETALIATION.description": "Wróg nie może kontratakować poprzez strzelanie",
"core.bonus.CATAPULT.name": "Katapulta",
"core.bonus.CATAPULT.description": "Atakuje mury obronne",
"core.bonus.CATAPULT_EXTRA_SHOTS.name": "Dodatkowe ataki oblężnicze",
"core.bonus.CATAPULT_EXTRA_SHOTS.description": "Może uderzyć mury obronne ${val} dodatkowych razy na atak",
"core.bonus.CHANGES_SPELL_COST_FOR_ALLY.name": "Zmniejsz koszt czarów (${val})",
"core.bonus.CHANGES_SPELL_COST_FOR_ALLY.description": "Zmniejsza koszt czaru bohatera",
"core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.name": "Tłumienie magii (${val})",
"core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.description": "Zwiększa koszt wrogich czarów",
"core.bonus.CHARGE_IMMUNITY.name": "Odporność na szarżę",
"core.bonus.CHARGE_IMMUNITY.description": "Odporny na szarżę czempionów",
"core.bonus.DARKNESS.name": "Całun ciemności",
"core.bonus.DARKNESS.description": "Generuje ${val} wartości promienia mgły wojny",
"core.bonus.DEATH_STARE.name": "Spojrzenie Śmierci (${val}%)",
"core.bonus.DEATH_STARE.description": "${val}% szans na zabicie jednego stworzenia",
"core.bonus.DEFENSIVE_STANCE.name": "Bonus do obrony",
"core.bonus.DEFENSIVE_STANCE.description": "+${val} Obrony kiedy broni",
"core.bonus.DESTRUCTION.name": "Destrukcja",
"core.bonus.DESTRUCTION.description": "Ma ${val}% szans na zabicie dodatkowych jednostek po ataku",
"core.bonus.DOUBLE_DAMAGE_CHANCE.name": "Uderzenie Śmierci",
"core.bonus.DOUBLE_DAMAGE_CHANCE.description": "${val}% szans na podwójne obrażenia",
"core.bonus.DRAGON_NATURE.name": "Smok",
"core.bonus.DRAGON_NATURE.description": "Stworzenie posiada smoczą naturę",
"core.bonus.DIRECT_DAMAGE_IMMUNITY.name": "Odporność na bezpośrednie obrażenia",
"core.bonus.DIRECT_DAMAGE_IMMUNITY.description": "Odporny na czary zadające bezpośrednie obrażenia",
"core.bonus.EARTH_IMMUNITY.name": "Odporność na ziemię",
"core.bonus.EARTH_IMMUNITY.description": "Odporny na wszystkie czary szkoły ziemi",
"core.bonus.ENCHANTER.name": "Czarodziej",
"core.bonus.ENCHANTER.description": "Może rzucać masowy czar ${subtype.spell} każdej tury",
"core.bonus.ENCHANTED.name": "Zaczarowany",
"core.bonus.ENCHANTED.description": "Pod wpływem trwałego ${subtype.spell}",
"core.bonus.ENEMY_DEFENCE_REDUCTION.name": "Ignoruje Obronę (${val}%)",
"core.bonus.ENEMY_DEFENCE_REDUCTION.description": "Ignoruje część obrony podczas ataku",
"core.bonus.FIRE_IMMUNITY.name": "Odporność na ogień",
"core.bonus.FIRE_IMMUNITY.description": "Odporny na wszystkie czary szkoły ognia",
"core.bonus.FIRE_SHIELD.name": "Ognista tarcza (${val}%)",
"core.bonus.FIRE_SHIELD.description": "Odbija część obrażeń z walki wręcz",
"core.bonus.FIRST_STRIKE.name": "Pierwsze Uderzenie",
"core.bonus.FIRST_STRIKE.description": "To stworzenie atakuje pierwsze w ramach kontrataku",
"core.bonus.FEAR.name": "Strach",
"core.bonus.FEAR.description": "Wzbudza strach na wrogim stworzeniu",
"core.bonus.FEARLESS.name": "Nieustraszony",
"core.bonus.FEARLESS.description": "Odporny na strach",
"core.bonus.FLYING.name": "Lot",
"core.bonus.FLYING.description": "Może latać (ignoruje przeszkody)",
"core.bonus.FREE_SHOOTING.name": "Bliski Strzał",
"core.bonus.FREE_SHOOTING.description": "Może strzelać w zasięgu walki wręcz",
"core.bonus.FULL_HP_REGENERATION.name": "Regeneracja",
"core.bonus.FULL_HP_REGENERATION.description": "Może zregenerować się do pełni zdrowia",
"core.bonus.GARGOYLE.name": "Gargulec",
"core.bonus.GARGOYLE.description": "Nie może być wskrzeszony lub uleczony",
"core.bonus.GENERAL_DAMAGE_REDUCTION.name": "Zmniejsz obrażenia (${val}%)",
"core.bonus.GENERAL_DAMAGE_REDUCTION.description": "Zmiejsza obrażenia fizyczne z dystansu lub walki wręcz",
"core.bonus.HATE.name": "Nienawidzi ${subtype.creature}",
"core.bonus.HATE.description": "Zadaje ${val}% więcej obrażeń",
"core.bonus.HEALER.name": "Uzdrowiciel",
"core.bonus.HEALER.description": "Leczy sprzymierzone jednostki",
"core.bonus.HP_REGENERATION.name": "Regeneracja",
"core.bonus.HP_REGENERATION.description": "Leczy ${val} punktów zdrowia każdej rundy",
"core.bonus.JOUSTING.name": "Szarża Czempiona",
"core.bonus.JOUSTING.description": "+5% obrażeń na przebytego heksa",
"core.bonus.KING1.name": "Król 1",
"core.bonus.KING1.description": "Wrażliwy na podstawowy czar POGROMCA",
"core.bonus.KING2.name": "Król 2",
"core.bonus.KING2.description": "Wrażliwy na zaawansowany czar POGROMCA",
"core.bonus.KING3.name": "Król 3",
"core.bonus.KING3.description":"Wrażliwy na ekspercki czar POGROMCA",
"core.bonus.LEVEL_SPELL_IMMUNITY.name": "Odporność na czary 1-${val}",
"core.bonus.LEVEL_SPELL_IMMUNITY.description": "Odporny na czary 1-${val} poziomu",
"core.bonus.LIMITED_SHOOTING_RANGE.name" : "Ograniczony zasięg strzelania",
"core.bonus.LIMITED_SHOOTING_RANGE.description" : "Nie może strzelać do celów będących dalej niż ${val} heksów",
"core.bonus.LIFE_DRAIN.name": "Wysysa życie (${val}%)",
"core.bonus.LIFE_DRAIN.description": "Wysysa ${val}% zadanych obrażeń",
"core.bonus.MANA_CHANNELING.name": "Transfer many ${val}%",
"core.bonus.MANA_CHANNELING.description": "Daje twojemu bohaterowi manę zużytą przez przeciwnika",
"core.bonus.MANA_DRAIN.name": "Wyssanie many",
"core.bonus.MANA_DRAIN.description": "Wysysa ${val} many każdej tury",
"core.bonus.MAGIC_MIRROR.name": "Magiczne Zwierciadło (${val}%)",
"core.bonus.MAGIC_MIRROR.description": "${val}% szans na odbicie ofensywnego czaru do wroga",
"core.bonus.MAGIC_RESISTANCE.name": "Odporność na Magię(${MR}%)",
"core.bonus.MAGIC_RESISTANCE.description": "${MR}% szans na przeciwstawienie się wrogiemu czarowi",
"core.bonus.MIND_IMMUNITY.name": "Odporność na czasy umysłu",
"core.bonus.MIND_IMMUNITY.description": "Odporny na czary typu umysłu",
"core.bonus.NO_DISTANCE_PENALTY.name": "Brak ograniczeń za odległość",
"core.bonus.NO_DISTANCE_PENALTY.description": "Pełne obrażenia z każdego zasięgu",
"core.bonus.NO_MELEE_PENALTY.name": "Brak ograniczeń za walkę wręcz",
"core.bonus.NO_MELEE_PENALTY.description": "Stworzenie nie ma kar w walce wręcz",
"core.bonus.NO_MORALE.name": "Neutralne Morale",
"core.bonus.NO_MORALE.description": "Stworzenie jest odporne na efekty morale",
"core.bonus.NO_WALL_PENALTY.name": "Brak kar za strzelanie przez przeszkody",
"core.bonus.NO_WALL_PENALTY.description": "Pełne obrażenia podczas oblężenia",
"core.bonus.NON_LIVING.name": "Nie żyjący",
"core.bonus.NON_LIVING.description": "Niewrażliwość na wiele efektów",
"core.bonus.RANDOM_SPELLCASTER.name": "Losowy czarodziej",
"core.bonus.RANDOM_SPELLCASTER.description": "Może rzucić losowy czar",
"core.bonus.RANGED_RETALIATION.name": "Dystansowy kontratak",
"core.bonus.RANGED_RETALIATION.description": "Może wykonać kontratak dystansowy",
"core.bonus.RECEPTIVE.name": "Absorpcyjny",
"core.bonus.RECEPTIVE.description": "Brak odporności na przyjazne zaklęcia",
"core.bonus.REBIRTH.name": "Odrodzenie (${val}%)",
"core.bonus.REBIRTH.description": "${val}% stworzeń powstanie po śmierci",
"core.bonus.RETURN_AFTER_STRIKE.name": "Atak i Powrót",
"core.bonus.RETURN_AFTER_STRIKE.description": "Wraca po ataku wręcz",
"core.bonus.SELF_LUCK.name": "Pozytywne szczęście",
"core.bonus.SELF_LUCK.description": "Zawsze posiada pozytywne szczęście",
"core.bonus.SELF_MORALE.name": "Pozytywne Morale",
"core.bonus.SELF_MORALE.description": "Zawsze posiada pozytywne morale",
"core.bonus.SHOOTER.name": "Dystansowy",
"core.bonus.SHOOTER.description": "Stworzenie może strzelać",
"core.bonus.SHOOTS_ALL_ADJACENT.name": "Ostrzeliwuje wszystko dookoła",
"core.bonus.SHOOTS_ALL_ADJACENT.description": "Ataki dystansowe tego stworzenia uderzają we wszystkie cele na małym obszarze",
"core.bonus.SOUL_STEAL.name": "Kradzież dusz",
"core.bonus.SOUL_STEAL.description": "Zdobywa ${val} nowych stworzeń za każdego zabitego wroga",
"core.bonus.SPELLCASTER.name": "Czarodziej",
"core.bonus.SPELLCASTER.description": "Może rzucić ${subtype.spell}",
"core.bonus.SPELL_AFTER_ATTACK.name": "Rzuca czar po ataku",
"core.bonus.SPELL_AFTER_ATTACK.description": "${val}% szans aby rzucić ${subtype.spell} po ataku",
"core.bonus.SPELL_BEFORE_ATTACK.name": "Rzuca czar przed atakiem",
"core.bonus.SPELL_BEFORE_ATTACK.description": "${val}% szans aby rzucić ${subtype.spell} przed atakiem",
"core.bonus.SPELL_DAMAGE_REDUCTION.name": "Odporność na czary",
"core.bonus.SPELL_DAMAGE_REDUCTION.description": "Obrażenia od czarów są zmniejszone o ${val}%.",
"core.bonus.SPELL_IMMUNITY.name": "Odporność na czar",
"core.bonus.SPELL_IMMUNITY.description": "Odporny na ${subtype.spell}",
"core.bonus.SPELL_LIKE_ATTACK.name": "Atak czaropodobny",
"core.bonus.SPELL_LIKE_ATTACK.description": "Atakuje z użyciem ${subtype.spell}",
"core.bonus.SPELL_RESISTANCE_AURA.name": "Aura Odporności",
"core.bonus.SPELL_RESISTANCE_AURA.description": "Pobliskie stworzenia otrzymują ${val}% magicznej odporności",
"core.bonus.SUMMON_GUARDIANS.name": "Wezwij strażników",
"core.bonus.SUMMON_GUARDIANS.description": "Na początku walki wzywa ${subtype.creature} (${val}%)",
"core.bonus.SYNERGY_TARGET.name": "Synergiczny",
"core.bonus.SYNERGY_TARGET.description": "To stworzenie jest podatne na efekt synergii",
"core.bonus.TWO_HEX_ATTACK_BREATH.name": "Zionięcie",
"core.bonus.TWO_HEX_ATTACK_BREATH.description": "Atak zionący (zasięg 2 heksów)",
"core.bonus.THREE_HEADED_ATTACK.name": "Atak trzema głowami",
"core.bonus.THREE_HEADED_ATTACK.description": "Atakuje trzy sąsiadujące jednostki",
"core.bonus.TRANSMUTATION.name": "Transmutacja",
"core.bonus.TRANSMUTATION.description": "${val}% szans aby przetransformować atakowaną jednostkę na inny typ",
"core.bonus.UNDEAD.name": "Nieumarły",
"core.bonus.UNDEAD.description": "Stworzenie jest nieumarłe",
"core.bonus.UNLIMITED_RETALIATIONS.name": "Nieskończone kontrataki",
"core.bonus.UNLIMITED_RETALIATIONS.description": "Kontratakuje nieskończoną ilość razy",
"core.bonus.WATER_IMMUNITY.name": "Odporność na wodę",
"core.bonus.WATER_IMMUNITY.description": "Odporny na wszystkie czary szkoły wody",
"core.bonus.WIDE_BREATH.name": "Szerokie zionięcie",
"core.bonus.WIDE_BREATH.description": "Szeroki atak zionięciem (wiele heksów)"
}

View File

@ -14,10 +14,10 @@
},
"polish" : {
"name" : "VCMI essential files",
"description" : "Essential files required for VCMI to run correctly",
"author" : "VCMI Team",
"modType" : "Graphical",
"name" : "Podstawowe pliki VCMI",
"description" : "Dodatkowe pliki wymagane do prawidłowego działania VCMI",
"author" : "Zespół VCMI",
"modType" : "Graficzny",
"translations" : [
"config/vcmi/polish.json"

View File

@ -1,6 +1,7 @@
[![GitHub](https://github.com/vcmi/vcmi/actions/workflows/github.yml/badge.svg)](https://github.com/vcmi/vcmi/actions/workflows/github.yml)
[![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/github/vcmi/vcmi?branch=develop&svg=true)](https://ci.appveyor.com/project/vcmi/vcmi)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/vcmi/badge.svg)](https://scan.coverity.com/projects/vcmi)
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.1.1/total)](https://github.com/vcmi/vcmi/releases/tag/1.1.1)
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.1.0/total)](https://github.com/vcmi/vcmi/releases/tag/1.1.0)
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/total)](https://github.com/vcmi/vcmi/releases)
# VCMI Project

View File

@ -54,7 +54,7 @@
#include <SDL.h>
#ifdef VCMI_WINDOWS
#include "SDL_syswm.h"
#include <SDL_syswm.h>
#endif
#ifdef VCMI_ANDROID
#include "lib/CAndroidVMHelper.h"
@ -839,7 +839,7 @@ static bool recreateWindow(int w, int h, int bpp, bool fullscreen, int displayIn
}
#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
#ifdef VCMI_ENDIAN_BIG
int bmask = 0xff000000;
int gmask = 0x00ff0000;
int rmask = 0x0000ff00;
@ -949,7 +949,7 @@ static void handleEvent(SDL_Event & ev)
}
else if(ev.type == SDL_USEREVENT)
{
switch(ev.user.code)
switch(static_cast<EUserEvent>(ev.user.code))
{
case EUserEvent::FORCE_QUIT:
{
@ -1050,7 +1050,7 @@ static void handleEvent(SDL_Event & ev)
static void mainLoop()
{
SettingsListener resChanged = settings.listen["video"]["fullscreen"];
resChanged([](const JsonNode &newState){ CGuiHandler::pushSDLEvent(SDL_USEREVENT, EUserEvent::FULLSCREEN_TOGGLED); });
resChanged([](const JsonNode &newState){ CGuiHandler::pushUserEvent(EUserEvent::FULLSCREEN_TOGGLED); });
inGuiThread.reset(new bool(true));
GH.mainFPSmng->init();

View File

@ -54,6 +54,7 @@ set(client_SRCS
render/CFadeAnimation.cpp
render/Canvas.cpp
render/ColorFilter.cpp
render/Colors.cpp
render/Graphics.cpp
render/IFont.cpp
@ -140,6 +141,7 @@ set(client_HEADERS
gui/CIntObject.h
gui/CursorHandler.h
gui/InterfaceObjectConfigurable.h
gui/MouseButton.h
gui/NotificationHandler.h
gui/TextAlignment.h
@ -164,6 +166,7 @@ set(client_HEADERS
render/CFadeAnimation.h
render/Canvas.h
render/ColorFilter.h
render/Colors.h
render/Graphics.h
render/ICursor.h
render/IFont.h

View File

@ -23,6 +23,7 @@
#include "gui/CursorHandler.h"
#include "windows/CKingdomInterface.h"
#include "CGameInfo.h"
#include "CMT.h"
#include "windows/CHeroWindow.h"
#include "windows/CCreatureWindow.h"
#include "windows/CQuestLog.h"
@ -87,8 +88,6 @@
return; \
RETURN_IF_QUICK_COMBAT
using namespace CSDL_Ext;
extern std::queue<SDL_Event> SDLEventsQueue;
extern boost::mutex eventsM;
boost::recursive_mutex * CPlayerInterface::pim = new boost::recursive_mutex;
@ -1043,7 +1042,7 @@ void CPlayerInterface::showComp(const Component &comp, std::string message)
void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<Component> & components, int soundID)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
if (settings["session"]["autoSkip"].Bool() && !LOCPLINT->shiftPressed())
if (settings["session"]["autoSkip"].Bool() && !GH.isKeyboardShiftDown())
{
return;
}
@ -1067,7 +1066,7 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
LOG_TRACE_PARAMS(logGlobal, "player=%s, text=%s, is LOCPLINT=%d", playerID % text % (this==LOCPLINT));
waitWhileDialog();
if (settings["session"]["autoSkip"].Bool() && !LOCPLINT->shiftPressed())
if (settings["session"]["autoSkip"].Bool() && !GH.isKeyboardShiftDown())
{
return;
}
@ -1328,16 +1327,6 @@ void CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
boost::thread moveHeroTask(std::bind(&CPlayerInterface::doMoveHero,this,h,path));
}
bool CPlayerInterface::shiftPressed() const
{
return isShiftKeyDown();
}
bool CPlayerInterface::altPressed() const
{
return isAltKeyDown();
}
void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
@ -1558,11 +1547,6 @@ void CPlayerInterface::playerBlocked(int reason, bool start)
}
}
bool CPlayerInterface::ctrlPressed() const
{
return isCtrlKeyDown();
}
const CArmedInstance * CPlayerInterface::getSelection()
{
return currentSelection;
@ -1604,7 +1588,7 @@ void CPlayerInterface::update()
if (!adventureInt || adventureInt->isActive())
GH.simpleRedraw();
else if((adventureInt->swipeEnabled && adventureInt->swipeMovementRequested) || adventureInt->scrollingDir)
else if((adventureInt->swipeEnabled && adventureInt->swipeMovementRequested) || (adventureInt->scrollingDir && GH.isKeyboardCtrlDown()))
GH.totalRedraw(); //player forces map scrolling though interface is disabled
else
GH.simpleRedraw();
@ -1990,7 +1974,7 @@ void CPlayerInterface::acceptTurn()
adventureInt->updateNextHero(nullptr);
adventureInt->showAll(screen);
if(settings["session"]["autoSkip"].Bool() && !LOCPLINT->shiftPressed())
if(settings["session"]["autoSkip"].Bool() && !GH.isKeyboardShiftDown())
{
if(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt().get()))
iw->close();
@ -2154,12 +2138,7 @@ void CPlayerInterface::requestReturningToMainMenu(bool won)
if(won && cb->getStartInfo()->campState)
CSH->startCampaignScenario(cb->getStartInfo()->campState);
else
sendCustomEvent(EUserEvent::RETURN_TO_MAIN_MENU);
}
void CPlayerInterface::sendCustomEvent( int code )
{
CGuiHandler::pushSDLEvent(SDL_USEREVENT, code);
GH.pushUserEvent(EUserEvent::RETURN_TO_MAIN_MENU);
}
void CPlayerInterface::askToAssembleArtifact(const ArtifactLocation &al)
@ -2283,7 +2262,7 @@ void CPlayerInterface::waitForAllDialogs(bool unlockPim)
void CPlayerInterface::proposeLoadingGame()
{
showYesNoDialog(CGI->generaltexth->allTexts[68], [this](){ sendCustomEvent(EUserEvent::RETURN_TO_MENU_LOAD); }, nullptr);
showYesNoDialog(CGI->generaltexth->allTexts[68], [](){ GH.pushUserEvent(EUserEvent::RETURN_TO_MENU_LOAD); }, nullptr);
}
CPlayerInterface::SpellbookLastSetting::SpellbookLastSetting()

View File

@ -213,9 +213,6 @@ public:
void heroKilled(const CGHeroInstance* hero);
void waitWhileDialog(bool unlockPim = true);
void waitForAllDialogs(bool unlockPim = true);
bool shiftPressed() const; //determines if shift key is pressed (left or right or both)
bool ctrlPressed() const; //determines if ctrl key is pressed (left or right or both)
bool altPressed() const; //determines if alt key is pressed (left or right or both)
void redrawHeroWin(const CGHeroInstance * hero);
void openTownWindow(const CGTownInstance * town); //shows townscreen
void openHeroWindow(const CGHeroInstance * hero); //shows hero window with given hero
@ -243,7 +240,6 @@ public:
void tryDiggging(const CGHeroInstance *h);
void showShipyardDialogOrProblemPopup(const IShipyard *obj); //obj may be town or shipyard;
void requestReturningToMainMenu(bool won);
void sendCustomEvent(int code);
void proposeLoadingGame();
// Ambient sounds

View File

@ -60,8 +60,6 @@
#include <windows.h>
#endif
#include <SDL_events.h>
template<typename T> class CApplyOnLobby;
const std::string CServerHandler::localhostAddress{"127.0.0.1"};
@ -655,14 +653,10 @@ void CServerHandler::endGameplay(bool closeConnection, bool restart)
void CServerHandler::startCampaignScenario(std::shared_ptr<CCampaignState> cs)
{
SDL_Event event;
event.type = SDL_USEREVENT;
event.user.code = EUserEvent::CAMPAIGN_START_SCENARIO;
if(cs)
event.user.data1 = CMemorySerializer::deepCopy(*cs.get()).release();
GH.pushUserEvent(EUserEvent::CAMPAIGN_START_SCENARIO, CMemorySerializer::deepCopy(*cs.get()).release());
else
event.user.data1 = CMemorySerializer::deepCopy(*si->campState.get()).release();
SDL_PushEvent(&event);
GH.pushUserEvent(EUserEvent::CAMPAIGN_START_SCENARIO, CMemorySerializer::deepCopy(*si->campState.get()).release());
}
void CServerHandler::showServerError(std::string txt)
@ -824,7 +818,7 @@ void CServerHandler::threadHandleConnection()
if(client)
{
state = EClientState::DISCONNECTING;
CGuiHandler::pushSDLEvent(SDL_USEREVENT, EUserEvent::RETURN_TO_MAIN_MENU);
CGuiHandler::pushUserEvent(EUserEvent::RETURN_TO_MAIN_MENU);
}
else
{

View File

@ -10,6 +10,7 @@
#include "StdInc.h"
#include "CVideoHandler.h"
#include "CMT.h"
#include "gui/CGuiHandler.h"
#include "renderSDL/SDL_Extensions.h"
#include "CPlayerInterface.h"

View File

@ -31,6 +31,7 @@
#include "../widgets/TextControls.h"
#include "../widgets/Buttons.h"
#include "../windows/SettingsMainContainer.h"
#include "../CMT.h"
#include "../../CCallback.h"
#include "../../lib/CConfigHandler.h"
@ -43,9 +44,6 @@
#include "../../lib/UnlockGuard.h"
#include "../../lib/TerrainHandler.h"
#include <SDL_surface.h>
#include <SDL_events.h>
#define ADVOPT (conf.go()->ac)
std::shared_ptr<CAdvMapInt> adventureInt;
@ -91,8 +89,8 @@ CAdvMapInt::CAdvMapInt():
swipeTargetPosition(int3(-1, -1, -1))
{
pos.x = pos.y = 0;
pos.w = screen->w;
pos.h = screen->h;
pos.w = GH.screenDimensions().x;
pos.h = GH.screenDimensions().y;
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);
@ -138,7 +136,7 @@ CAdvMapInt::CAdvMapInt():
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;
int panelSpaceBottom = GH.screenDimensions().y - resdatabar.pos.h - 4;
panelMain = std::make_shared<CAdvMapPanel>(nullptr, Point(0, 0));
// TODO correct drawing position
@ -159,7 +157,7 @@ CAdvMapInt::CAdvMapInt():
// 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.x = GH.screenDimensions().x - 73;
worldViewBackConfig.y = 343 + 195;
worldViewBackConfig.playerColoured = false;
panelWorldView->addChildToPanel(
@ -167,7 +165,7 @@ CAdvMapInt::CAdvMapInt():
config::ButtonInfo worldViewPuzzleConfig = config::ButtonInfo();
worldViewPuzzleConfig.defName = "VWPUZ.DEF";
worldViewPuzzleConfig.x = screen->w - 188;
worldViewPuzzleConfig.x = GH.screenDimensions().x - 188;
worldViewPuzzleConfig.y = 343 + 195;
worldViewPuzzleConfig.playerColoured = false;
panelWorldView->addChildToPanel( // no help text for this one
@ -176,7 +174,7 @@ CAdvMapInt::CAdvMapInt():
config::ButtonInfo worldViewScale1xConfig = config::ButtonInfo();
worldViewScale1xConfig.defName = "VWMAG1.DEF";
worldViewScale1xConfig.x = screen->w - 191;
worldViewScale1xConfig.x = GH.screenDimensions().x - 191;
worldViewScale1xConfig.y = 23 + 195;
worldViewScale1xConfig.playerColoured = false;
panelWorldView->addChildToPanel( // help text is wrong for this button
@ -184,7 +182,7 @@ CAdvMapInt::CAdvMapInt():
config::ButtonInfo worldViewScale2xConfig = config::ButtonInfo();
worldViewScale2xConfig.defName = "VWMAG2.DEF";
worldViewScale2xConfig.x = screen->w - 191 + 63;
worldViewScale2xConfig.x = GH.screenDimensions().x- 191 + 63;
worldViewScale2xConfig.y = 23 + 195;
worldViewScale2xConfig.playerColoured = false;
panelWorldView->addChildToPanel( // help text is wrong for this button
@ -192,7 +190,7 @@ CAdvMapInt::CAdvMapInt():
config::ButtonInfo worldViewScale4xConfig = config::ButtonInfo();
worldViewScale4xConfig.defName = "VWMAG4.DEF";
worldViewScale4xConfig.x = screen->w - 191 + 126;
worldViewScale4xConfig.x = GH.screenDimensions().x- 191 + 126;
worldViewScale4xConfig.y = 23 + 195;
worldViewScale4xConfig.playerColoured = false;
panelWorldView->addChildToPanel( // help text is wrong for this button
@ -201,7 +199,7 @@ CAdvMapInt::CAdvMapInt():
config::ButtonInfo worldViewUndergroundConfig = config::ButtonInfo();
worldViewUndergroundConfig.defName = "IAM010.DEF";
worldViewUndergroundConfig.additionalDefs.push_back("IAM003.DEF");
worldViewUndergroundConfig.x = screen->w - 115;
worldViewUndergroundConfig.x = GH.screenDimensions().x - 115;
worldViewUndergroundConfig.y = 343 + 195;
worldViewUndergroundConfig.playerColoured = true;
worldViewUnderground = makeButton(294, std::bind(&CAdvMapInt::fswitchLevel,this), worldViewUndergroundConfig, SDLK_u);
@ -617,7 +615,7 @@ void CAdvMapInt::handleMapScrollingUpdate()
int scrollSpeed = static_cast<int>(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) || CSDL_Ext::isCtrlKeyDown()))
&& GH.isKeyboardCtrlDown())
{
if((scrollingDir & LEFT) && (position.x > -CGI->mh->frameW))
position.x--;
@ -713,21 +711,46 @@ void CAdvMapInt::centerOn(const CGObjectInstance * obj, bool fade)
centerOn(obj->getSightCenter(), fade);
}
void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
void CAdvMapInt::keyReleased(const SDL_Keycode &key)
{
if (mode == EAdvMapMode::WORLD_VIEW)
return;
switch (key)
{
case SDLK_s:
if(isActive())
GH.pushIntT<CSavingScreen>();
return;
default:
{
auto direction = keyToMoveDirection(key);
if (!direction)
return;
ui8 Dir = (direction->x<0 ? LEFT : 0) |
(direction->x>0 ? RIGHT : 0) |
(direction->y<0 ? UP : 0) |
(direction->y>0 ? DOWN : 0) ;
scrollingDir &= ~Dir;
}
}
}
void CAdvMapInt::keyPressed(const SDL_Keycode & 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)
switch(key)
{
case SDLK_g:
if(key.state != SDL_PRESSED || GH.topInt()->type & BLOCK_ADV_HOTKEYS)
if(GH.topInt()->type & BLOCK_ADV_HOTKEYS)
return;
{
@ -751,13 +774,9 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
if(isActive())
LOCPLINT->proposeLoadingGame();
return;
case SDLK_s:
if(isActive() && key.type == SDL_KEYUP)
GH.pushIntT<CSavingScreen>();
return;
case SDLK_d:
{
if(h && isActive() && LOCPLINT->makingTurn && key.state == SDL_PRESSED)
if(h && isActive() && LOCPLINT->makingTurn)
LOCPLINT->tryDiggging(h);
return;
}
@ -770,17 +789,17 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
LOCPLINT->viewWorldMap();
return;
case SDLK_r:
if(isActive() && LOCPLINT->ctrlPressed())
if(isActive() && GH.isKeyboardCtrlDown())
{
LOCPLINT->showYesNoDialog(CGI->generaltexth->translate("vcmi.adventureMap.confirmRestartGame"),
[](){ LOCPLINT->sendCustomEvent(EUserEvent::RESTART_GAME); }, nullptr);
[](){ GH.pushUserEvent(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)
if(h)
{
auto unlockPim = vstd::makeUnlockGuard(*CPlayerInterface::pim);
//TODO!!!!!!! possible freeze, when GS mutex is locked and network thread can't apply package
@ -793,7 +812,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
return;
case SDLK_RETURN:
{
if(!isActive() || !selection || key.state != SDL_PRESSED)
if(!isActive() || !selection)
return;
if(h)
LOCPLINT->openHeroWindow(h);
@ -803,7 +822,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
}
case SDLK_ESCAPE:
{
if(isActive() || GH.topInt().get() != this || !spellBeingCasted || key.state != SDL_PRESSED)
if(isActive() || GH.topInt().get() != this || !spellBeingCasted)
return;
leaveCastingMode();
@ -812,10 +831,10 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
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)
if(GH.topInt()->type & BLOCK_ADV_HOTKEYS)
return;
if(LOCPLINT->ctrlPressed()) //CTRL + T => open marketplace
if(GH.isKeyboardCtrlDown()) //CTRL + T => open marketplace
{
//check if we have any marketplace
const CGTownInstance *townWithMarket = nullptr;
@ -841,37 +860,29 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
}
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) };
auto direction = keyToMoveDirection(key);
//numpad arrow
if(CGuiHandler::isArrowKey(k))
k = CGuiHandler::arrowToNum(k);
if (!direction)
return;
k -= SDLK_KP_1;
ui8 Dir = (direction->x<0 ? LEFT : 0) |
(direction->x>0 ? RIGHT : 0) |
(direction->y<0 ? UP : 0) |
(direction->y>0 ? DOWN : 0) ;
if(k < 0 || k > 8)
scrollingDir |= Dir;
//ctrl makes arrow move screen, not hero
if(GH.isKeyboardCtrlDown())
return;
if(!h || !isActive())
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)
if(*direction == Point(0,0))
{
centerOn(h);
return;
@ -879,7 +890,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
CGPath &path = LOCPLINT->paths[h];
terrain.currentPath = &path;
int3 dst = h->visitablePos() + dir;
int3 dst = h->visitablePos() + int3(direction->x, direction->y, 0);
if(dst != verifyPos(dst) || !LOCPLINT->cb->getPathsInfo(h)->getPath(path, dst))
{
terrain.currentPath = nullptr;
@ -895,13 +906,29 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
return;
}
if(Dir && key.state == SDL_PRESSED //arrow is pressed
&& LOCPLINT->ctrlPressed()
)
scrollingDir |= Dir;
else
scrollingDir &= ~Dir;
}
boost::optional<Point> CAdvMapInt::keyToMoveDirection(const SDL_Keycode & key)
{
switch (key) {
case SDLK_DOWN: return Point( 0, +1);
case SDLK_LEFT: return Point(-1, 0);
case SDLK_RIGHT: return Point(+1, 0);
case SDLK_UP: return Point( 0, -1);
case SDLK_KP_1: return Point(-1, +1);
case SDLK_KP_2: return Point( 0, +1);
case SDLK_KP_3: return Point(+1, +1);
case SDLK_KP_4: return Point(-1, 0);
case SDLK_KP_5: return Point( 0, 0);
case SDLK_KP_6: return Point(+1, 0);
case SDLK_KP_7: return Point(-1, -1);
case SDLK_KP_8: return Point( 0, -1);
case SDLK_KP_9: return Point(+1, -1);
}
return boost::none;
}
void CAdvMapInt::handleRightClick(std::string text, tribool down)
{
if(down)
@ -972,7 +999,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView)
heroList.redraw();
}
void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
void CAdvMapInt::mouseMoved( const Point & cursorPosition )
{
#if defined(VCMI_ANDROID) || defined(VCMI_IOS)
if(swipeEnabled)
@ -981,9 +1008,9 @@ 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(!CSDL_Ext::isCtrlKeyDown() && isActive() && sEvent.windowID != 0 && mode == EAdvMapMode::NORMAL)
if(!GH.isKeyboardCtrlDown() && isActive() && mode == EAdvMapMode::NORMAL)
{
if(sEvent.x<15)
if(cursorPosition.x<15)
{
scrollingDir |= LEFT;
}
@ -991,7 +1018,7 @@ void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
{
scrollingDir &= ~LEFT;
}
if(sEvent.x>screen->w-15)
if(cursorPosition.x > GH.screenDimensions().x - 15)
{
scrollingDir |= RIGHT;
}
@ -999,7 +1026,7 @@ void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
{
scrollingDir &= ~RIGHT;
}
if(sEvent.y<15)
if(cursorPosition.y<15)
{
scrollingDir |= UP;
}
@ -1007,7 +1034,7 @@ void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent )
{
scrollingDir &= ~UP;
}
if(sEvent.y>screen->h-15)
if(cursorPosition.y > GH.screenDimensions().y - 15)
{
scrollingDir |= DOWN;
}
@ -1246,7 +1273,7 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
const CGPathNode * pathNode = LOCPLINT->cb->getPathsInfo(hero)->getPathInfo(mapPos);
assert(pathNode);
if(LOCPLINT->altPressed() && pathNode->reachable()) //overwrite status bar text with movement info
if(GH.isKeyboardAltDown() && pathNode->reachable()) //overwrite status bar text with movement info
{
ShowMoveDetailsInStatusbar(*hero, *pathNode);
}

View File

@ -56,6 +56,8 @@ class CAdvMapInt : public CIntObject
//Return object that must be active at this tile (=clickable)
const CGObjectInstance *getActiveObject(const int3 &tile);
boost::optional<Point> keyToMoveDirection(const SDL_Keycode & key);
public:
CAdvMapInt();
@ -158,8 +160,9 @@ public:
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;
void keyPressed(const SDL_Keycode & key) override;
void keyReleased(const SDL_Keycode & key) override;
void mouseMoved (const Point & cursorPosition) override;
bool isActive();
bool isHeroSleeping(const CGHeroInstance *hero);

View File

@ -11,7 +11,7 @@
#include "StdInc.h"
#include "CInGameConsole.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../render/Colors.h"
#include "../CGameInfo.h"
#include "../CMusicHandler.h"
#include "../CPlayerInterface.h"
@ -24,7 +24,6 @@
#include "../../lib/mapObjects/CArmedInstance.h"
#include <SDL_timer.h>
#include <SDL_events.h>
CInGameConsole::CInGameConsole()
: CIntObject(KEYBOARD | TEXTINPUT),
@ -91,13 +90,11 @@ void CInGameConsole::print(const std::string &txt)
}
}
void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key)
void CInGameConsole::keyPressed (const SDL_Keycode & key)
{
if(key.type != SDL_KEYDOWN) return;
if(!captureAllKeys && key != SDLK_TAB) return; //because user is not entering any text
if(!captureAllKeys && key.keysym.sym != SDLK_TAB) return; //because user is not entering any text
switch(key.keysym.sym)
switch(key)
{
case SDLK_TAB:
case SDLK_ESCAPE:
@ -106,7 +103,7 @@ void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key)
{
endEnteringText(false);
}
else if(SDLK_TAB == key.keysym.sym)
else if(SDLK_TAB == key)
{
startEnteringText();
}
@ -178,19 +175,19 @@ void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key)
}
}
void CInGameConsole::textInputed(const SDL_TextInputEvent & event)
void CInGameConsole::textInputed(const std::string & inputtedText)
{
if(!captureAllKeys || enteredText.size() == 0)
return;
enteredText.resize(enteredText.size()-1);
enteredText += event.text;
enteredText += inputtedText;
enteredText += "_";
refreshEnteredText();
}
void CInGameConsole::textEdited(const SDL_TextEditingEvent & event)
void CInGameConsole::textEdited(const std::string & inputtedText)
{
//do nothing here
}

View File

@ -26,10 +26,10 @@ 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 keyPressed(const SDL_Keycode & key) override;
void textInputed(const SDL_TextInputEvent & event) override;
void textEdited(const SDL_TextEditingEvent & event) override;
void textInputed(const std::string & enteredText) override;
void textEdited(const std::string & enteredText) override;
void startEnteringText();
void endEnteringText(bool processEnteredText);

View File

@ -17,6 +17,7 @@
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../gui/CGuiHandler.h"
#include "../render/Colors.h"
#include "../renderSDL/SDL_PixelAccess.h"
#include "../../CCallback.h"
@ -229,9 +230,9 @@ void CMinimap::hover(bool on)
GH.statusbar->clear();
}
void CMinimap::mouseMoved(const SDL_MouseMotionEvent & sEvent)
void CMinimap::mouseMoved(const Point & cursorPosition)
{
if(mouseState(EIntObjMouseBtnType::LEFT))
if(mouseState(MouseButton::LEFT))
moveAdvMapSelection();
}

View File

@ -53,7 +53,7 @@ protected:
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 mouseMoved (const Point & cursorPosition) override;
void moveAdvMapSelection();

View File

@ -12,6 +12,7 @@
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../render/Colors.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../gui/CGuiHandler.h"
#include "../widgets/Images.h"
@ -44,8 +45,6 @@ CResDataBar::CResDataBar(const std::string & defname, int x, int y, int offx, in
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);
}
@ -68,12 +67,23 @@ CResDataBar::CResDataBar()
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;
std::string CResDataBar::buildDateString()
{
std::string pattern = "%s: %d, %s: %d, %s: %d";
auto formatted = boost::format(pattern)
% CGI->generaltexth->translate("core.genrltxt.62") % LOCPLINT->cb->getDate(Date::MONTH)
% CGI->generaltexth->translate("core.genrltxt.63") % LOCPLINT->cb->getDate(Date::WEEK)
% CGI->generaltexth->translate("core.genrltxt.64") % LOCPLINT->cb->getDate(Date::DAY_OF_WEEK);
return boost::str(formatted);
}
void CResDataBar::draw(SDL_Surface * to)
{
//TODO: all this should be labels, but they require proper text update on change
@ -81,15 +91,9 @@ void CResDataBar::draw(SDL_Surface * to)
{
std::string text = boost::lexical_cast<std::string>(LOCPLINT->cb->getResourceAmount(i));
graphics->fonts[FONT_SMALL]->renderTextLeft(to, text, Colors::WHITE, Point(txtpos[i].first,txtpos[i].second));
graphics->fonts[FONT_SMALL]->renderTextLeft(to, text, Colors::WHITE, Point(txtpos[i].first, txtpos[i].second));
}
std::vector<std::string> temp;
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::MONTH)));
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::WEEK)));
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK)));
graphics->fonts[FONT_SMALL]->renderTextLeft(to, CSDL_Ext::processStr(datetext,temp), Colors::WHITE, Point(txtpos[7].first,txtpos[7].second));
graphics->fonts[FONT_SMALL]->renderTextLeft(to, buildDateString(), Colors::WHITE, Point(txtpos[7].first, txtpos[7].second));
}
void CResDataBar::show(SDL_Surface * to)

View File

@ -15,11 +15,12 @@
/// Current date is displayed too
class CResDataBar : public CIntObject
{
std::string buildDateString();
public:
std::shared_ptr<CPicture> background;
std::vector<std::pair<int,int> > txtpos;
std::string datetext;
void clickRight(tribool down, bool previousState) override;
CResDataBar();

View File

@ -22,13 +22,14 @@
#include "../render/IImage.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../widgets/TextControls.h"
#include "../CMT.h"
#include "../../CCallback.h"
#include "../../lib/CConfigHandler.h"
#include "../../lib/mapping/CMap.h"
#include "../../lib/CPathfinder.h"
#include <SDL_events.h>
#include <SDL_surface.h>
#define ADVOPT (conf.go()->ac)
@ -110,32 +111,31 @@ void CTerrainRect::clickMiddle(tribool down, bool previousState)
handleSwipeStateChange((bool)down == true);
}
void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent)
void CTerrainRect::mouseMoved(const Point & cursorPosition)
{
handleHover(sEvent);
handleHover(cursorPosition);
if(!adventureInt->swipeEnabled)
return;
handleSwipeMove(sEvent);
handleSwipeMove(cursorPosition);
}
void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent)
void CTerrainRect::handleSwipeMove(const Point & cursorPosition)
{
#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
{
if(!GH.isMouseButtonPressed() || GH.multifinger) // any "button" is enough on mobile
return;
}
#else
if(!GH.isMouseButtonPressed(MouseButton::MIDDLE)) // swipe only works with middle mouse on other platforms
return;
#endif
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)
if(abs(cursorPosition.x - swipeInitialRealPos.x) > SwipeTouchSlop ||
abs(cursorPosition.y - swipeInitialRealPos.y) > SwipeTouchSlop)
{
isSwiping = true;
}
@ -144,9 +144,9 @@ void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent)
if(isSwiping)
{
adventureInt->swipeTargetPosition.x =
swipeInitialMapPos.x + static_cast<si32>(swipeInitialRealPos.x - sEvent.x) / 32;
swipeInitialMapPos.x + static_cast<si32>(swipeInitialRealPos.x - cursorPosition.x) / 32;
adventureInt->swipeTargetPosition.y =
swipeInitialMapPos.y + static_cast<si32>(swipeInitialRealPos.y - sEvent.y) / 32;
swipeInitialMapPos.y + static_cast<si32>(swipeInitialRealPos.y - cursorPosition.y) / 32;
adventureInt->swipeMovementRequested = true;
}
}
@ -155,7 +155,7 @@ bool CTerrainRect::handleSwipeStateChange(bool btnPressed)
{
if(btnPressed)
{
swipeInitialRealPos = int3(GH.getCursorPosition().x, GH.getCursorPosition().y, 0);
swipeInitialRealPos = Point(GH.getCursorPosition().x, GH.getCursorPosition().y);
swipeInitialMapPos = int3(adventureInt->position);
return true;
}
@ -167,9 +167,9 @@ bool CTerrainRect::handleSwipeStateChange(bool btnPressed)
return false;
}
void CTerrainRect::handleHover(const SDL_MouseMotionEvent &sEvent)
void CTerrainRect::handleHover(const Point & cursorPosition)
{
int3 tHovered = whichTileIsIt(sEvent.x, sEvent.y);
int3 tHovered = whichTileIsIt(cursorPosition.x, cursorPosition.y);
int3 pom = adventureInt->verifyPos(tHovered);
if(tHovered != pom) //tile outside the map
@ -277,17 +277,17 @@ void CTerrainRect::showPath(const Rect & extRect, SDL_Surface * to)
}
else if(hvx<0)
{
Rect srcRect = CSDL_Ext::genRect(arrow->height() - hvy, arrow->width(), 0, 0);
Rect srcRect (Point(0, 0), Point(arrow->height() - hvy, arrow->width()));
arrow->draw(to, x + moveX, y + moveY, &srcRect);
}
else if (hvy<0)
{
Rect srcRect = CSDL_Ext::genRect(arrow->height(), arrow->width() - hvx, 0, 0);
Rect srcRect (Point(0, 0), Point(arrow->height(), arrow->width() - hvx));
arrow->draw(to, x + moveX, y + moveY, &srcRect);
}
else
{
Rect srcRect = CSDL_Ext::genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0);
Rect srcRect (Point(0, 0), Point(arrow->height() - hvy, arrow->width() - hvx));
arrow->draw(to, x + moveX, y + moveY, &srcRect);
}
}
@ -299,17 +299,17 @@ void CTerrainRect::showPath(const Rect & extRect, SDL_Surface * to)
}
else if(hvx<0)
{
Rect srcRect = CSDL_Ext::genRect(arrow->height() - hvy, arrow->width(), 0, 0);
Rect srcRect (Point(0, 0), Point(arrow->height() - hvy, arrow->width()));
arrow->draw(to, x, y, &srcRect);
}
else if (hvy<0)
{
Rect srcRect = CSDL_Ext::genRect(arrow->height(), arrow->width() - hvx, 0, 0);
Rect srcRect (Point(0, 0), Point(arrow->height(), arrow->width() - hvx));
arrow->draw(to, x, y, &srcRect);
}
else
{
Rect srcRect = CSDL_Ext::genRect(arrow->height() - hvy, arrow->width() - hvx, 0, 0);
Rect srcRect (Point(0, 0), Point(arrow->height() - hvy, arrow->width() - hvx));
arrow->draw(to, x, y, &srcRect);
}
}

View File

@ -27,12 +27,12 @@ class CTerrainRect : public CIntObject
std::shared_ptr<CFadeAnimation> fadeAnim;
int3 swipeInitialMapPos;
int3 swipeInitialRealPos;
Point swipeInitialRealPos;
bool isSwiping;
static constexpr float SwipeTouchSlop = 16.0f;
void handleHover(const SDL_MouseMotionEvent & sEvent);
void handleSwipeMove(const SDL_MouseMotionEvent & sEvent);
void handleHover(const Point & cursorPosition);
void handleSwipeMove(const Point & cursorPosition);
/// handles start/finish of swipe (press/release of corresponding button); returns true if state change was handled
bool handleSwipeStateChange(bool btnPressed);
public:
@ -48,7 +48,7 @@ public:
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 mouseMoved (const Point & cursorPosition) override;
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;
void showAnim(SDL_Surface * to);

View File

@ -13,6 +13,7 @@
#include "../render/CAnimation.h"
#include "../render/CFadeAnimation.h"
#include "../render/Colors.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../CGameInfo.h"
#include "../render/Graphics.h"

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,10 @@
VCMI_LIB_NAMESPACE_BEGIN
class BattleAction;
namespace spells {
class Caster;
enum class Mode;
}
VCMI_LIB_NAMESPACE_END
@ -34,65 +38,87 @@ class BattleActionsController
/// all actions possible to call at the moment by player
std::vector<PossiblePlayerBattleAction> possibleActions;
/// actions possible to take on hovered hex
std::vector<PossiblePlayerBattleAction> localActions;
/// these actions display message in case of illegal target
std::vector<PossiblePlayerBattleAction> illegalActions;
/// action that will be performed on l-click
PossiblePlayerBattleAction currentAction;
/// last action chosen (and saved) by player
PossiblePlayerBattleAction selectedAction;
/// if there are not possible actions to choose from, this action should be show as "illegal" in UI
PossiblePlayerBattleAction illegalAction;
/// if true, stack currently aims to cats a spell
bool creatureCasting;
/// if true, player is choosing destination for his spell - only for GUI / console
bool spellDestSelectMode;
/// spell for which player is choosing destination
std::shared_ptr<BattleAction> spellToCast;
/// spell for which player is choosing destination, pointer for convenience
const CSpell *currentSpell;
/// spell for which player's hero is choosing destination
std::shared_ptr<BattleAction> heroSpellToCast;
/// cached message that was set by this class in status bar
std::string currentConsoleMsg;
/// if true, active stack could possibly cast some target spell
const CSpell * creatureSpellToCast;
bool isCastingPossibleHere (const CStack *sactive, const CStack *shere, BattleHex myNumber);
bool canStackMoveHere (const CStack *sactive, BattleHex MyNumber) const; //TODO: move to BattleState / callback
std::vector<PossiblePlayerBattleAction> getPossibleActionsForStack (const CStack *stack) const; //called when stack gets its turn
void reorderPossibleActionsPriority(const CStack * stack, MouseHoveredHexContext context);
bool actionIsLegal(PossiblePlayerBattleAction action, BattleHex hoveredHex);
void actionSetCursor(PossiblePlayerBattleAction action, BattleHex hoveredHex);
void actionSetCursorBlocked(PossiblePlayerBattleAction action, BattleHex hoveredHex);
std::string actionGetStatusMessage(PossiblePlayerBattleAction action, BattleHex hoveredHex);
std::string actionGetStatusMessageBlocked(PossiblePlayerBattleAction action, BattleHex hoveredHex);
void actionRealize(PossiblePlayerBattleAction action, BattleHex hoveredHex);
PossiblePlayerBattleAction selectAction(BattleHex myNumber);
const CStack * getStackForHex(BattleHex myNumber) ;
/// attempts to initialize spellcasting action for stack
/// will silently return if stack is not a spellcaster
void tryActivateStackSpellcasting(const CStack *casterStack);
/// returns spell that is currently being cast by hero or nullptr if none
const CSpell * getHeroSpellToCast() const;
/// if current stack is spellcaster, returns spell being cast, or null othervice
const CSpell * getStackSpellToCast( ) const;
/// returns true if current stack is a spellcaster
bool isActiveStackSpellcaster() const;
public:
BattleActionsController(BattleInterface & owner);
/// initialize list of potential actions for new active stack
void activateStack();
/// initialize potential actions for spells that can be cast by active stack
/// returns true if UI is currently in target selection mode
bool spellcastingModeActive() const;
/// returns true if one of the following is true:
/// - we are casting spell by hero
/// - we are casting spell by creature in targeted mode (F hotkey)
/// - current creature is spellcaster and preferred action for current hex is spellcast
bool currentActionSpellcasting(BattleHex hoveredHex);
/// enter targeted spellcasting mode for creature, e.g. via "F" hotkey
void enterCreatureCastingMode();
/// initialize potential actions for selected spell
/// initialize hero spellcasting mode, e.g. on selecting spell in spellbook
void castThisSpell(SpellID spellID);
/// ends casting spell (eg. when spell has been cast or canceled)
void endCastingSpell();
/// update UI (e.g. status bar/cursor) according to new active hex
void handleHex(BattleHex myNumber, int eventType);
/// update cursor and status bar according to new active hex
void onHexHovered(BattleHex hoveredHex);
/// returns currently selected spell or SpellID::NONE on error
SpellID selectedSpell() const;
/// called when cursor is no longer over battlefield and cursor/battle log should be reset
void onHoverEnded();
/// performs action according to selected hex
void onHexLeftClicked(BattleHex clickedHex);
/// performs action according to selected hex
void onHexRightClicked(BattleHex clickedHex);
const spells::Caster * getCurrentSpellcaster() const;
const CSpell * getCurrentSpell() const;
spells::Mode getCurrentCastMode() const;
/// returns true if UI is currently in target selection mode
bool spellcastingModeActive() const;
/// methods to work with array of possible actions, needed to control special creatures abilities
const std::vector<PossiblePlayerBattleAction> & getPossibleActions() const;
void removePossibleAction(PossiblePlayerBattleAction);

View File

@ -34,6 +34,8 @@
#include "../../lib/CStack.h"
#include "../../lib/spells/ISpellMechanics.h"
#include <SDL_events.h>
BattleFieldController::BattleFieldController(BattleInterface & owner):
owner(owner)
{
@ -76,20 +78,11 @@ BattleFieldController::BattleFieldController(BattleInterface & owner):
backgroundWithHexes = std::make_unique<Canvas>(Point(background->width(), background->height()));
for (int h = 0; h < GameConstants::BFIELD_SIZE; ++h)
{
auto hex = std::make_shared<ClickableHex>();
hex->myNumber = h;
hex->pos = hexPositionAbsolute(h);
hex->myInterface = &owner;
bfield.push_back(hex);
}
auto accessibility = owner.curInt->cb->getAccesibility();
for(int i = 0; i < accessibility.size(); i++)
stackCountOutsideHexes[i] = (accessibility[i] == EAccessibility::ACCESSIBLE);
addUsedEvents(MOVE);
addUsedEvents(LCLICK | RCLICK | MOVE);
LOCPLINT->cingconsole->pos = this->pos;
}
@ -105,13 +98,40 @@ void BattleFieldController::createHeroes()
owner.defendingHero = std::make_shared<BattleHero>(owner, owner.defendingHeroInstance, true);
}
void BattleFieldController::mouseMoved(const SDL_MouseMotionEvent &event)
void BattleFieldController::mouseMoved(const Point & cursorPosition)
{
BattleHex selectedHex = getHoveredHex();
if (!pos.isInside(cursorPosition))
{
owner.actionsController->onHoverEnded();
return;
}
owner.actionsController->handleHex(selectedHex, MOVE);
BattleHex selectedHex = getHoveredHex();
owner.actionsController->onHexHovered(selectedHex);
}
void BattleFieldController::clickLeft(tribool down, bool previousState)
{
if(!down)
{
BattleHex selectedHex = getHoveredHex();
if (selectedHex != BattleHex::INVALID)
owner.actionsController->onHexLeftClicked(selectedHex);
}
}
void BattleFieldController::clickRight(tribool down, bool previousState)
{
if(down)
{
BattleHex selectedHex = getHoveredHex();
if (selectedHex != BattleHex::INVALID)
owner.actionsController->onHexRightClicked(selectedHex);
}
}
void BattleFieldController::renderBattlefield(Canvas & canvas)
{
@ -233,19 +253,9 @@ std::set<BattleHex> BattleFieldController::getHighlightedHexesSpellRange()
const spells::Caster *caster = nullptr;
const CSpell *spell = nullptr;
spells::Mode mode = spells::Mode::HERO;
if(owner.actionsController->spellcastingModeActive())//hero casts spell
{
spell = owner.actionsController->selectedSpell().toSpell();
caster = owner.getActiveHero();
}
else if(owner.stacksController->activeStackSpellToCast() != SpellID::NONE)//stack casts spell
{
spell = SpellID(owner.stacksController->activeStackSpellToCast()).toSpell();
caster = owner.stacksController->getActiveStack();
mode = spells::Mode::CREATURE_ACTIVE;
}
spells::Mode mode = owner.actionsController->getCurrentCastMode();
spell = owner.actionsController->getCurrentSpell();
caster = owner.actionsController->getCurrentSpellcaster();
if(caster && spell) //when casting spell
{
@ -310,7 +320,10 @@ void BattleFieldController::showHighlightedHexes(Canvas & canvas)
std::set<BattleHex> hoveredSpell = getHighlightedHexesSpellRange();
std::set<BattleHex> hoveredMove = getHighlightedHexesMovementTarget();
auto const & hoveredMouse = owner.actionsController->spellcastingModeActive() ? hoveredSpell : hoveredMove;
if (getHoveredHex() == BattleHex::INVALID)
return;
auto const & hoveredMouse = owner.actionsController->currentActionSpellcasting(getHoveredHex()) ? hoveredSpell : hoveredMove;
for(int b=0; b<GameConstants::BFIELD_SIZE; ++b)
{
@ -355,9 +368,31 @@ bool BattleFieldController::isPixelInHex(Point const & position)
BattleHex BattleFieldController::getHoveredHex()
{
for ( auto const & hex : bfield)
if (hex->hovered && hex->strictHovered)
return hex->myNumber;
Point hoverPos = GH.getCursorPosition();
if (owner.attackingHero)
{
if (owner.attackingHero->pos.isInside(hoverPos))
return BattleHex::HERO_ATTACKER;
}
if (owner.defendingHero)
{
if (owner.attackingHero->pos.isInside(hoverPos))
return BattleHex::HERO_DEFENDER;
}
for (int h = 0; h < GameConstants::BFIELD_SIZE; ++h)
{
Rect hexPosition = hexPositionAbsolute(h);
if (!hexPosition.isInside(hoverPos))
continue;
if (isPixelInHex(hoverPos - hexPosition.topLeft()))
return h;
}
return BattleHex::INVALID;
}
@ -520,7 +555,7 @@ BattleHex BattleFieldController::fromWhichHexAttack(BattleHex attackTarget)
}
default:
assert(0);
return attackTarget.cloneInDirection(BattleHex::LEFT);
return BattleHex::INVALID;
}
}
}

View File

@ -20,7 +20,6 @@ class Point;
VCMI_LIB_NAMESPACE_END
class ClickableHex;
class BattleHero;
class Canvas;
class IImage;
@ -50,8 +49,6 @@ class BattleFieldController : public CIntObject
/// hexes that when in front of a unit cause it's amount box to move back
std::array<bool, GameConstants::BFIELD_SIZE> stackCountOutsideHexes;
std::vector<std::shared_ptr<ClickableHex>> bfield;
void showHighlightedHex(Canvas & to, BattleHex hex, bool darkBorder);
std::set<BattleHex> getHighlightedHexesStackRange();
@ -65,10 +62,12 @@ class BattleFieldController : public CIntObject
BattleHex::EDir selectAttackDirection(BattleHex myNumber, const Point & point);
void mouseMoved(const SDL_MouseMotionEvent &event) override;
void mouseMoved(const Point & cursorPosition) override;
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void showAll(SDL_Surface * to) override;
void show(SDL_Surface * to) override;
public:
BattleFieldController(BattleInterface & owner);

View File

@ -54,7 +54,6 @@ BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet *
, attackerInt(att)
, defenderInt(defen)
, curInt(att)
, myTurn(false)
, moveSoundHander(-1)
{
for ( auto & event : animationEvents)
@ -249,7 +248,6 @@ void BattleInterface::sendCommand(BattleAction *& command, const CStack * actor)
if(!tacticsMode)
{
logGlobal->trace("Setting command for %s", (actor ? actor->nodeName() : "hero"));
myTurn = false;
stacksController->setActiveStack(nullptr);
givenCommand.setn(command);
}
@ -260,6 +258,7 @@ void BattleInterface::sendCommand(BattleAction *& command, const CStack * actor)
stacksController->setActiveStack(nullptr);
//next stack will be activated when action ends
}
CCS->curh->set(Cursor::Combat::POINTER);
}
const CGHeroInstance * BattleInterface::getActiveHero()
@ -499,7 +498,6 @@ void BattleInterface::displaySpellHit(const CSpell * spell, BattleHex destinatio
displaySpellAnimationQueue(spell, spell->animationInfo.hit, destinationTile, true);
}
CPlayerInterface *BattleInterface::getCurrentPlayerInterface() const
{
return curInt.get();
@ -522,7 +520,6 @@ void BattleInterface::activateStack()
if(!s)
return;
myTurn = true;
windowObject->updateQueue();
windowObject->blockUI(false);
fieldController->redrawBackgroundWithHexes();
@ -530,6 +527,11 @@ void BattleInterface::activateStack()
GH.fakeMouseMove();
}
bool BattleInterface::makingTurn() const
{
return stacksController->getActiveStack() != nullptr;
}
void BattleInterface::endAction(const BattleAction* action)
{
const CStack *stack = curInt->cb->battleGetStackByID(action->stackNumber);

View File

@ -37,7 +37,6 @@ class Canvas;
class BattleResultWindow;
class StackQueue;
class CPlayerInterface;
class ClickableHex;
class CAnimation;
struct BattleEffect;
class IImage;
@ -146,7 +145,8 @@ public:
static CondSh<BattleAction *> givenCommand; //data != nullptr if we have i.e. moved current unit
bool myTurn; //if true, interface is active (commands can be ordered)
bool makingTurn() const;
int moveSoundHander; // sound handler used when moving a unit
BattleInterface(const CCreatureSet *army1, const CCreatureSet *army2, const CGHeroInstance *hero1, const CGHeroInstance *hero2, std::shared_ptr<CPlayerInterface> att, std::shared_ptr<CPlayerInterface> defen, std::shared_ptr<CPlayerInterface> spectatorInt = nullptr);

View File

@ -30,10 +30,10 @@
#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 "../renderSDL/SDL_Extensions.h"
#include "../../CCallback.h"
#include "../../lib/CStack.h"
@ -48,9 +48,6 @@
#include "../../lib/CondSh.h"
#include "../../lib/mapObjects/CGTownInstance.h"
#include <SDL_surface.h>
#include <SDL_events.h>
void BattleConsole::showAll(SDL_Surface * to)
{
CIntObject::showAll(to);
@ -163,12 +160,12 @@ void BattleConsole::setEnteringMode(bool on)
if (on)
{
assert(enteringText == false);
CSDL_Ext::startTextInput(pos);
GH.startTextInput(pos);
}
else
{
assert(enteringText == true);
CSDL_Ext::stopTextInput();
GH.stopTextInput();
}
enteringText = on;
redraw();
@ -274,50 +271,29 @@ void BattleHero::setPhase(EHeroAnimType newPhase)
nextPhase = EHeroAnimType::HOLDING;
}
void BattleHero::hover(bool on)
{
//TODO: BROKEN CODE
if (on)
CCS->curh->set(Cursor::Combat::HERO);
else
CCS->curh->set(Cursor::Combat::POINTER);
}
void BattleHero::clickLeft(tribool down, bool previousState)
void BattleHero::heroLeftClicked()
{
if(owner.actionsController->spellcastingModeActive()) //we are casting a spell
return;
if(boost::logic::indeterminate(down))
return;
if(!hero || down || !owner.myTurn)
if(!hero || !owner.makingTurn())
return;
if(owner.getCurrentPlayerInterface()->cb->battleCanCastSpell(hero, spells::Mode::HERO) == ESpellCastProblem::OK) //check conditions
{
BattleHex hoveredHex = owner.fieldController->getHoveredHex();
//do nothing when any hex is hovered - hero's animation overlaps battlefield
if ( hoveredHex != BattleHex::INVALID )
return;
CCS->curh->set(Cursor::Map::POINTER);
GH.pushIntT<CSpellWindow>(hero, owner.getCurrentPlayerInterface());
}
}
void BattleHero::clickRight(tribool down, bool previousState)
void BattleHero::heroRightClicked()
{
if(boost::logic::indeterminate(down))
return;
Point windowPosition;
windowPosition.x = (!defender) ? owner.fieldController->pos.left() + 1 : owner.fieldController->pos.right() - 79;
windowPosition.y = owner.fieldController->pos.y + 135;
InfoAboutHero targetHero;
if(down && (owner.myTurn || settings["session"]["spectate"].Bool()))
if(owner.makingTurn() || settings["session"]["spectate"].Bool())
{
auto h = defender ? owner.defendingHeroInstance : owner.attackingHeroInstance;
targetHero.initFromHero(h, InfoAboutHero::EInfoLevel::INBATTLE);
@ -374,8 +350,6 @@ BattleHero::BattleHero(const BattleInterface & owner, const CGHeroInstance * her
flagAnimation->preload();
flagAnimation->playerColored(hero->tempOwner);
addUsedEvents(LCLICK | RCLICK | HOVER);
switchToNextPhase();
play();
}
@ -427,9 +401,9 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
{
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
pos = CSDL_Ext::genRect(561, 470, (screen->w - 800)/2 + 165, (screen->h - 600)/2 + 19);
background = std::make_shared<CPicture>("CPRESULT");
background->colorize(owner.playerID);
pos = center(background->pos);
exit = std::make_shared<CButton>(Point(384, 505), "iok6432.def", std::make_pair("", ""), [&](){ bExitf();}, SDLK_RETURN);
exit->setBorderColor(Colors::METALLIC_GOLD);
@ -591,7 +565,7 @@ void BattleResultWindow::activate()
void BattleResultWindow::show(SDL_Surface * to)
{
CIntObject::show(to);
CCS->videoh->update(pos.x + 107, pos.y + 70, screen, true, false);
CCS->videoh->update(pos.x + 107, pos.y + 70, to, true, false);
}
void BattleResultWindow::bExitf()
@ -609,68 +583,6 @@ void BattleResultWindow::bExitf()
CCS->videoh->close();
}
void ClickableHex::hover(bool on)
{
hovered = on;
//Hoverable::hover(on);
if(!on && setAlterText)
{
GH.statusbar->clear();
setAlterText = false;
}
}
ClickableHex::ClickableHex() : setAlterText(false), myNumber(-1), strictHovered(false), myInterface(nullptr)
{
addUsedEvents(LCLICK | RCLICK | HOVER | MOVE);
}
void ClickableHex::mouseMoved(const SDL_MouseMotionEvent &sEvent)
{
strictHovered = myInterface->fieldController->isPixelInHex(Point(sEvent.x-pos.x, sEvent.y-pos.y));
if(hovered && strictHovered) //print attacked creature to console
{
const CStack * attackedStack = myInterface->getCurrentPlayerInterface()->cb->battleGetStackByPos(myNumber);
if( attackedStack != nullptr &&
attackedStack->owner != myInterface->getCurrentPlayerInterface()->playerID &&
attackedStack->alive())
{
MetaString text;
text.addTxt(MetaString::GENERAL_TXT, 220);
attackedStack->addNameReplacement(text);
GH.statusbar->write(text.toString());
setAlterText = true;
}
}
else if(setAlterText)
{
GH.statusbar->clear();
setAlterText = false;
}
}
void ClickableHex::clickLeft(tribool down, bool previousState)
{
if(!down && hovered && strictHovered) //we've been really clicked!
{
myInterface->actionsController->handleHex(myNumber, LCLICK);
}
}
void ClickableHex::clickRight(tribool down, bool previousState)
{
const CStack * myst = myInterface->getCurrentPlayerInterface()->cb->battleGetStackByPos(myNumber); //stack info
if(hovered && strictHovered && myst!=nullptr)
{
if(!myst->alive()) return;
if(down)
{
GH.pushIntT<CStackWindow>(myst, true);
}
}
}
StackQueue::StackQueue(bool Embedded, BattleInterface & owner)
: embedded(Embedded),
owner(owner)
@ -712,6 +624,14 @@ StackQueue::StackQueue(bool Embedded, BattleInterface & owner)
void StackQueue::show(SDL_Surface * to)
{
auto unitIdsToHighlight = owner.stacksController->getHoveredStacksUnitIds();
for(auto & stackBox : stackBoxes)
{
bool isBoundUnitCurrentlyHovered = vstd::contains(unitIdsToHighlight, stackBox->getBoundUnitID());
stackBox->toggleHighlight(isBoundUnitCurrentlyHovered);
}
if (embedded)
showAll(to);
CIntObject::show(to);
@ -740,8 +660,21 @@ int32_t StackQueue::getSiegeShooterIconID()
return owner.siegeController->getSiegedTown()->town->faction->getIndex();
}
boost::optional<uint32_t> StackQueue::getHoveredUnitIdIfAny() const
{
for(const auto & stackBox : stackBoxes)
{
if(stackBox->hovered || stackBox->mouseState(MouseButton::RIGHT))
{
return stackBox->getBoundUnitID();
}
}
return boost::none;
}
StackQueue::StackBox::StackBox(StackQueue * owner):
owner(owner)
CIntObject(RCLICK | HOVER), owner(owner)
{
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
background = std::make_shared<CPicture>(owner->embedded ? "StackQueueSmall" : "StackQueueLarge");
@ -771,6 +704,7 @@ void StackQueue::StackBox::setUnit(const battle::Unit * unit, size_t turn)
{
if(unit)
{
boundUnitID = unit->unitId();
background->colorize(unit->unitOwner());
icon->visible = true;
@ -783,7 +717,7 @@ void StackQueue::StackBox::setUnit(const battle::Unit * unit, size_t turn)
if (unit->unitType()->idNumber == CreatureID::ARROW_TOWERS)
icon->setFrame(owner->getSiegeShooterIconID(), 1);
amount->setText(CSDL_Ext::makeNumberShort(unit->getCount(), 4));
amount->setText(vstd::formatMetric(unit->getCount(), 4));
if(stateIcon)
{
@ -805,6 +739,7 @@ void StackQueue::StackBox::setUnit(const battle::Unit * unit, size_t turn)
}
else
{
boundUnitID = boost::none;
background->colorize(PlayerColor::NEUTRAL);
icon->visible = false;
icon->setFrame(0);
@ -814,3 +749,21 @@ void StackQueue::StackBox::setUnit(const battle::Unit * unit, size_t turn)
stateIcon->visible = false;
}
}
boost::optional<uint32_t> StackQueue::StackBox::getBoundUnitID() const
{
return boundUnitID;
}
void StackQueue::StackBox::toggleHighlight(bool value)
{
highlighted = value;
}
void StackQueue::StackBox::show(SDL_Surface *to)
{
if(highlighted)
CSDL_Ext::drawBorder(to, background->pos.x, background->pos.y, background->pos.w, background->pos.h, { 0, 255, 255, 255 }, 2);
CIntObject::show(to);
}

View File

@ -123,9 +123,9 @@ public:
void pause();
void play();
void hover(bool on) override;
void clickLeft(tribool down, bool previousState) override; //call-in
void clickRight(tribool down, bool previousState) override; //call-in
void heroLeftClicked();
void heroRightClicked();
BattleHero(const BattleInterface & owner, const CGHeroInstance * hero, bool defender);
};
@ -157,38 +157,27 @@ public:
void show(SDL_Surface * to = 0) override;
};
/// Class which stands for a single hex field on a battlefield
class ClickableHex : public CIntObject
{
private:
bool setAlterText; //if true, this hex has set alternative text in console and will clean it
public:
ui32 myNumber; //number of hex in commonly used format
bool strictHovered; //for determining if hex is hovered by mouse (this is different problem than hex's graphic hovering)
BattleInterface * myInterface; //interface that owns me
//for user interactions
void hover (bool on) override;
void mouseMoved (const SDL_MouseMotionEvent &sEvent) override;
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
ClickableHex();
};
/// Shows the stack queue
class StackQueue : public CIntObject
{
class StackBox : public CIntObject
{
StackQueue * owner;
boost::optional<uint32_t> boundUnitID;
bool highlighted = false;
public:
std::shared_ptr<CPicture> background;
std::shared_ptr<CAnimImage> icon;
std::shared_ptr<CLabel> amount;
std::shared_ptr<CAnimImage> stateIcon;
void setUnit(const battle::Unit * unit, size_t turn = 0);
StackBox(StackQueue * owner);
void setUnit(const battle::Unit * unit, size_t turn = 0);
void toggleHighlight(bool value);
boost::optional<uint32_t> getBoundUnitID() const;
void show(SDL_Surface * to) override;
};
static const int QUEUE_SIZE = 10;
@ -205,6 +194,7 @@ public:
StackQueue(bool Embedded, BattleInterface & owner);
void update();
boost::optional<uint32_t> getHoveredUnitIdIfAny() const;
void show(SDL_Surface * to) override;
};

View File

@ -26,8 +26,9 @@
#include "../CMusicHandler.h"
#include "../CGameInfo.h"
#include "../gui/CGuiHandler.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../render/Colors.h"
#include "../render/Canvas.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../../CCallback.h"
#include "../../lib/spells/ISpellMechanics.h"
@ -73,8 +74,6 @@ BattleStacksController::BattleStacksController(BattleInterface & owner):
activeStack(nullptr),
stackToActivate(nullptr),
selectedStack(nullptr),
stackCanCastSpell(false),
creatureSpellToCast(uint32_t(-1)),
animIDhelper(0)
{
//preparing graphics for displaying amounts of creatures
@ -317,7 +316,7 @@ void BattleStacksController::showStackAmountBox(Canvas & canvas, const CStack *
//blitting amount
Point textPos = stackAnimation[stack->ID]->pos.topLeft() + amountBG->dimensions()/2 + Point(xAdd, yAdd);
canvas.drawText(textPos, EFonts::FONT_TINY, Colors::WHITE, ETextAlignment::CENTER, CSDL_Ext::makeNumberShort(stack->getCount(), 4));
canvas.drawText(textPos, EFonts::FONT_TINY, Colors::WHITE, ETextAlignment::CENTER, vstd::formatMetric(stack->getCount(), 4));
}
void BattleStacksController::showStack(Canvas & canvas, const CStack * stack)
@ -738,25 +737,6 @@ void BattleStacksController::activateStack()
const CStack * s = getActiveStack();
if(!s)
return;
//set casting flag to true if creature can use it to not check it every time
const auto spellcaster = s->getBonusLocalFirst(Selector::type()(Bonus::SPELLCASTER));
const auto randomSpellcaster = s->getBonusLocalFirst(Selector::type()(Bonus::RANDOM_SPELLCASTER));
if(s->canCast() && (spellcaster || randomSpellcaster))
{
stackCanCastSpell = true;
if(randomSpellcaster)
creatureSpellToCast = -1; //spell will be set later on cast
else
creatureSpellToCast = owner.curInt->cb->battleGetRandomStackSpell(CRandomGenerator::getDefault(), s, CBattleInfoCallback::RANDOM_AIMED); //faerie dragon can cast only one spell until their next move
//TODO: what if creature can cast BOTH random genie spell and aimed spell?
//TODO: faerie dragon type spell should be selected by server
}
else
{
stackCanCastSpell = false;
creatureSpellToCast = -1;
}
}
void BattleStacksController::setSelectedStack(const CStack *stack)
@ -779,18 +759,6 @@ bool BattleStacksController::facingRight(const CStack * stack) const
return stackFacingRight.at(stack->ID);
}
bool BattleStacksController::activeStackSpellcaster()
{
return stackCanCastSpell;
}
SpellID BattleStacksController::activeStackSpellToCast()
{
if (!stackCanCastSpell)
return SpellID::NONE;
return SpellID(creatureSpellToCast);
}
Point BattleStacksController::getStackPositionAtHex(BattleHex hexNum, const CStack * stack) const
{
Point ret(-500, -500); //returned value
@ -896,6 +864,12 @@ std::vector<const CStack *> BattleStacksController::selectHoveredStacks()
if(owner.getAnimationCondition(EAnimationEvents::ACTION) == true)
return {};
auto hoveredQueueUnitId = owner.windowObject->getQueueHoveredUnitId();
if(hoveredQueueUnitId.is_initialized())
{
return { owner.curInt->cb->battleGetStackByID(hoveredQueueUnitId.value(), true) };
}
auto hoveredHex = owner.fieldController->getHoveredHex();
if (!hoveredHex.isValid())
@ -904,21 +878,11 @@ std::vector<const CStack *> BattleStacksController::selectHoveredStacks()
const spells::Caster *caster = nullptr;
const CSpell *spell = nullptr;
spells::Mode mode = spells::Mode::HERO;
spells::Mode mode = owner.actionsController->getCurrentCastMode();
spell = owner.actionsController->getCurrentSpell();
caster = owner.actionsController->getCurrentSpellcaster();
if(owner.actionsController->spellcastingModeActive())//hero casts spell
{
spell = owner.actionsController->selectedSpell().toSpell();
caster = owner.getActiveHero();
}
else if(owner.stacksController->activeStackSpellToCast() != SpellID::NONE)//stack casts spell
{
spell = SpellID(owner.stacksController->activeStackSpellToCast()).toSpell();
caster = owner.stacksController->getActiveStack();
mode = spells::Mode::CREATURE_ACTIVE;
}
if(caster && spell) //when casting spell
if(caster && spell && owner.actionsController->currentActionSpellcasting(hoveredHex) ) //when casting spell
{
spells::Target target;
target.emplace_back(hoveredHex);
@ -938,3 +902,14 @@ std::vector<const CStack *> BattleStacksController::selectHoveredStacks()
return {};
}
const std::vector<uint32_t> BattleStacksController::getHoveredStacksUnitIds() const
{
auto result = std::vector<uint32_t>();
for (auto const * stack : mouseHoveredStacks)
{
result.push_back(stack->unitId());
}
return result;
}

View File

@ -70,7 +70,7 @@ class BattleStacksController
/// currently active stack; nullptr - no one
const CStack *activeStack;
/// stacks below mouse pointer (multiple stacks possible while spellcasting), used for border animation
/// stacks or their battle queue images below mouse pointer (multiple stacks possible while spellcasting), used for border animation
std::vector<const CStack *> mouseHoveredStacks;
///when animation is playing, we should wait till the end to make the next stack active; nullptr of none
@ -79,10 +79,6 @@ class BattleStacksController
/// stack that was selected for multi-target spells - Teleport / Sacrifice
const CStack *selectedStack;
/// if true, active stack could possibly cast some target spell
bool stackCanCastSpell;
si32 creatureSpellToCast;
/// for giving IDs for animations
ui32 animIDhelper;
@ -123,9 +119,6 @@ public:
void startAction(const BattleAction* action);
void endAction(const BattleAction* action);
bool activeStackSpellcaster();
SpellID activeStackSpellToCast();
void activateStack(); //sets activeStack to stackToActivate etc. //FIXME: No, it's not clear at all
void setActiveStack(const CStack *stack);
@ -144,6 +137,7 @@ public:
const CStack* getActiveStack() const;
const CStack* getSelectedStack() const;
const std::vector<uint32_t> getHoveredStacksUnitIds() const;
void update();

View File

@ -37,9 +37,6 @@
#include "../../lib/filesystem/ResourceID.h"
#include "windows/BattleOptionsWindow.h"
#include <SDL_surface.h>
#include <SDL_events.h>
BattleWindow::BattleWindow(BattleInterface & owner):
owner(owner)
{
@ -80,9 +77,9 @@ BattleWindow::BattleWindow(BattleInterface & owner):
std::string queueSize = settings["battle"]["queueSize"].String();
if(queueSize == "auto")
embedQueue = screen->h < 700;
embedQueue = GH.screenDimensions().y < 700;
else
embedQueue = screen->h < 700 || queueSize == "small";
embedQueue = GH.screenDimensions().y < 700 || queueSize == "small";
queue = std::make_shared<StackQueue>(embedQueue, owner);
if(!embedQueue && settings["battle"]["showQueue"].Bool())
@ -166,9 +163,9 @@ void BattleWindow::deactivate()
LOCPLINT->cingconsole->deactivate();
}
void BattleWindow::keyPressed(const SDL_KeyboardEvent & key)
void BattleWindow::keyPressed(const SDL_Keycode & key)
{
if(key.keysym.sym == SDLK_q && key.state == SDL_PRESSED)
if(key == SDLK_q)
{
if(settings["battle"]["showQueue"].Bool()) //hide queue
hideQueue();
@ -176,11 +173,11 @@ void BattleWindow::keyPressed(const SDL_KeyboardEvent & key)
showQueue();
}
else if(key.keysym.sym == SDLK_f && key.state == SDL_PRESSED)
else if(key == SDLK_f)
{
owner.actionsController->enterCreatureCastingMode();
}
else if(key.keysym.sym == SDLK_ESCAPE)
else if(key == SDLK_ESCAPE)
{
if(owner.getAnimationCondition(EAnimationEvents::OPENING) == true)
CCS->soundh->stopSound(owner.battleIntroSoundChannel);
@ -346,6 +343,7 @@ void BattleWindow::showAlternativeActionIcon(PossiblePlayerBattleAction action)
auto anim = std::make_shared<CAnimation>(iconName);
w->setImage(anim, false);
w->redraw();
}
void BattleWindow::setAlternativeActions(const std::list<PossiblePlayerBattleAction> & actions)
@ -392,7 +390,7 @@ void BattleWindow::bSpellf()
if (owner.actionsController->spellcastingModeActive())
return;
if (!owner.myTurn)
if (!owner.makingTurn())
return;
auto myHero = owner.currentHero();
@ -554,11 +552,16 @@ void BattleWindow::blockUI(bool on)
}
}
boost::optional<uint32_t> BattleWindow::getQueueHoveredUnitId()
{
return queue->getHoveredUnitIdIfAny();
}
void BattleWindow::showAll(SDL_Surface *to)
{
CIntObject::showAll(to);
if (screen->w != 800 || screen->h !=600)
if (GH.screenDimensions().x != 800 || GH.screenDimensions().y !=600)
CMessage::drawBorder(owner.curInt->playerID, to, pos.w+28, pos.h+29, pos.x-14, pos.y-15);
}

View File

@ -74,9 +74,12 @@ public:
/// Refresh queue after turn order changes
void updateQueue();
/// Get mouse-hovered battle queue unit ID if any found
boost::optional<uint32_t> getQueueHoveredUnitId();
void activate() override;
void deactivate() override;
void keyPressed(const SDL_KeyboardEvent & key) override;
void keyPressed(const SDL_Keycode & key) override;
void clickRight(tribool down, bool previousState) override;
void show(SDL_Surface *to) override;
void showAll(SDL_Surface *to) override;

View File

@ -78,10 +78,7 @@ float AnimationControls::getCreatureAnimationSpeed(const CCreature * creature, c
return baseSpeed;
case ECreatureAnimType::HOLDING:
if ( creature->animation.idleAnimationTime > 0.01)
return speed / creature->animation.idleAnimationTime;
else
return 0.f; // this animation is disabled for current creature
return creature->animation.idleAnimationTime;
case ECreatureAnimType::SHOOT_UP:
case ECreatureAnimType::SHOOT_FRONT:
@ -315,7 +312,7 @@ void CreatureAnimation::playOnce( ECreatureAnimType type )
inline int getBorderStrength(float time)
{
float borderStrength = fabs(vstd::round(time) - time) * 2; // generate value in range 0-1
float borderStrength = fabs(std::round(time) - time) * 2; // generate value in range 0-1
return static_cast<int>(borderStrength * 155 + 100); // scale to 0-255
}

View File

@ -15,6 +15,7 @@
#include "CursorHandler.h"
#include "../CGameInfo.h"
#include "../render/Colors.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../CMT.h"
#include "../CPlayerInterface.h"
@ -27,6 +28,14 @@
#include <SDL_timer.h>
#include <SDL_events.h>
#ifdef VCMI_APPLE
#include <dispatch/dispatch.h>
#endif
#ifdef VCMI_IOS
#include "ios/utils.h"
#endif
extern std::queue<SDL_Event> SDLEventsQueue;
extern boost::mutex eventsM;
@ -118,7 +127,7 @@ void CGuiHandler::popInt(std::shared_ptr<IShowActivatable> top)
listInt.front()->activate();
totalRedraw();
pushSDLEvent(SDL_USEREVENT, EUserEvent::INTERFACE_CHANGED);
pushUserEvent(EUserEvent::INTERFACE_CHANGED);
}
void CGuiHandler::pushInt(std::shared_ptr<IShowActivatable> newInt)
@ -137,7 +146,7 @@ void CGuiHandler::pushInt(std::shared_ptr<IShowActivatable> newInt)
objsToBlit.push_back(newInt);
totalRedraw();
pushSDLEvent(SDL_USEREVENT, EUserEvent::INTERFACE_CHANGED);
pushUserEvent(EUserEvent::INTERFACE_CHANGED);
}
void CGuiHandler::popInts(int howMany)
@ -160,7 +169,7 @@ void CGuiHandler::popInts(int howMany)
}
fakeMouseMove();
pushSDLEvent(SDL_USEREVENT, EUserEvent::INTERFACE_CHANGED);
pushUserEvent(EUserEvent::INTERFACE_CHANGED);
}
std::shared_ptr<IShowActivatable> CGuiHandler::topInt()
@ -203,7 +212,12 @@ void CGuiHandler::handleEvents()
{
continueEventHandling = true;
SDL_Event currentEvent = SDLEventsQueue.front();
cursorPosition = Point(currentEvent.motion.x, currentEvent.motion.y);
if (currentEvent.type == SDL_MOUSEMOTION)
{
cursorPosition = Point(currentEvent.motion.x, currentEvent.motion.y);
mouseButtonsMask = currentEvent.motion.state;
}
SDLEventsQueue.pop();
// In a sequence of mouse motion events, skip all but the last one.
@ -257,6 +271,59 @@ void CGuiHandler::fakeMouseMove()
fakeMoveCursor(0, 0);
}
void CGuiHandler::startTextInput(const Rect & whereInput)
{
#ifdef VCMI_APPLE
dispatch_async(dispatch_get_main_queue(), ^{
#endif
// TODO ios: looks like SDL bug actually, try fixing there
auto renderer = SDL_GetRenderer(mainWindow);
float scaleX, scaleY;
SDL_Rect viewport;
SDL_RenderGetScale(renderer, &scaleX, &scaleY);
SDL_RenderGetViewport(renderer, &viewport);
#ifdef VCMI_IOS
const auto nativeScale = iOS_utils::screenScale();
scaleX /= nativeScale;
scaleY /= nativeScale;
#endif
SDL_Rect rectInScreenCoordinates;
rectInScreenCoordinates.x = (viewport.x + whereInput.x) * scaleX;
rectInScreenCoordinates.y = (viewport.y + whereInput.y) * scaleY;
rectInScreenCoordinates.w = whereInput.w * scaleX;
rectInScreenCoordinates.h = whereInput.h * scaleY;
SDL_SetTextInputRect(&rectInScreenCoordinates);
if (SDL_IsTextInputActive() == SDL_FALSE)
{
SDL_StartTextInput();
}
#ifdef VCMI_APPLE
});
#endif
}
void CGuiHandler::stopTextInput()
{
#ifdef VCMI_APPLE
dispatch_async(dispatch_get_main_queue(), ^{
#endif
if (SDL_IsTextInputActive() == SDL_TRUE)
{
SDL_StopTextInput();
}
#ifdef VCMI_APPLE
});
#endif
}
void CGuiHandler::fakeMouseButtonEventRelativeMode(bool down, bool right)
{
SDL_Event event;
@ -280,9 +347,9 @@ void CGuiHandler::fakeMouseButtonEventRelativeMode(bool down, bool right)
SDL_RenderGetScale(mainRenderer, &xScale, &yScale);
SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
CSDL_Ext::warpMouse(
moveCursorToPosition( Point(
(int)(sme.x * xScale) + (w - rLogicalWidth * xScale) / 2,
(int)(sme.y * yScale + (h - rLogicalHeight * yScale) / 2));
(int)(sme.y * yScale + (h - rLogicalHeight * yScale) / 2)));
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
event.button = sme;
@ -345,7 +412,7 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
bool keysCaptured = false;
for(auto i = keyinterested.begin(); i != keyinterested.end() && continueEventHandling; i++)
{
if((*i)->captureThisEvent(key))
if((*i)->captureThisKey(key.keysym.sym))
{
keysCaptured = true;
break;
@ -354,8 +421,13 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
std::list<CIntObject*> miCopy = keyinterested;
for(auto i = miCopy.begin(); i != miCopy.end() && continueEventHandling; i++)
if(vstd::contains(keyinterested,*i) && (!keysCaptured || (*i)->captureThisEvent(key)))
(**i).keyPressed(key);
if(vstd::contains(keyinterested,*i) && (!keysCaptured || (*i)->captureThisKey(key.keysym.sym)))
{
if (key.state == SDL_PRESSED)
(**i).keyPressed(key.keysym.sym);
if (key.state == SDL_RELEASED)
(**i).keyReleased(key.keysym.sym);
}
}
else if(current.type == SDL_MOUSEMOTION)
{
@ -387,14 +459,14 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
lastClickTime = SDL_GetTicks();
if(!doubleClicked)
handleMouseButtonClick(lclickable, EIntObjMouseBtnType::LEFT, true);
handleMouseButtonClick(lclickable, MouseButton::LEFT, true);
break;
}
case SDL_BUTTON_RIGHT:
handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, true);
handleMouseButtonClick(rclickable, MouseButton::RIGHT, true);
break;
case SDL_BUTTON_MIDDLE:
handleMouseButtonClick(mclickable, EIntObjMouseBtnType::MIDDLE, true);
handleMouseButtonClick(mclickable, MouseButton::MIDDLE, true);
break;
default:
break;
@ -416,14 +488,14 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
{
for(auto it : textInterested)
{
it->textInputed(current.text);
it->textInputed(current.text.text);
}
}
else if(current.type == SDL_TEXTEDITING)
{
for(auto it : textInterested)
{
it->textEdited(current.edit);
it->textEdited(current.edit.text);
}
}
else if(current.type == SDL_MOUSEBUTTONUP)
@ -433,13 +505,13 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
switch(current.button.button)
{
case SDL_BUTTON_LEFT:
handleMouseButtonClick(lclickable, EIntObjMouseBtnType::LEFT, false);
handleMouseButtonClick(lclickable, MouseButton::LEFT, false);
break;
case SDL_BUTTON_RIGHT:
handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false);
handleMouseButtonClick(rclickable, MouseButton::RIGHT, false);
break;
case SDL_BUTTON_MIDDLE:
handleMouseButtonClick(mclickable, EIntObjMouseBtnType::MIDDLE, false);
handleMouseButtonClick(mclickable, MouseButton::MIDDLE, false);
break;
}
}
@ -471,7 +543,7 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
{
convertTouchToMouse(&current);
handleMouseMotion(current);
handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, true);
handleMouseButtonClick(rclickable, MouseButton::RIGHT, true);
}
#endif //VCMI_IOS
}
@ -495,14 +567,14 @@ void CGuiHandler::handleCurrentEvent( SDL_Event & current )
{
convertTouchToMouse(&current);
handleMouseMotion(current);
handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false);
handleMouseButtonClick(rclickable, MouseButton::RIGHT, false);
multifinger = fingerCount != 0;
}
#endif //VCMI_IOS
}
} //event end
void CGuiHandler::handleMouseButtonClick(CIntObjectList & interestedObjs, EIntObjMouseBtnType btn, bool isPressed)
void CGuiHandler::handleMouseButtonClick(CIntObjectList & interestedObjs, MouseButton btn, bool isPressed)
{
auto hlp = interestedObjs;
for(auto i = hlp.begin(); i != hlp.end() && continueEventHandling; i++)
@ -546,7 +618,9 @@ void CGuiHandler::handleMouseMotion(const SDL_Event & current)
elem->hovered = true;
}
handleMoveInterested(current.motion);
// do not send motion events for events outside our window
//if (current.motion.windowID == 0)
handleMoveInterested(current.motion);
}
void CGuiHandler::simpleRedraw()
@ -566,7 +640,7 @@ void CGuiHandler::handleMoveInterested(const SDL_MouseMotionEvent & motion)
{
if(elem->strongInterest || Rect::createAround(elem->pos, 1).isInside( motion.x, motion.y)) //checking bounds including border fixes bug #2476
{
(elem)->mouseMoved(motion);
(elem)->mouseMoved(Point(motion.x, motion.y));
}
}
}
@ -612,13 +686,16 @@ void CGuiHandler::renderFrame()
CGuiHandler::CGuiHandler()
: lastClick(-500, -500),lastClickTime(0), defActionsDef(0), captureChildren(false),
multifinger(false)
: lastClick(-500, -500)
, lastClickTime(0)
, defActionsDef(0)
, captureChildren(false)
, multifinger(false)
, mouseButtonsMask(0)
, continueEventHandling(true)
, curInt(nullptr)
, statusbar(nullptr)
{
continueEventHandling = true;
curInt = nullptr;
statusbar = nullptr;
// Creates the FPS manager and sets the framerate to 48 which is doubled the value of the original Heroes 3 FPS rate
mainFPSmng = new CFramerateManager(60);
//do not init CFramerateManager here --AVS
@ -632,6 +709,27 @@ CGuiHandler::~CGuiHandler()
delete terminate_cond;
}
void CGuiHandler::moveCursorToPosition(const Point & position)
{
SDL_WarpMouseInWindow(mainWindow, position.x, position.y);
}
bool CGuiHandler::isKeyboardCtrlDown() const
{
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LCTRL] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RCTRL];
}
bool CGuiHandler::isKeyboardAltDown() const
{
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LALT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RALT];
}
bool CGuiHandler::isKeyboardShiftDown() const
{
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LSHIFT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RSHIFT];
}
void CGuiHandler::breakEventHandling()
{
continueEventHandling = false;
@ -642,6 +740,28 @@ const Point & CGuiHandler::getCursorPosition() const
return cursorPosition;
}
Point CGuiHandler::screenDimensions() const
{
return Point(screen->w, screen->h);
}
bool CGuiHandler::isMouseButtonPressed() const
{
return mouseButtonsMask > 0;
}
bool CGuiHandler::isMouseButtonPressed(MouseButton button) const
{
static_assert(static_cast<uint32_t>(MouseButton::LEFT) == SDL_BUTTON_LEFT, "mismatch between VCMI and SDL enum!");
static_assert(static_cast<uint32_t>(MouseButton::MIDDLE) == SDL_BUTTON_MIDDLE, "mismatch between VCMI and SDL enum!");
static_assert(static_cast<uint32_t>(MouseButton::RIGHT) == SDL_BUTTON_RIGHT, "mismatch between VCMI and SDL enum!");
static_assert(static_cast<uint32_t>(MouseButton::EXTRA1) == SDL_BUTTON_X1, "mismatch between VCMI and SDL enum!");
static_assert(static_cast<uint32_t>(MouseButton::EXTRA2) == SDL_BUTTON_X2, "mismatch between VCMI and SDL enum!");
uint32_t index = static_cast<uint32_t>(button);
return mouseButtonsMask & SDL_BUTTON(index);
}
void CGuiHandler::drawFPSCounter()
{
static SDL_Rect overlay = { 0, 0, 64, 32};
@ -719,11 +839,17 @@ bool CGuiHandler::amIGuiThread()
return inGuiThread.get() && *inGuiThread;
}
void CGuiHandler::pushSDLEvent(int type, int usercode)
void CGuiHandler::pushUserEvent(EUserEvent usercode)
{
pushUserEvent(usercode, nullptr);
}
void CGuiHandler::pushUserEvent(EUserEvent usercode, void * userdata)
{
SDL_Event event;
event.type = type;
event.user.code = usercode; // not necessarily used
event.type = SDL_USEREVENT;
event.user.code = static_cast<int32_t>(usercode);
event.user.data1 = userdata;
SDL_PushEvent(&event);
}

View File

@ -9,12 +9,15 @@
*/
#pragma once
#include "MouseButton.h"
#include "../../lib/Point.h"
#include "SDL_keycode.h"
#include <SDL_keycode.h>
VCMI_LIB_NAMESPACE_BEGIN
template <typename T> struct CondSh;
class Rect;
VCMI_LIB_NAMESPACE_END
@ -27,10 +30,9 @@ class CIntObject;
class IUpdateable;
class IShowActivatable;
class IShowable;
enum class EIntObjMouseBtnType;
// TODO: event handling need refactoring
enum EUserEvent
enum class EUserEvent
{
/*CHANGE_SCREEN_RESOLUTION = 1,*/
RETURN_TO_MAIN_MENU = 2,
@ -71,6 +73,7 @@ public:
private:
Point cursorPosition;
uint32_t mouseButtonsMask;
std::vector<std::shared_ptr<IShowActivatable>> disposed;
@ -90,7 +93,7 @@ private:
CIntObjectList textInterested;
void handleMouseButtonClick(CIntObjectList & interestedObjs, EIntObjMouseBtnType btn, bool isPressed);
void handleMouseButtonClick(CIntObjectList & interestedObjs, MouseButton btn, bool isPressed);
void processLists(const ui16 activityFlag, std::function<void (std::list<CIntObject*> *)> cb);
void handleCurrentEvent(SDL_Event &current);
void handleMouseMotion(const SDL_Event & current);
@ -107,8 +110,28 @@ public:
//objs to blit
std::vector<std::shared_ptr<IShowActivatable>> objsToBlit;
/// returns current position of mouse cursor, relative to vcmi window
const Point & getCursorPosition() const;
Point screenDimensions() const;
/// returns true if at least one mouse button is pressed
bool isMouseButtonPressed() const;
/// returns true if specified mouse button is pressed
bool isMouseButtonPressed(MouseButton button) const;
/// returns true if chosen keyboard key is currently pressed down
bool isKeyboardAltDown() const;
bool isKeyboardCtrlDown() const;
bool isKeyboardShiftDown() const;
void startTextInput(const Rect & where);
void stopTextInput();
/// moves mouse pointer into specified position inside vcmi window
void moveCursorToPosition(const Point & position);
IUpdateable *curInt;
Point lastClick;
@ -155,7 +178,8 @@ public:
static bool isNumKey(SDL_Keycode key, bool number = true); //checks if key is on numpad (numbers - check only for numpad digits)
static bool isArrowKey(SDL_Keycode key);
static bool amIGuiThread();
static void pushSDLEvent(int type, int usercode = 0);
static void pushUserEvent(EUserEvent usercode);
static void pushUserEvent(EUserEvent usercode, void * userdata);
CondSh<bool> * terminate_cond; // confirm termination
};

View File

@ -13,10 +13,9 @@
#include "CGuiHandler.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../windows/CMessage.h"
#include "../CMT.h"
#include <SDL_pixels.h>
#include <SDL_surface.h>
#include <SDL_events.h>
IShowActivatable::IShowActivatable()
{
@ -146,18 +145,18 @@ void CIntObject::deactivate(ui16 what)
GH.handleElementDeActivate(this, what);
}
void CIntObject::click(EIntObjMouseBtnType btn, tribool down, bool previousState)
void CIntObject::click(MouseButton btn, tribool down, bool previousState)
{
switch(btn)
{
default:
case EIntObjMouseBtnType::LEFT:
case MouseButton::LEFT:
clickLeft(down, previousState);
break;
case EIntObjMouseBtnType::MIDDLE:
case MouseButton::MIDDLE:
clickMiddle(down, previousState);
break;
case EIntObjMouseBtnType::RIGHT:
case MouseButton::RIGHT:
clickRight(down, previousState);
break;
}
@ -228,8 +227,8 @@ void CIntObject::fitToScreen(int borderWidth, bool propagate)
Point newPos = pos.topLeft();
vstd::amax(newPos.x, borderWidth);
vstd::amax(newPos.y, borderWidth);
vstd::amin(newPos.x, screen->w - borderWidth - pos.w);
vstd::amin(newPos.y, screen->h - borderWidth - pos.h);
vstd::amin(newPos.x, GH.screenDimensions().x - borderWidth - pos.w);
vstd::amin(newPos.y, GH.screenDimensions().y - borderWidth - pos.h);
if (newPos != pos.topLeft())
moveTo(newPos, propagate);
}
@ -309,7 +308,7 @@ const Rect & CIntObject::center( const Rect &r, bool propagate )
{
pos.w = r.w;
pos.h = r.h;
return center(Point(screen->w/2, screen->h/2), propagate);
return center(Point(GH.screenDimensions().x/2, GH.screenDimensions().y/2), propagate);
}
const Rect & CIntObject::center( bool propagate )
@ -325,7 +324,7 @@ const Rect & CIntObject::center(const Point & p, bool propagate)
return pos;
}
bool CIntObject::captureThisEvent(const SDL_KeyboardEvent & key)
bool CIntObject::captureThisKey(const SDL_Keycode & key)
{
return captureAllKeys;
}
@ -343,14 +342,26 @@ CKeyShortcut::CKeyShortcut(std::set<int> Keys)
:assignedKeys(Keys)
{}
void CKeyShortcut::keyPressed(const SDL_KeyboardEvent & key)
void CKeyShortcut::keyPressed(const SDL_Keycode & key)
{
if(vstd::contains(assignedKeys,key.keysym.sym)
|| vstd::contains(assignedKeys, CGuiHandler::numToDigit(key.keysym.sym)))
if(vstd::contains(assignedKeys,key)
|| vstd::contains(assignedKeys, CGuiHandler::numToDigit(key)))
{
bool prev = mouseState(EIntObjMouseBtnType::LEFT);
updateMouseState(EIntObjMouseBtnType::LEFT, key.state == SDL_PRESSED);
clickLeft(key.state == SDL_PRESSED, prev);
bool prev = mouseState(MouseButton::LEFT);
updateMouseState(MouseButton::LEFT, true);
clickLeft(true, prev);
}
}
void CKeyShortcut::keyReleased(const SDL_Keycode & key)
{
if(vstd::contains(assignedKeys,key)
|| vstd::contains(assignedKeys, CGuiHandler::numToDigit(key)))
{
bool prev = mouseState(MouseButton::LEFT);
updateMouseState(MouseButton::LEFT, false);
clickLeft(false, prev);
}
}

View File

@ -9,17 +9,15 @@
*/
#pragma once
#include "../../lib/Rect.h"
#include "MouseButton.h"
#include "../render/Graphics.h"
#include "../../lib/Rect.h"
struct SDL_Surface;
class CGuiHandler;
class CPicture;
struct SDL_KeyboardEvent;
struct SDL_TextInputEvent;
struct SDL_TextEditingEvent;
struct SDL_MouseMotionEvent;
typedef int32_t SDL_Keycode;
using boost::logic::tribool;
@ -62,9 +60,6 @@ public:
virtual ~IShowActivatable(){};
};
enum class EIntObjMouseBtnType { LEFT, MIDDLE, RIGHT };
//typedef ui16 ActivityFlag;
// Base UI element
class CIntObject : public IShowActivatable //interface object
{
@ -74,7 +69,7 @@ class CIntObject : public IShowActivatable //interface object
int toNextTick;
int timerDelay;
std::map<EIntObjMouseBtnType, bool> currentMouseState;
std::map<MouseButton, bool> currentMouseState;
void onTimer(int timePassed);
@ -108,10 +103,10 @@ public:
CIntObject(int used=0, Point offset=Point());
virtual ~CIntObject();
void updateMouseState(EIntObjMouseBtnType btn, bool state) { currentMouseState[btn] = state; }
bool mouseState(EIntObjMouseBtnType btn) const { return currentMouseState.count(btn) ? currentMouseState.at(btn) : false; }
void updateMouseState(MouseButton btn, bool state) { currentMouseState[btn] = state; }
bool mouseState(MouseButton btn) const { return currentMouseState.count(btn) ? currentMouseState.at(btn) : false; }
virtual void click(EIntObjMouseBtnType btn, tribool down, bool previousState);
virtual void click(MouseButton btn, tribool down, bool previousState);
virtual void clickLeft(tribool down, bool previousState) {}
virtual void clickRight(tribool down, bool previousState) {}
virtual void clickMiddle(tribool down, bool previousState) {}
@ -122,15 +117,16 @@ public:
//keyboard handling
bool captureAllKeys; //if true, only this object should get info about pressed keys
virtual void keyPressed(const SDL_KeyboardEvent & key){}
virtual bool captureThisEvent(const SDL_KeyboardEvent & key); //allows refining captureAllKeys against specific events (eg. don't capture ENTER)
virtual void keyPressed(const SDL_Keycode & key){}
virtual void keyReleased(const SDL_Keycode & key){}
virtual bool captureThisKey(const SDL_Keycode & key); //allows refining captureAllKeys against specific events (eg. don't capture ENTER)
virtual void textInputed(const SDL_TextInputEvent & event){};
virtual void textEdited(const SDL_TextEditingEvent & event){};
virtual void textInputed(const std::string & enteredText){};
virtual void textEdited(const std::string & enteredText){};
//mouse movement handling
bool strongInterest; //if true - report all mouse movements, if not - only when hovered
virtual void mouseMoved (const SDL_MouseMotionEvent & sEvent){}
virtual void mouseMoved (const Point & cursorPosition){}
//time handling
void setTimer(int msToTrigger);//set timer delay and activate timer if needed.
@ -205,7 +201,9 @@ public:
CKeyShortcut();
CKeyShortcut(int key);
CKeyShortcut(std::set<int> Keys);
virtual void keyPressed(const SDL_KeyboardEvent & key) override; //call-in
void keyPressed(const SDL_Keycode & key) override;
void keyReleased(const SDL_Keycode & key) override;
};
class WindowBase : public CIntObject

View File

@ -17,17 +17,9 @@
#include "../render/CAnimation.h"
#include "../render/IImage.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../CMT.h"
#include "../../lib/CConfigHandler.h"
#include <SDL_render.h>
#include <SDL_events.h>
#ifdef VCMI_APPLE
#include <dispatch/dispatch.h>
#endif
std::unique_ptr<ICursor> CursorHandler::createCursor()
{
if (settings["video"]["cursor"].String() == "auto")
@ -254,18 +246,6 @@ std::shared_ptr<IImage> CursorHandler::getCurrentImage()
return cursors[static_cast<size_t>(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

View File

@ -178,7 +178,4 @@ public:
/// change cursor's positions to (x, y)
void cursorMove(const int & x, const int & y);
/// Move cursor to screen center
void centerCursor();
};

View File

@ -1,23 +1,19 @@
/*
* Ability.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
*
*/
VCMI_LIB_NAMESPACE_BEGIN
namespace abilities
{
class DLL_LINKAGE Ability
{
};
}
VCMI_LIB_NAMESPACE_END
/*
* MouseButton.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
enum class MouseButton
{
LEFT = 1,
MIDDLE = 2,
RIGHT = 3,
EXTRA1 = 4,
EXTRA2 = 5
};

View File

@ -454,7 +454,7 @@ void CBonusSelection::restartMap()
close();
LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[67], [=]()
{
LOCPLINT->sendCustomEvent(EUserEvent::RESTART_GAME);
GH.pushUserEvent(EUserEvent::RESTART_GAME);
}, 0);
}

View File

@ -43,8 +43,6 @@
#include "../../lib/mapping/CMapInfo.h"
#include "../../lib/serializer/Connection.h"
#include <SDL_events.h>
ISelectionScreenInfo::ISelectionScreenInfo(ESelectionScreen ScreenType)
: screenType(ScreenType)
{
@ -320,9 +318,9 @@ CChatBox::CChatBox(const Rect & rect)
chatHistory->label->color = Colors::GREEN;
}
void CChatBox::keyPressed(const SDL_KeyboardEvent & key)
void CChatBox::keyPressed(const SDL_Keycode & key)
{
if(key.keysym.sym == SDLK_RETURN && key.state == SDL_PRESSED && inputBox->getText().size())
if(key == SDLK_RETURN && inputBox->getText().size())
{
CSH->sendMessage(inputBox->getText());
inputBox->setText("");

View File

@ -120,8 +120,7 @@ public:
CChatBox(const Rect & rect);
void keyPressed(const SDL_KeyboardEvent & key) override;
void keyPressed(const SDL_Keycode & key) override;
void addNewMessage(const std::string & text);
};

View File

@ -35,8 +35,6 @@
#include "../../lib/mapping/CMapInfo.h"
#include "../../lib/serializer/Connection.h"
#include <SDL_events.h>
bool mapSorter::operator()(const std::shared_ptr<CMapInfo> aaa, const std::shared_ptr<CMapInfo> bbb)
{
auto a = aaa->mapHeader.get();
@ -280,13 +278,10 @@ void SelectionTab::clickLeft(tribool down, bool previousState)
}
}
void SelectionTab::keyPressed(const SDL_KeyboardEvent & key)
void SelectionTab::keyPressed(const SDL_Keycode & key)
{
if(key.state != SDL_PRESSED)
return;
int moveBy = 0;
switch(key.keysym.sym)
switch(key)
{
case SDLK_UP:
moveBy = -1;

View File

@ -66,7 +66,8 @@ public:
void toggleMode();
void clickLeft(tribool down, bool previousState) override;
void keyPressed(const SDL_KeyboardEvent & key) override;
void keyPressed(const SDL_Keycode & key) override;
void onDoubleClick() override;
void filter(int size, bool selectFirst = false); //0 - all

View File

@ -16,25 +16,8 @@
#include "../lobby/CBonusSelection.h"
#include "../lobby/CSelectionBase.h"
#include "../lobby/CLobbyScreen.h"
#include "../../lib/filesystem/Filesystem.h"
#include "../../lib/filesystem/CCompressedStream.h"
#include "../gui/CursorHandler.h"
#include "../CGameInfo.h"
#include "../../lib/CGeneralTextHandler.h"
#include "../../lib/JsonNode.h"
#include "../CMusicHandler.h"
#include "../CVideoHandler.h"
#include "../../lib/serializer/Connection.h"
#include "../../lib/serializer/CTypeList.h"
#include "../../lib/VCMIDirs.h"
#include "../../lib/mapping/CMap.h"
#include "../windows/GUIClasses.h"
#include "../CPlayerInterface.h"
#include "../../CCallback.h"
#include "../Client.h"
#include "../gui/CGuiHandler.h"
#include "../widgets/CComponent.h"
#include "../widgets/Buttons.h"
@ -43,6 +26,24 @@
#include "../widgets/TextControls.h"
#include "../windows/InfoWindows.h"
#include "../CServerHandler.h"
#include "../CGameInfo.h"
#include "../CMusicHandler.h"
#include "../CVideoHandler.h"
#include "../CPlayerInterface.h"
#include "../Client.h"
#include "../CMT.h"
#include "../../CCallback.h"
#include "../../lib/CGeneralTextHandler.h"
#include "../../lib/JsonNode.h"
#include "../../lib/serializer/Connection.h"
#include "../../lib/serializer/CTypeList.h"
#include "../../lib/filesystem/Filesystem.h"
#include "../../lib/filesystem/CCompressedStream.h"
#include "../../lib/VCMIDirs.h"
#include "../../lib/mapping/CMap.h"
#include "../../lib/CStopWatch.h"
#include "../../lib/NetPacksLobby.h"
#include "../../lib/CThreadHelper.h"
@ -52,7 +53,6 @@
#include "../../lib/CondSh.h"
#include "../../lib/mapping/CCampaignHandler.h"
#include <SDL_events.h>
namespace fs = boost::filesystem;
@ -61,9 +61,7 @@ ISelectionScreenInfo * SEL;
static void do_quit()
{
SDL_Event event;
event.quit.type = SDL_QUIT;
SDL_PushEvent(&event);
GH.pushUserEvent(EUserEvent::FORCE_QUIT);
}
CMenuScreen::CMenuScreen(const JsonNode & configNode)
@ -73,7 +71,7 @@ CMenuScreen::CMenuScreen(const JsonNode & configNode)
background = std::make_shared<CPicture>(config["background"].String());
if(config["scalable"].Bool())
background->scaleTo(Point(screen->w, screen->h));
background->scaleTo(GH.screenDimensions());
pos = background->center();
@ -276,8 +274,8 @@ const JsonNode & CMainMenuConfig::getCampaigns() const
CMainMenu::CMainMenu()
{
pos.w = screen->w;
pos.h = screen->h;
pos.w = GH.screenDimensions().x;
pos.h = GH.screenDimensions().y;
GH.defActionsDef = 63;
menu = std::make_shared<CMenuScreen>(CMainMenuConfig::get().getConfig()["window"]);
@ -484,7 +482,7 @@ void CSimpleJoinScreen::connectToServer()
{
textTitle->setText("Connecting...");
buttonOk->block(true);
CSDL_Ext::stopTextInput();
GH.stopTextInput();
boost::thread(&CSimpleJoinScreen::connectThread, this, inputAddress->getText(), boost::lexical_cast<ui16>(inputPort->getText()));
}

View File

@ -16,6 +16,7 @@
#include "../CVideoHandler.h"
#include "../gui/CGuiHandler.h"
#include "../widgets/TextControls.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../../lib/mapping/CCampaignHandler.h"

View File

@ -81,7 +81,7 @@ SDL_Surface * BitmapHandler::loadH3PCX(ui8 * pcx, size_t size)
}
else
{
#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
#ifdef VCMI_ENDIAN_BIG
int bmask = 0xff0000;
int gmask = 0x00ff00;
int rmask = 0x0000ff;

26
client/render/Colors.cpp Normal file
View File

@ -0,0 +1,26 @@
/*
* IFont.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 "Colors.h"
#include <SDL_pixels.h>
const SDL_Color Colors::YELLOW = { 229, 215, 123, SDL_ALPHA_OPAQUE };
const SDL_Color Colors::WHITE = { 255, 243, 222, SDL_ALPHA_OPAQUE };
const SDL_Color Colors::METALLIC_GOLD = { 173, 142, 66, SDL_ALPHA_OPAQUE };
const SDL_Color Colors::GREEN = { 0, 255, 0, SDL_ALPHA_OPAQUE };
const SDL_Color Colors::ORANGE = { 232, 184, 32, SDL_ALPHA_OPAQUE };
const SDL_Color Colors::BRIGHT_YELLOW = { 242, 226, 110, SDL_ALPHA_OPAQUE };
const SDL_Color Colors::DEFAULT_KEY_COLOR = {0, 255, 255, SDL_ALPHA_OPAQUE};
const SDL_Color Colors::RED = {255, 0, 0, SDL_ALPHA_OPAQUE};
const SDL_Color Colors::PURPLE = {255, 75, 125, SDL_ALPHA_OPAQUE};
const SDL_Color Colors::BLACK = {0, 0, 0, SDL_ALPHA_OPAQUE};
const SDL_Color Colors::TRANSPARENCY = {0, 0, 0, SDL_ALPHA_TRANSPARENT};

50
client/render/Colors.h Normal file
View File

@ -0,0 +1,50 @@
/*
* ICursor.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
struct SDL_Color;
/**
* The colors class defines color constants of type SDL_Color.
*/
class Colors
{
public:
/** the h3 yellow color, typically used for headlines */
static const SDL_Color YELLOW;
/** the standard h3 white color */
static const SDL_Color WHITE;
/** the metallic gold color used mostly as a border around buttons */
static const SDL_Color METALLIC_GOLD;
/** green color used for in-game console */
static const SDL_Color GREEN;
/** the h3 orange color, used for blocked buttons */
static const SDL_Color ORANGE;
/** the h3 bright yellow color, used for selection border */
static const SDL_Color BRIGHT_YELLOW;
/** default key color for all 8 & 24 bit graphics */
static const SDL_Color DEFAULT_KEY_COLOR;
/// Selected creature card
static const SDL_Color RED;
/// Minimap border
static const SDL_Color PURPLE;
static const SDL_Color BLACK;
static const SDL_Color TRANSPARENCY;
};

View File

@ -42,8 +42,6 @@
#include <SDL_surface.h>
using namespace CSDL_Ext;
Graphics * graphics = nullptr;
void Graphics::loadPaletteAndColors()

View File

@ -10,7 +10,8 @@
#include "StdInc.h"
#include "CTrueTypeFont.h"
#include "SDL_Extensions.h"
#include "../render/Colors.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../../lib/JsonNode.h"
#include "../../lib/CGeneralTextHandler.h"

View File

@ -11,8 +11,9 @@
#include "StdInc.h"
#include "CursorHardware.h"
#include "SDL_Extensions.h"
#include "../render/Colors.h"
#include "../render/IImage.h"
#include "SDL_Extensions.h"
#include <SDL_render.h>
#include <SDL_events.h>

View File

@ -11,9 +11,10 @@
#include "StdInc.h"
#include "CursorSoftware.h"
#include "SDL_Extensions.h"
#include "../render/Colors.h"
#include "../render/IImage.h"
#include "../CMT.h"
#include "SDL_Extensions.h"
#include <SDL_render.h>
#include <SDL_events.h>

View File

@ -13,40 +13,10 @@
#include "SDL_PixelAccess.h"
#include "../render/Graphics.h"
#include "../render/Colors.h"
#include "../CMT.h"
#include <SDL_render.h>
#include <SDL_video.h>
#include <SDL_events.h>
#ifdef VCMI_APPLE
#include <dispatch/dispatch.h>
#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 };
const SDL_Color Colors::METALLIC_GOLD = { 173, 142, 66, SDL_ALPHA_OPAQUE };
const SDL_Color Colors::GREEN = { 0, 255, 0, SDL_ALPHA_OPAQUE };
const SDL_Color Colors::ORANGE = { 232, 184, 32, SDL_ALPHA_OPAQUE };
const SDL_Color Colors::BRIGHT_YELLOW = { 242, 226, 110, SDL_ALPHA_OPAQUE };
const SDL_Color Colors::DEFAULT_KEY_COLOR = {0, 255, 255, SDL_ALPHA_OPAQUE};
const SDL_Color Colors::RED = {255, 0, 0, SDL_ALPHA_OPAQUE};
const SDL_Color Colors::PURPLE = {255, 75, 125, SDL_ALPHA_OPAQUE};
const SDL_Color Colors::BLACK = {0, 0, 0, SDL_ALPHA_OPAQUE};
const SDL_Color Colors::TRANSPARENCY = {0, 0, 0, SDL_ALPHA_TRANSPARENT};
Rect CSDL_Ext::genRect(const int & hh, const int & ww, const int & xx, const int & yy)
{
Rect ret;
ret.h=hh;
ret.w=ww;
ret.x=xx;
ret.y=yy;
return ret;
}
Rect CSDL_Ext::fromSDL(const SDL_Rect & rect)
{
@ -79,31 +49,19 @@ SDL_Color CSDL_Ext::toSDL(const ColorRGBA & color)
return result;
}
Rect CSDL_Ext::getDisplayBounds()
{
SDL_Rect displayBounds;
SDL_GetDisplayBounds(std::max(0, SDL_GetWindowDisplayIndex(mainWindow)), &displayBounds);
return fromSDL(displayBounds);
}
void CSDL_Ext::setColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors)
{
SDL_SetPaletteColors(surface->format->palette,colors,firstcolor,ncolors);
}
void CSDL_Ext::warpMouse(int x, int y)
{
SDL_WarpMouseInWindow(mainWindow,x,y);
}
bool CSDL_Ext::isCtrlKeyDown()
{
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LCTRL] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RCTRL];
}
bool CSDL_Ext::isAltKeyDown()
{
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LALT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RALT];
}
bool CSDL_Ext::isShiftKeyDown()
{
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LSHIFT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RSHIFT];
}
void CSDL_Ext::setAlpha(SDL_Surface * bg, int value)
{
SDL_SetSurfaceAlphaMod(bg, value);
@ -122,6 +80,11 @@ void CSDL_Ext::updateRect(SDL_Surface *surface, const Rect & rect )
}
SDL_Surface * CSDL_Ext::newSurface(int w, int h)
{
return newSurface(w, h, screen);
}
SDL_Surface * CSDL_Ext::newSurface(int w, int h, SDL_Surface * mod) //creates new surface, with flags/format same as in surface given
{
SDL_Surface * ret = SDL_CreateRGBSurface(0,w,h,mod->format->BitsPerPixel,mod->format->Rmask,mod->format->Gmask,mod->format->Bmask,mod->format->Amask);
@ -409,14 +372,6 @@ uint32_t CSDL_Ext::colorTouint32_t(const SDL_Color * color)
return ret;
}
void CSDL_Ext::update(SDL_Surface * what)
{
if(!what)
return;
if(0 !=SDL_UpdateTexture(screenTexture, nullptr, what->pixels, what->pitch))
logGlobal->error("%s SDL_UpdateTexture %s", __FUNCTION__, SDL_GetError());
}
static void drawLineX(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color1, const SDL_Color & color2)
{
for(int x = x1; x <= x2; x++)
@ -479,23 +434,27 @@ void CSDL_Ext::drawLine(SDL_Surface * sur, int x1, int y1, int x2, int y2, const
}
}
void CSDL_Ext::drawBorder(SDL_Surface * sur, int x, int y, int w, int h, const SDL_Color &color)
void CSDL_Ext::drawBorder(SDL_Surface * sur, int x, int y, int w, int h, const SDL_Color &color, int depth)
{
for(int i = 0; i < w; i++)
depth = std::max(1, depth);
for(int depthIterator = 0; depthIterator < depth; depthIterator++)
{
CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur,x+i,y,color.r,color.g,color.b);
CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur,x+i,y+h-1,color.r,color.g,color.b);
}
for(int i = 0; i < h; i++)
{
CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur,x,y+i,color.r,color.g,color.b);
CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur,x+w-1,y+i,color.r,color.g,color.b);
for(int i = 0; i < w; i++)
{
CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur,x+i,y+depthIterator,color.r,color.g,color.b);
CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur,x+i,y+h-1-depthIterator,color.r,color.g,color.b);
}
for(int i = 0; i < h; i++)
{
CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur,x+depthIterator,y+i,color.r,color.g,color.b);
CSDL_Ext::putPixelWithoutRefreshIfInSurf(sur,x+w-1-depthIterator,y+i,color.r,color.g,color.b);
}
}
}
void CSDL_Ext::drawBorder( SDL_Surface * sur, const Rect &r, const SDL_Color &color )
void CSDL_Ext::drawBorder( SDL_Surface * sur, const Rect &r, const SDL_Color &color, int depth)
{
drawBorder(sur, r.x, r.y, r.w, r.h, color);
drawBorder(sur, r.x, r.y, r.w, r.h, color, depth);
}
void CSDL_Ext::drawDashedBorder(SDL_Surface * sur, const Rect &r, const SDL_Color &color)
@ -581,15 +540,6 @@ uint8_t * CSDL_Ext::getPxPtr(const SDL_Surface * const &srf, const int x, const
return (uint8_t *)srf->pixels + y * srf->pitch + x * srf->format->BytesPerPixel;
}
std::string CSDL_Ext::processStr(std::string str, std::vector<std::string> & tor)
{
for (size_t i=0; (i<tor.size())&&(boost::find_first(str,"%s")); ++i)
{
boost::replace_first(str,"%s",tor[i]);
}
return str;
}
bool CSDL_Ext::isTransparent( SDL_Surface * srf, const Point & position )
{
return isTransparent(srf, position.x, position.y);
@ -883,59 +833,6 @@ SDL_Color CSDL_Ext::makeColor(ui8 r, ui8 g, ui8 b, ui8 a)
return ret;
}
void CSDL_Ext::startTextInput(const Rect & whereInput)
{
#ifdef VCMI_APPLE
dispatch_async(dispatch_get_main_queue(), ^{
#endif
// TODO ios: looks like SDL bug actually, try fixing there
auto renderer = SDL_GetRenderer(mainWindow);
float scaleX, scaleY;
SDL_Rect viewport;
SDL_RenderGetScale(renderer, &scaleX, &scaleY);
SDL_RenderGetViewport(renderer, &viewport);
#ifdef VCMI_IOS
const auto nativeScale = iOS_utils::screenScale();
scaleX /= nativeScale;
scaleY /= nativeScale;
#endif
SDL_Rect rectInScreenCoordinates;
rectInScreenCoordinates.x = (viewport.x + whereInput.x) * scaleX;
rectInScreenCoordinates.y = (viewport.y + whereInput.y) * scaleY;
rectInScreenCoordinates.w = whereInput.w * scaleX;
rectInScreenCoordinates.h = whereInput.h * scaleY;
SDL_SetTextInputRect(&rectInScreenCoordinates);
if (SDL_IsTextInputActive() == SDL_FALSE)
{
SDL_StartTextInput();
}
#ifdef VCMI_APPLE
});
#endif
}
void CSDL_Ext::stopTextInput()
{
#ifdef VCMI_APPLE
dispatch_async(dispatch_get_main_queue(), ^{
#endif
if (SDL_IsTextInputActive() == SDL_TRUE)
{
SDL_StopTextInput();
}
#ifdef VCMI_APPLE
});
#endif
}
STRONG_INLINE static uint32_t mapColor(SDL_Surface * surface, SDL_Color color)
{
return SDL_MapRGBA(surface->format, color.r, color.g, color.b, color.a);

View File

@ -20,11 +20,6 @@ struct SDL_Texture;
struct SDL_Surface;
struct SDL_Color;
extern SDL_Window * mainWindow;
extern SDL_Renderer * mainRenderer;
extern SDL_Texture * screenTexture;
extern SDL_Surface * screen, *screen2, *screenBuf;
VCMI_LIB_NAMESPACE_BEGIN
class Rect;
@ -32,44 +27,6 @@ class Point;
VCMI_LIB_NAMESPACE_END
/**
* The colors class defines color constants of type SDL_Color.
*/
class Colors
{
public:
/** the h3 yellow color, typically used for headlines */
static const SDL_Color YELLOW;
/** the standard h3 white color */
static const SDL_Color WHITE;
/** the metallic gold color used mostly as a border around buttons */
static const SDL_Color METALLIC_GOLD;
/** green color used for in-game console */
static const SDL_Color GREEN;
/** the h3 orange color, used for blocked buttons */
static const SDL_Color ORANGE;
/** the h3 bright yellow color, used for selection border */
static const SDL_Color BRIGHT_YELLOW;
/** default key color for all 8 & 24 bit graphics */
static const SDL_Color DEFAULT_KEY_COLOR;
/// Selected creature card
static const SDL_Color RED;
/// Minimap border
static const SDL_Color PURPLE;
static const SDL_Color BLACK;
static const SDL_Color TRANSPARENCY;
};
namespace CSDL_Ext
{
@ -86,39 +43,13 @@ ColorRGBA fromSDL(const SDL_Color & 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();
bool isAltKeyDown();
bool isShiftKeyDown();
void setAlpha(SDL_Surface * bg, int value);
template<typename IntType>
std::string makeNumberShort(IntType number, IntType maxLength = 3) //the output is a string containing at most 5 characters [4 if positive] (eg. intead 10000 it gives 10k)
{
IntType max = pow(10, maxLength);
if (std::abs(number) < max)
return boost::lexical_cast<std::string>(number);
std::string symbols = " kMGTPE";
auto iter = symbols.begin();
while (number >= max)
{
number /= 1000;
iter++;
assert(iter != symbols.end());//should be enough even for int64
}
return boost::lexical_cast<std::string>(number) + *iter;
}
Rect genRect(const int & hh, const int & ww, const int & xx, const int & yy);
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);
void blitAt(SDL_Surface * src, int x, int y, SDL_Surface * dst);
void blitAt(SDL_Surface * src, const Rect & pos, SDL_Surface * dst);
void setClipRect(SDL_Surface * src, const Rect & other);
void getClipRect(SDL_Surface * src, Rect & other);
@ -150,14 +81,17 @@ typedef void (*TColorPutterAlpha)(uint8_t *&ptr, const uint8_t & R, const uint8_
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)
/// returns dimensions of display on which VCMI window is located
Rect getDisplayBounds();
void drawLine(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color1, const SDL_Color & color2);
void drawBorder(SDL_Surface * sur, int x, int y, int w, int h, const SDL_Color &color);
void drawBorder(SDL_Surface * sur, const Rect &r, const SDL_Color &color);
void drawBorder(SDL_Surface * sur, int x, int y, int w, int h, const SDL_Color &color, int depth = 1);
void drawBorder(SDL_Surface * sur, const Rect &r, const SDL_Color &color, int depth = 1);
void drawDashedBorder(SDL_Surface * sur, const Rect &r, const SDL_Color &color);
void setPlayerColor(SDL_Surface * sur, PlayerColor player); //sets correct color of flags; -1 for neutral
std::string processStr(std::string str, std::vector<std::string> & tor); //replaces %s in string
SDL_Surface * newSurface(int w, int h, SDL_Surface * mod=screen); //creates new surface, with flags/format same as in surface given
SDL_Surface * newSurface(int w, int h, SDL_Surface * mod); //creates new surface, with flags/format same as in surface given
SDL_Surface * newSurface(int w, int h); //creates new surface, with flags/format same as in screen surface
SDL_Surface * copySurface(SDL_Surface * mod); //returns copy of given surface
template<int bpp>
SDL_Surface * createSurfaceWithBpp(int width, int height); //create surface with give bits per pixels value
@ -173,14 +107,10 @@ typedef void (*TColorPutterAlpha)(uint8_t *&ptr, const uint8_t & R, const uint8_
void applyEffectBpp( SDL_Surface * surf, const Rect & rect, int mode );
void applyEffect(SDL_Surface * surf, const Rect & rect, int mode); //mode: 0 - sepia, 1 - grayscale
void startTextInput(const Rect & where);
void stopTextInput();
void setColorKey(SDL_Surface * surface, SDL_Color color);
///set key-color to 0,255,255
void setDefaultColorKey(SDL_Surface * surface);
///set key-color to 0,255,255 only if it exactly mapped
void setDefaultColorKeyPresize(SDL_Surface * surface);

View File

@ -68,7 +68,7 @@ namespace Channels
static channel_empty a;
};
#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
#ifdef VCMI_ENDIAN_BIG
template<>
struct px<4>

View File

@ -21,12 +21,11 @@
#include "../gui/CGuiHandler.h"
#include "../windows/InfoWindows.h"
#include "../render/CAnimation.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../../lib/CConfigHandler.h"
#include "../../lib/CGeneralTextHandler.h"
#include <SDL_events.h>
void CButton::update()
{
if (overlay)
@ -555,22 +554,22 @@ void CSlider::sliderClicked()
addUsedEvents(MOVE);
}
void CSlider::mouseMoved (const SDL_MouseMotionEvent & sEvent)
void CSlider::mouseMoved (const Point & cursorPosition)
{
double v = 0;
if(horizontal)
{
if( std::abs(sEvent.y-(pos.y+pos.h/2)) > pos.h/2+40 || std::abs(sEvent.x-(pos.x+pos.w/2)) > pos.w/2 )
if( std::abs(cursorPosition.y-(pos.y+pos.h/2)) > pos.h/2+40 || std::abs(cursorPosition.x-(pos.x+pos.w/2)) > pos.w/2 )
return;
v = sEvent.x - pos.x - 24;
v = cursorPosition.x - pos.x - 24;
v *= positions;
v /= (pos.w - 48);
}
else
{
if(std::abs(sEvent.x-(pos.x+pos.w/2)) > pos.w/2+40 || std::abs(sEvent.y-(pos.y+pos.h/2)) > pos.h/2 )
if(std::abs(cursorPosition.x-(pos.x+pos.w/2)) > pos.w/2+40 || std::abs(cursorPosition.y-(pos.y+pos.h/2)) > pos.h/2 )
return;
v = sEvent.y - pos.y - 24;
v = cursorPosition.y - pos.y - 24;
v *= positions;
v /= (pos.h - 48);
}
@ -679,7 +678,7 @@ void CSlider::clickLeft(tribool down, bool previousState)
return;
// if (rw>1) return;
// if (rw<0) return;
slider->clickLeft(true, slider->mouseState(EIntObjMouseBtnType::LEFT));
slider->clickLeft(true, slider->mouseState(MouseButton::LEFT));
moveTo((int)(rw * positions + 0.5));
return;
}
@ -780,12 +779,10 @@ void CSlider::wheelScrolled(bool down, bool in)
moveTo(value + 3 * (down ? +scrollStep : -scrollStep));
}
void CSlider::keyPressed(const SDL_KeyboardEvent & key)
void CSlider::keyPressed(const SDL_Keycode & key)
{
if(key.state != SDL_PRESSED) return;
int moveDest = value;
switch(key.keysym.sym)
switch(key)
{
case SDLK_UP:
if (!horizontal)

View File

@ -10,7 +10,7 @@
#pragma once
#include "../gui/CIntObject.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../render/Colors.h"
#include "../../lib/FunctionList.h"
#include <SDL_pixels.h>
@ -270,10 +270,10 @@ public:
void addCallback(std::function<void(int)> callback);
void keyPressed(const SDL_KeyboardEvent & key) override;
void keyPressed(const SDL_Keycode & key) override;
void wheelScrolled(bool down, bool in) override;
void clickLeft(tribool down, bool previousState) override;
void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
void mouseMoved (const Point & cursorPosition) override;
void showAll(SDL_Surface * to) override;
/// @param position coordinates of slider

View File

@ -19,6 +19,7 @@
#include "../windows/CHeroWindow.h"
#include "../windows/CSpellWindow.h"
#include "../windows/GUIClasses.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../CPlayerInterface.h"
#include "../CGameInfo.h"

View File

@ -14,11 +14,11 @@
#include "TextControls.h"
#include "../gui/CGuiHandler.h"
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../windows/CCreatureWindow.h"
#include "../windows/GUIClasses.h"
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../../CCallback.h"
@ -28,12 +28,6 @@
#include "../../lib/CGameState.h"
#ifdef VCMI_MAC
#define SDL_SCANCODE_LCTRL SDL_SCANCODE_LGUI
#endif
#include <SDL_keyboard.h>
void CGarrisonSlot::setHighlight(bool on)
{
if (on)
@ -336,7 +330,7 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState)
lastHeroStackSelected = true;
}
if((owner->getSplittingMode() || LOCPLINT->shiftPressed()) // split window
if((owner->getSplittingMode() || GH.isKeyboardShiftDown()) // split window
&& (!creature || creature == selection->creature))
{
refr = split();
@ -380,7 +374,7 @@ void CGarrisonSlot::update()
creatureImage->setFrame(creature->getIconIndex());
stackCount->enable();
stackCount->setText(CSDL_Ext::makeNumberShort(myStack->count, 4));
stackCount->setText(vstd::formatMetric(myStack->count, 4));
}
else
{
@ -439,10 +433,9 @@ void CGarrisonSlot::splitIntoParts(CGarrisonSlot::EGarrisonType type, int amount
bool CGarrisonSlot::handleSplittingShortcuts()
{
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];
const bool isAlt = GH.isKeyboardAltDown();
const bool isLShift = GH.isKeyboardShiftDown();
const bool isLCtrl = GH.isKeyboardCtrlDown();
if(!isAlt && !isLShift && !isLCtrl)
return false; // This is only case when return false

View File

@ -182,6 +182,18 @@ void CMinorResDataBar::show(SDL_Surface * to)
{
}
std::string CMinorResDataBar::buildDateString()
{
std::string pattern = "%s: %d, %s: %d, %s: %d";
auto formatted = boost::format(pattern)
% CGI->generaltexth->translate("core.genrltxt.62") % LOCPLINT->cb->getDate(Date::MONTH)
% CGI->generaltexth->translate("core.genrltxt.63") % LOCPLINT->cb->getDate(Date::WEEK)
% CGI->generaltexth->translate("core.genrltxt.64") % LOCPLINT->cb->getDate(Date::DAY_OF_WEEK);
return boost::str(formatted);
}
void CMinorResDataBar::showAll(SDL_Surface * to)
{
CIntObject::showAll(to);
@ -192,16 +204,7 @@ void CMinorResDataBar::showAll(SDL_Surface * to)
graphics->fonts[FONT_SMALL]->renderTextCenter(to, text, Colors::WHITE, Point(pos.x + 50 + 76 * i, pos.y + pos.h/2));
}
std::vector<std::string> temp;
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::MONTH)));
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::WEEK)));
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK)));
std::string datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63]
+ ": %s, " + CGI->generaltexth->allTexts[64] + ": %s";
graphics->fonts[FONT_SMALL]->renderTextCenter(to, CSDL_Ext::processStr(datetext,temp), Colors::WHITE, Point(pos.x+545+(pos.w-545)/2,pos.y+pos.h/2));
graphics->fonts[FONT_SMALL]->renderTextCenter(to, buildDateString(), Colors::WHITE, Point(pos.x+545+(pos.w-545)/2,pos.y+pos.h/2));
}
CMinorResDataBar::CMinorResDataBar()
@ -248,7 +251,7 @@ void CArmyTooltip::init(const InfoAboutArmy &army)
std::string subtitle;
if(army.army.isDetailed)
{
subtitle = CSDL_Ext::makeNumberShort(slot.second.count, 4);
subtitle = vstd::formatMetric(slot.second.count, 4);
}
else
{

View File

@ -117,6 +117,8 @@ public:
class CMinorResDataBar : public CIntObject
{
std::shared_ptr<CPicture> background;
std::string buildDateString();
public:
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;

View File

@ -17,14 +17,14 @@
#include "../gui/CGuiHandler.h"
#include "../windows/CMessage.h"
#include "../adventureMap/CInGameConsole.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../../lib/CGeneralTextHandler.h"
#ifdef VCMI_ANDROID
#include "lib/CAndroidVMHelper.h"
#endif
#include <SDL_events.h>
std::list<CFocusable*> CFocusable::focusables;
CFocusable * CFocusable::inputWithFocus;
@ -353,14 +353,14 @@ void CGStatusBar::setEnteringMode(bool on)
{
assert(enteringText == false);
alignment = ETextAlignment::TOPLEFT;
CSDL_Ext::startTextInput(pos);
GH.startTextInput(pos);
setText(consoleText);
}
else
{
assert(enteringText == true);
alignment = ETextAlignment::CENTER;
CSDL_Ext::stopTextInput();
GH.stopTextInput();
setText(hoverText);
}
enteringText = on;
@ -526,7 +526,7 @@ CKeyboardFocusListener::CKeyboardFocusListener(CTextInput * textInput)
void CKeyboardFocusListener::focusGot()
{
CSDL_Ext::startTextInput(textInput->pos);
GH.startTextInput(textInput->pos);
usageIndex++;
}
@ -534,7 +534,7 @@ void CKeyboardFocusListener::focusLost()
{
if(0 == --usageIndex)
{
CSDL_Ext::stopTextInput();
GH.stopTextInput();
}
}
@ -549,13 +549,12 @@ void CTextInput::clickLeft(tribool down, bool previousState)
giveFocus();
}
void CTextInput::keyPressed(const SDL_KeyboardEvent & key)
void CTextInput::keyPressed(const SDL_Keycode & key)
{
if(!focus || key.state != SDL_PRESSED)
if(!focus)
return;
if(key.keysym.sym == SDLK_TAB)
if(key == SDLK_TAB)
{
moveFocus();
GH.breakEventHandling();
@ -564,7 +563,7 @@ void CTextInput::keyPressed(const SDL_KeyboardEvent & key)
bool redrawNeeded = false;
switch(key.keysym.sym)
switch(key)
{
case SDLK_DELETE: // have index > ' ' so it won't be filtered out by default section
return;
@ -603,21 +602,21 @@ void CTextInput::setText(const std::string & nText, bool callCb)
cb(text);
}
bool CTextInput::captureThisEvent(const SDL_KeyboardEvent & key)
bool CTextInput::captureThisKey(const SDL_Keycode & key)
{
if(key.keysym.sym == SDLK_RETURN || key.keysym.sym == SDLK_KP_ENTER || key.keysym.sym == SDLK_ESCAPE)
if(key == SDLK_RETURN || key == SDLK_KP_ENTER || key == SDLK_ESCAPE)
return false;
return true;
}
void CTextInput::textInputed(const SDL_TextInputEvent & event)
void CTextInput::textInputed(const std::string & enteredText)
{
if(!focus)
return;
std::string oldText = text;
text += event.text;
text += enteredText;
filters(text, oldText);
if(text != oldText)
@ -628,12 +627,12 @@ void CTextInput::textInputed(const SDL_TextInputEvent & event)
newText.clear();
}
void CTextInput::textEdited(const SDL_TextEditingEvent & event)
void CTextInput::textEdited(const std::string & enteredText)
{
if(!focus)
return;
newText = event.text;
newText = enteredText;
redraw();
cb(text + newText);
}

View File

@ -11,7 +11,7 @@
#include "../gui/CIntObject.h"
#include "../gui/TextAlignment.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../render/Colors.h"
#include "../render/Graphics.h"
#include "../../lib/FunctionList.h"
@ -225,11 +225,12 @@ public:
CTextInput(const Rect & Pos, std::shared_ptr<IImage> srf);
void clickLeft(tribool down, bool previousState) override;
void keyPressed(const SDL_KeyboardEvent & key) override;
bool captureThisEvent(const SDL_KeyboardEvent & key) override;
void keyPressed(const SDL_Keycode & key) override;
void textInputed(const SDL_TextInputEvent & event) override;
void textEdited(const SDL_TextEditingEvent & event) override;
bool captureThisKey(const SDL_Keycode & key) override;
void textInputed(const std::string & enteredText) override;
void textEdited(const std::string & enteredText) override;
//Filter that will block all characters not allowed in filenames
static void filenameFilter(std::string & text, const std::string & oldText);

View File

@ -102,7 +102,7 @@ BattleOptionsWindow::BattleOptionsWindow(BattleInterface * owner):
int BattleOptionsWindow::getAnimSpeed() const
{
if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-battle-speed"].isNull())
return static_cast<int>(vstd::round(settings["session"]["spectate-battle-speed"].Float()));
return static_cast<int>(std::round(settings["session"]["spectate-battle-speed"].Float()));
return static_cast<int>(vstd::round(settings["battle"]["speedFactor"].Float()));
return static_cast<int>(std::round(settings["battle"]["speedFactor"].Float()));
}

View File

@ -43,7 +43,6 @@
#include "../../lib/mapObjects/CGHeroInstance.h"
#include "../../lib/mapObjects/CGTownInstance.h"
#include <SDL_events.h>
CBuildingRect::CBuildingRect(CCastleBuildings * Par, const CGTownInstance * Town, const CStructure * Str)
: CShowableAnim(0, 0, Str->defName, CShowableAnim::BASE, BUILDING_FRAME_TIME),
@ -146,7 +145,7 @@ void CBuildingRect::clickRight(tribool down, bool previousState)
else
{
int level = ( bid - BuildingID::DWELL_FIRST ) % GameConstants::CREATURES_PER_TOWN;
GH.pushIntT<CDwellingInfoBox>(parent->pos.x+parent->pos.w/2, parent->pos.y+parent->pos.h/2, town, level);
GH.pushIntT<CDwellingInfoBox>(parent->pos.x+parent->pos.w / 2, parent->pos.y+parent->pos.h /2, town, level);
}
}
}
@ -241,11 +240,11 @@ std::string CBuildingRect::getSubtitle()//hover text for building
}
}
void CBuildingRect::mouseMoved (const SDL_MouseMotionEvent & sEvent)
void CBuildingRect::mouseMoved (const Point & cursorPosition)
{
if(area && pos.isInside(sEvent.x, sEvent.y))
if(area && pos.isInside(cursorPosition.x, cursorPosition.y))
{
if(area->isTransparent(GH.getCursorPosition() - pos.topLeft())) //hovered pixel is inside this building
if(area->isTransparent(cursorPosition - pos.topLeft())) //hovered pixel is inside this building
{
if(parent->selectedBuilding == this)
{
@ -1066,7 +1065,7 @@ void CCreaInfo::clickRight(tribool down, bool previousState)
if(down)
{
if (showAvailable)
GH.pushIntT<CDwellingInfoBox>(screen->w/2, screen->h/2, town, level);
GH.pushIntT<CDwellingInfoBox>(GH.screenDimensions().x / 2, GH.screenDimensions().y / 2, town, level);
else
CRClickPopup::createAndPush(genGrowthText(), std::make_shared<CComponent>(CComponent::creature, creature->idNumber));
}
@ -1255,11 +1254,9 @@ void CCastleInterface::recreateIcons()
creainfo.push_back(std::make_shared<CCreaInfo>(Point(14+55*(int)i, 507), town, (int)i+4));
}
void CCastleInterface::keyPressed(const SDL_KeyboardEvent & key)
void CCastleInterface::keyPressed(const SDL_Keycode & key)
{
if(key.state != SDL_PRESSED) return;
switch(key.keysym.sym)
switch(key)
{
case SDLK_UP:
townlist->selectPrev();

View File

@ -68,7 +68,7 @@ public:
void hover(bool on) override;
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
void mouseMoved (const Point & cursorPosition) override;
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;
};
@ -245,7 +245,8 @@ public:
void castleTeleport(int where);
void townChange();
void keyPressed(const SDL_KeyboardEvent & key) override;
void keyPressed(const SDL_Keycode & key) override;
void close();
void addBuilding(BuildingID bid);
void removeBuilding(BuildingID bid);

View File

@ -22,6 +22,7 @@
#include "../widgets/TextControls.h"
#include "../widgets/ObjectLists.h"
#include "../gui/CGuiHandler.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../../CCallback.h"
#include "../../lib/CStack.h"
@ -31,8 +32,6 @@
#include "../../lib/CHeroHandler.h"
#include "../../lib/CGameState.h"
using namespace CSDL_Ext;
class CCreatureArtifactInstance;
class CSelectableSkill;
@ -518,8 +517,8 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
const CStack * battleStack = parent->info->stack;
morale = std::make_shared<MoraleLuckBox>(true, genRect(42, 42, 321, 110));
luck = std::make_shared<MoraleLuckBox>(false, genRect(42, 42, 375, 110));
morale = std::make_shared<MoraleLuckBox>(true, Rect(Point(321, 110), Point(42, 42) ));
luck = std::make_shared<MoraleLuckBox>(false, Rect(Point(375, 110), Point(42, 42) ));
if(battleStack != nullptr) // in battle
{
@ -583,7 +582,7 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
}
expLabel = std::make_shared<CLabel>(
pos.x + 21, pos.y + 52, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE,
makeNumberShort<TExpType>(stack->experience, 6));
vstd::formatMetric(stack->experience, 6));
}
if(showArt)

View File

@ -15,7 +15,6 @@
#include "GUIClasses.h"
#include "../CGameInfo.h"
#include "../CMT.h"
#include "../CPlayerInterface.h"
#include "../gui/CGuiHandler.h"

View File

@ -14,7 +14,6 @@
#include "InfoWindows.h"
#include "../CGameInfo.h"
#include "../CMT.h"
#include "../CPlayerInterface.h"
#include "../gui/CGuiHandler.h"
#include "../widgets/CComponent.h"

View File

@ -18,8 +18,10 @@
#include "../widgets/Buttons.h"
#include "../widgets/CComponent.h"
#include "../widgets/TextControls.h"
#include "../gui/CGuiHandler.h"
#include "../render/CAnimation.h"
#include "../render/IImage.h"
#include "../renderSDL/SDL_Extensions.h"
#include <SDL_surface.h>
@ -210,8 +212,8 @@ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, PlayerColor play
assert(ret && ret->text);
for(int i = 0;
i < ARRAY_COUNT(sizes)
&& sizes[i][0] < screen->w - 150
&& sizes[i][1] < screen->h - 150
&& sizes[i][0] < GH.screenDimensions().x - 150
&& sizes[i][1] < GH.screenDimensions().y - 150
&& ret->text->slider;
i++)
{
@ -253,7 +255,7 @@ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, PlayerColor play
vstd::amax(winSize.first, comps.w);
vstd::amax(winSize.first, bw);
vstd::amin(winSize.first, screen->w - 150);
vstd::amin(winSize.first, GH.screenDimensions().x - 150);
ret->bitmap = drawDialogBox (winSize.first + 2*SIDE_MARGIN, winSize.second + 2*SIDE_MARGIN, player);
ret->pos.h=ret->bitmap->h;

View File

@ -18,6 +18,7 @@
#include "../adventureMap/CAdvMapInt.h"
#include "../widgets/Buttons.h"
#include "../adventureMap/CMinimap.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../../CCallback.h"
#include "../../lib/CArtHandler.h"

View File

@ -66,7 +66,7 @@ class CQuestMinimap : public CMinimap
void clickLeft(tribool down, bool previousState) override{}; //minimap ignores clicking on its surface
void iconClicked();
void mouseMoved (const SDL_MouseMotionEvent & sEvent) override{};
void mouseMoved (const Point & cursorPosition) override{};
public:
const QuestInfo * currentQuest;

View File

@ -17,7 +17,6 @@
#include "CCastleInterface.h"
#include "../CGameInfo.h"
#include "../CMT.h"
#include "../CPlayerInterface.h"
#include "../CVideoHandler.h"
@ -28,6 +27,7 @@
#include "../widgets/TextControls.h"
#include "../adventureMap/CAdvMapInt.h"
#include "../render/CAnimation.h"
#include "../renderSDL/SDL_Extensions.h"
#include "../../CCallback.h"
@ -39,8 +39,6 @@
#include "../../lib/mapObjects/CGHeroInstance.h"
#include <SDL_events.h>
CSpellWindow::InteractiveArea::InteractiveArea(const Rect & myRect, std::function<void()> funcL, int helpTextId, CSpellWindow * _owner)
{
addUsedEvents(LCLICK | RCLICK | HOVER);
@ -185,38 +183,25 @@ CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _m
mana = std::make_shared<CLabel>(435, 426, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, boost::lexical_cast<std::string>(myHero->mana));
statusBar = CGStatusBar::create(7, 569, "Spelroll.bmp");
Rect temp_rect = CSDL_Ext::genRect(45, 35, 479 + pos.x, 405 + pos.y);
interactiveAreas.push_back(std::make_shared<InteractiveArea>(temp_rect, std::bind(&CSpellWindow::fexitb, this), 460, this));
temp_rect = CSDL_Ext::genRect(45, 35, 221 + pos.x, 405 + pos.y);
interactiveAreas.push_back(std::make_shared<InteractiveArea>(temp_rect, std::bind(&CSpellWindow::fbattleSpellsb, this), 453, this));
temp_rect = CSDL_Ext::genRect(45, 35, 355 + pos.x, 405 + pos.y);
interactiveAreas.push_back(std::make_shared<InteractiveArea>(temp_rect, std::bind(&CSpellWindow::fadvSpellsb, this), 452, this));
temp_rect = CSDL_Ext::genRect(45, 35, 418 + pos.x, 405 + pos.y);
interactiveAreas.push_back(std::make_shared<InteractiveArea>(temp_rect, std::bind(&CSpellWindow::fmanaPtsb, this), 459, this));
interactiveAreas.push_back(std::make_shared<InteractiveArea>( Rect( 479 + pos.x, 405 + pos.y, 36, 56), std::bind(&CSpellWindow::fexitb, this), 460, this));
interactiveAreas.push_back(std::make_shared<InteractiveArea>( Rect( 221 + pos.x, 405 + pos.y, 36, 56), std::bind(&CSpellWindow::fbattleSpellsb, this), 453, this));
interactiveAreas.push_back(std::make_shared<InteractiveArea>( Rect( 355 + pos.x, 405 + pos.y, 36, 56), std::bind(&CSpellWindow::fadvSpellsb, this), 452, this));
interactiveAreas.push_back(std::make_shared<InteractiveArea>( Rect( 418 + pos.x, 405 + pos.y, 36, 56), std::bind(&CSpellWindow::fmanaPtsb, this), 459, this));
interactiveAreas.push_back(std::make_shared<InteractiveArea>( Rect( 549 + pos.x, 94 + pos.y, 36, 56), std::bind(&CSpellWindow::selectSchool, this, 0), 454, this));
interactiveAreas.push_back(std::make_shared<InteractiveArea>( Rect( 549 + pos.x, 151 + pos.y, 45, 35), std::bind(&CSpellWindow::selectSchool, this, 3), 457, this));
interactiveAreas.push_back(std::make_shared<InteractiveArea>( Rect( 549 + pos.x, 210 + pos.y, 45, 35), std::bind(&CSpellWindow::selectSchool, this, 1), 455, this));
interactiveAreas.push_back(std::make_shared<InteractiveArea>( Rect( 549 + pos.x, 270 + pos.y, 45, 35), std::bind(&CSpellWindow::selectSchool, this, 2), 456, this));
interactiveAreas.push_back(std::make_shared<InteractiveArea>( Rect( 549 + pos.x, 330 + pos.y, 45, 35), std::bind(&CSpellWindow::selectSchool, this, 4), 458, this));
temp_rect = CSDL_Ext::genRect(36, 56, 549 + pos.x, 94 + pos.y);
interactiveAreas.push_back(std::make_shared<InteractiveArea>(temp_rect, std::bind(&CSpellWindow::selectSchool, this, 0), 454, this));
temp_rect = CSDL_Ext::genRect(36, 56, 549 + pos.x, 151 + pos.y);
interactiveAreas.push_back(std::make_shared<InteractiveArea>(temp_rect, std::bind(&CSpellWindow::selectSchool, this, 3), 457, this));
temp_rect = CSDL_Ext::genRect(36, 56, 549 + pos.x, 210 + pos.y);
interactiveAreas.push_back(std::make_shared<InteractiveArea>(temp_rect, std::bind(&CSpellWindow::selectSchool, this, 1), 455, this));
temp_rect = CSDL_Ext::genRect(36, 56, 549 + pos.x, 270 + pos.y);
interactiveAreas.push_back(std::make_shared<InteractiveArea>(temp_rect, std::bind(&CSpellWindow::selectSchool, this, 2), 456, this));
temp_rect = CSDL_Ext::genRect(36, 56, 549 + pos.x, 330 + pos.y);
interactiveAreas.push_back(std::make_shared<InteractiveArea>(temp_rect, std::bind(&CSpellWindow::selectSchool, this, 4), 458, this));
temp_rect = CSDL_Ext::genRect(leftCorner->pos.h, leftCorner->pos.w, 97 + pos.x, 77 + pos.y);
interactiveAreas.push_back(std::make_shared<InteractiveArea>(temp_rect, std::bind(&CSpellWindow::fLcornerb, this), 450, this));
temp_rect = CSDL_Ext::genRect(rightCorner->pos.h, rightCorner->pos.w, 487 + pos.x, 72 + pos.y);
interactiveAreas.push_back(std::make_shared<InteractiveArea>(temp_rect, std::bind(&CSpellWindow::fRcornerb, this), 451, this));
interactiveAreas.push_back(std::make_shared<InteractiveArea>( Rect( 97 + pos.x, 77 + pos.y, leftCorner->pos.h, leftCorner->pos.w ), std::bind(&CSpellWindow::fLcornerb, this), 450, this));
interactiveAreas.push_back(std::make_shared<InteractiveArea>( Rect( 487 + pos.x, 72 + pos.y, rightCorner->pos.h, rightCorner->pos.w ), std::bind(&CSpellWindow::fRcornerb, this), 451, this));
//areas for spells
int xpos = 117 + pos.x, ypos = 90 + pos.y;
for(int v=0; v<12; ++v)
{
temp_rect = CSDL_Ext::genRect(65, 78, xpos, ypos);
spellAreas[v] = std::make_shared<SpellArea>(temp_rect, this);
spellAreas[v] = std::make_shared<SpellArea>( Rect(xpos, ypos, 65, 78), this);
if(v == 5) //to right page
{
@ -422,17 +407,16 @@ void CSpellWindow::turnPageRight()
CCS->videoh->openAndPlayVideo("PGTRNRGH.SMK", pos.x+13, pos.y+15);
}
void CSpellWindow::keyPressed(const SDL_KeyboardEvent & key)
void CSpellWindow::keyPressed(const SDL_Keycode & key)
{
if(key.keysym.sym == SDLK_ESCAPE || key.keysym.sym == SDLK_RETURN)
if(key == SDLK_ESCAPE || key == SDLK_RETURN)
{
fexitb();
return;
}
if(key.state == SDL_PRESSED)
else
{
switch(key.keysym.sym)
switch(key)
{
case SDLK_LEFT:
fLcornerb();
@ -443,7 +427,7 @@ void CSpellWindow::keyPressed(const SDL_KeyboardEvent & key)
case SDLK_UP:
case SDLK_DOWN:
{
bool down = key.keysym.sym == SDLK_DOWN;
bool down = key == SDLK_DOWN;
static const int schoolsOrder[] = { 0, 3, 1, 2, 4 };
int index = -1;
while(schoolsOrder[++index] != selectedTab);
@ -464,9 +448,9 @@ void CSpellWindow::keyPressed(const SDL_KeyboardEvent & key)
}
//alt + 1234567890-= casts spell from 1 - 12 slot
if(myInt->altPressed())
if(GH.isKeyboardAltDown())
{
SDL_Keycode hlpKey = key.keysym.sym;
SDL_Keycode hlpKey = key;
if(CGuiHandler::isNumKey(hlpKey, false))
{
if(hlpKey == SDLK_KP_PLUS)

View File

@ -112,6 +112,7 @@ public:
void selectSchool(int school); //schools: 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic, 4 - all schools
int pagesWithinCurrentTab();
void keyPressed(const SDL_KeyboardEvent & key) override;
void keyPressed(const SDL_Keycode & key) override;
void show(SDL_Surface * to) override;
};

View File

@ -504,9 +504,13 @@ void CTradeWindow::getPositionsFor(std::vector<Rect> &poss, bool Left, EType typ
const std::vector<Rect> tmp =
{
CSDL_Ext::genRect(h, w, x, y), CSDL_Ext::genRect(h, w, x + dx, y), CSDL_Ext::genRect(h, w, x + 2*dx, y),
CSDL_Ext::genRect(h, w, x, y + dy), CSDL_Ext::genRect(h, w, x + dx, y + dy), CSDL_Ext::genRect(h, w, x + 2*dx, y + dy),
CSDL_Ext::genRect(h, w, x + dx, y + 2*dy)
Rect(Point(x + 0 * dx, y + 0 * dx), Point(h, w) ),
Rect(Point(x + 1 * dx, y + 0 * dx), Point(h, w) ),
Rect(Point(x + 2 * dx, y + 0 * dx), Point(h, w) ),
Rect(Point(x + 0 * dx, y + 1 * dy), Point(h, w) ),
Rect(Point(x + 1 * dx, y + 1 * dy), Point(h, w) ),
Rect(Point(x + 2 * dx, y + 1 * dy), Point(h, w) ),
Rect(Point(x + 1 * dx, y + 2 * dy), Point(h, w) )
};
vstd::concatenate(poss, tmp);

View File

@ -69,7 +69,7 @@ CWindowObject::CWindowObject(int options_, std::string imageName):
if(background)
pos = background->center();
else
center(Point(screen->w/2, screen->h/2));
center(GH.screenDimensions() / 2);
if(!(options & SHADOW_DISABLED))
setShadow(true);

View File

@ -63,10 +63,6 @@
#include "../lib/NetPacksBase.h"
#include "../lib/StartInfo.h"
#include <SDL_events.h>
using namespace CSDL_Ext;
CRecruitmentWindow::CCreatureCard::CCreatureCard(CRecruitmentWindow * window, const CCreature * crea, int totalAmount)
: CIntObject(LCLICK | RCLICK),
parent(window),
@ -103,9 +99,9 @@ void CRecruitmentWindow::CCreatureCard::showAll(SDL_Surface * to)
{
CIntObject::showAll(to);
if(selected)
drawBorder(to, pos, Colors::RED);
CSDL_Ext::drawBorder(to, pos, Colors::RED);
else
drawBorder(to, pos, Colors::YELLOW);
CSDL_Ext::drawBorder(to, pos, Colors::YELLOW);
}
void CRecruitmentWindow::select(std::shared_ptr<CCreatureCard> card)
@ -180,17 +176,17 @@ void CRecruitmentWindow::showAll(SDL_Surface * to)
CWindowObject::showAll(to);
// recruit\total values
drawBorder(to, pos.x + 172, pos.y + 222, 67, 42, Colors::YELLOW);
drawBorder(to, pos.x + 246, pos.y + 222, 67, 42, Colors::YELLOW);
CSDL_Ext::drawBorder(to, pos.x + 172, pos.y + 222, 67, 42, Colors::YELLOW);
CSDL_Ext::drawBorder(to, pos.x + 246, pos.y + 222, 67, 42, Colors::YELLOW);
//cost boxes
drawBorder(to, pos.x + 64, pos.y + 222, 99, 76, Colors::YELLOW);
drawBorder(to, pos.x + 322, pos.y + 222, 99, 76, Colors::YELLOW);
CSDL_Ext::drawBorder(to, pos.x + 64, pos.y + 222, 99, 76, Colors::YELLOW);
CSDL_Ext::drawBorder(to, pos.x + 322, pos.y + 222, 99, 76, Colors::YELLOW);
//buttons borders
drawBorder(to, pos.x + 133, pos.y + 312, 66, 34, Colors::METALLIC_GOLD);
drawBorder(to, pos.x + 211, pos.y + 312, 66, 34, Colors::METALLIC_GOLD);
drawBorder(to, pos.x + 289, pos.y + 312, 66, 34, Colors::METALLIC_GOLD);
CSDL_Ext::drawBorder(to, pos.x + 133, pos.y + 312, 66, 34, Colors::METALLIC_GOLD);
CSDL_Ext::drawBorder(to, pos.x + 211, pos.y + 312, 66, 34, Colors::METALLIC_GOLD);
CSDL_Ext::drawBorder(to, pos.x + 289, pos.y + 312, 66, 34, Colors::METALLIC_GOLD);
}
CRecruitmentWindow::CRecruitmentWindow(const CGDwelling * Dwelling, int Level, const CArmedInstance * Dst, const std::function<void(CreatureID,int)> & Recruit, int y_offset):
@ -921,9 +917,9 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
{
primSkillAreas.push_back(std::make_shared<LRClickableAreaWTextComp>());
if (qeLayout)
primSkillAreas[g]->pos = genRect(22, 152, pos.x + 324, pos.y + 12 + 26 * g);
primSkillAreas[g]->pos = Rect(Point(pos.x + 324, pos.y + 12 + 26 * g), Point(22, 152));
else
primSkillAreas[g]->pos = genRect(32, 140, pos.x + 329, pos.y + 19 + 36 * g);
primSkillAreas[g]->pos = Rect(Point(pos.x + 329, pos.y + 19 + 36 * g), Point(32, 140));
primSkillAreas[g]->text = CGI->generaltexth->arraytxt[2+g];
primSkillAreas[g]->type = g;
primSkillAreas[g]->bonusValue = -1;
@ -943,7 +939,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
int skill = hero->secSkills[g].first,
level = hero->secSkills[g].second; // <1, 3>
secSkillAreas[b].push_back(std::make_shared<LRClickableAreaWTextComp>());
secSkillAreas[b][g]->pos = genRect(32, 32, pos.x + 32 + g*36 + b*454 , pos.y + (qeLayout ? 83 : 88));
secSkillAreas[b][g]->pos = Rect(Point(pos.x + 32 + g * 36 + b * 454 , pos.y + (qeLayout ? 83 : 88)), Point(32, 32) );
secSkillAreas[b][g]->baseType = 1;
secSkillAreas[b][g]->type = skill;
@ -958,12 +954,12 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
heroAreas[b] = std::make_shared<CHeroArea>(257 + 228*b, 13, hero);
specialtyAreas[b] = std::make_shared<LRClickableAreaWText>();
specialtyAreas[b]->pos = genRect(32, 32, pos.x + 69 + 490*b, pos.y + (qeLayout ? 41 : 45));
specialtyAreas[b]->pos = Rect(Point(pos.x + 69 + 490 * b, pos.y + (qeLayout ? 41 : 45)), Point(32, 32));
specialtyAreas[b]->hoverText = CGI->generaltexth->heroscrn[27];
specialtyAreas[b]->text = hero->type->getSpecialtyDescriptionTranslated();
experienceAreas[b] = std::make_shared<LRClickableAreaWText>();
experienceAreas[b]->pos = genRect(32, 32, pos.x + 105 + 490*b, pos.y + (qeLayout ? 41 : 45));
experienceAreas[b]->pos = Rect(Point(pos.x + 105 + 490 * b, pos.y + (qeLayout ? 41 : 45)), Point(32, 32));
experienceAreas[b]->hoverText = CGI->generaltexth->heroscrn[9];
experienceAreas[b]->text = CGI->generaltexth->allTexts[2];
boost::algorithm::replace_first(experienceAreas[b]->text, "%d", boost::lexical_cast<std::string>(hero->level));
@ -971,15 +967,15 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2,
boost::algorithm::replace_first(experienceAreas[b]->text, "%d", boost::lexical_cast<std::string>(hero->exp));
spellPointsAreas[b] = std::make_shared<LRClickableAreaWText>();
spellPointsAreas[b]->pos = genRect(32, 32, pos.x + 141 + 490*b, pos.y + (qeLayout ? 41 : 45));
spellPointsAreas[b]->pos = Rect(Point(pos.x + 141 + 490 * b, pos.y + (qeLayout ? 41 : 45)), Point(32, 32));
spellPointsAreas[b]->hoverText = CGI->generaltexth->heroscrn[22];
spellPointsAreas[b]->text = CGI->generaltexth->allTexts[205];
boost::algorithm::replace_first(spellPointsAreas[b]->text, "%s", hero->getNameTranslated());
boost::algorithm::replace_first(spellPointsAreas[b]->text, "%d", boost::lexical_cast<std::string>(hero->mana));
boost::algorithm::replace_first(spellPointsAreas[b]->text, "%d", boost::lexical_cast<std::string>(hero->manaLimit()));
morale[b] = std::make_shared<MoraleLuckBox>(true, genRect(32, 32, 176 + 490 * b, 39), true);
luck[b] = std::make_shared<MoraleLuckBox>(false, genRect(32, 32, 212 + 490 * b, 39), true);
morale[b] = std::make_shared<MoraleLuckBox>(true, Rect(Point(176 + 490 * b, 39), Point(32, 32)), true);
luck[b] = std::make_shared<MoraleLuckBox>(false, Rect(Point(212 + 490 * b, 39), Point(32, 32)), true);
}
quit = std::make_shared<CButton>(Point(732, 567), "IOKAY.DEF", CGI->generaltexth->zelp[600], std::bind(&CExchangeWindow::close, this), SDLK_RETURN);
@ -1067,8 +1063,8 @@ void CExchangeWindow::updateWidgets()
secSkillIcons[leftRight][m]->setFrame(2 + id * 3 + level);
}
expValues[leftRight]->setText(makeNumberShort(hero->exp));
manaValues[leftRight]->setText(makeNumberShort(hero->mana));
expValues[leftRight]->setText(vstd::formatMetric(hero->exp, 3));
manaValues[leftRight]->setText(vstd::formatMetric(hero->mana, 3));
morale[leftRight]->set(hero);
luck[leftRight]->set(hero);
@ -1161,7 +1157,7 @@ CPuzzleWindow::CPuzzleWindow(const int3 & GrailPos, double discoveredRatio)
void CPuzzleWindow::showAll(SDL_Surface * to)
{
int3 moveInt = int3(8, 9, 0);
Rect mapRect = genRect(544, 591, pos.x + 8, pos.y + 7);
Rect mapRect = Rect(Point(pos.x + 8, pos.y + 7), Point(544, 591));
int3 topTile = grailPos - moveInt;
MapDrawingInfo info(topTile, LOCPLINT->cb->getVisibilityMap(), mapRect);
@ -1951,14 +1947,11 @@ void CObjectListWindow::changeSelection(size_t which)
selected = which;
}
void CObjectListWindow::keyPressed (const SDL_KeyboardEvent & key)
void CObjectListWindow::keyPressed (const SDL_Keycode & key)
{
if(key.state != SDL_PRESSED)
return;
int sel = static_cast<int>(selected);
switch(key.keysym.sym)
switch(key)
{
break; case SDLK_UP:
sel -=1;

View File

@ -43,6 +43,8 @@ class CTextBox;
class CResDataBar;
class CHeroWithMaybePickedArtifact;
enum class EUserEvent;
/// Recruitment window where you can recruit creatures
class CRecruitmentWindow : public CStatusbarWindow
{
@ -193,7 +195,7 @@ public:
std::shared_ptr<CIntObject> genItem(size_t index);
void elementSelected();//call callback and close this window
void changeSelection(size_t which);
void keyPressed (const SDL_KeyboardEvent & key) override;
void keyPressed(const SDL_Keycode & key) override;
};
class CTavernWindow : public CStatusbarWindow

View File

@ -245,8 +245,8 @@ CInfoPopup::CInfoPopup(SDL_Surface *Bitmap, bool Free)
if(bitmap)
{
pos.x = screen->w/2 - bitmap->w/2;
pos.y = screen->h/2 - bitmap->h/2;
pos.x = GH.screenDimensions().x / 2 - bitmap->w / 2;
pos.y = GH.screenDimensions().y / 2 - bitmap->h / 2;
pos.h = bitmap->h;
pos.w = bitmap->w;
}
@ -281,8 +281,8 @@ void CInfoPopup::init(int x, int y)
// Put the window back on screen if necessary
vstd::amax(pos.x, 0);
vstd::amax(pos.y, 0);
vstd::amin(pos.x, screen->w - bitmap->w);
vstd::amin(pos.y, screen->h - bitmap->h);
vstd::amin(pos.x, GH.screenDimensions().x - bitmap->w);
vstd::amin(pos.y, GH.screenDimensions().y - bitmap->h);
}

View File

@ -26,6 +26,7 @@
#include "VcmiSettingsWindow.h"
#include "GUIClasses.h"
#include "CServerHandler.h"
#include "renderSDL/SDL_Extensions.h"
static void setIntSetting(std::string group, std::string field, int value)
@ -110,8 +111,7 @@ void SystemOptionsWindow::selectGameResolution()
std::vector<std::string> items;
#ifndef VCMI_IOS
SDL_Rect displayBounds;
SDL_GetDisplayBounds(std::max(0, SDL_GetWindowDisplayIndex(mainWindow)), &displayBounds);
Rect displayBounds = CSDL_Ext::getDisplayBounds();
#endif
size_t currentResolutionIndex = 0;

View File

@ -239,8 +239,6 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
${MAIN_LIB_DIR}/../include/vcmi/Environment.h
${MAIN_LIB_DIR}/../include/vcmi/Services.h
${MAIN_LIB_DIR}/abilities/Ability.h
${MAIN_LIB_DIR}/battle/AccessibilityInfo.h
${MAIN_LIB_DIR}/battle/BattleAction.h
${MAIN_LIB_DIR}/battle/BattleAttackInfo.h
@ -477,7 +475,6 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
PUBLIC ${MAIN_LIB_DIR}/..
PUBLIC ${MAIN_LIB_DIR}/../include
PUBLIC ${MAIN_LIB_DIR}
PRIVATE ${SDL2_INCLUDE_DIR}
)
if(WIN32)

View File

@ -10,4 +10,4 @@ add_definitions(
set(APP_SHORT_VERSION "${VCMI_VERSION_MAJOR}.${VCMI_VERSION_MINOR}")
if(NOT VCMI_VERSION_PATCH EQUAL 0)
string(APPEND APP_SHORT_VERSION ".${VCMI_VERSION_PATCH}")
endif()
endif()

View File

@ -213,8 +213,9 @@
"specialty" : {
"bonuses" : {
"fortune" : {
"addInfo" : 3,
"subtype" : "spell.fortune",
"type" : "MAXED_SPELL"
"type" : "SPECIAL_FIXED_VALUE_ENCHANT"
}
}
}

8
debian/changelog vendored
View File

@ -2,8 +2,14 @@ vcmi (1.2.0) jammy; urgency=medium
* New upstream release
-- Ivan Savenko <saven.ivan@gmail.com> Fri, 23 Dec 2022 16:00:00 +0200
-- Ivan Savenko <saven.ivan@gmail.com> Sat, 04 Feb 2023 16:00:00 +0200
vcmi (1.1.1) jammy; urgency=medium
* New upstream release
-- Ivan Savenko <saven.ivan@gmail.com> Fri, 03 Feb 2023 12:00:00 +0200
vcmi (1.1.0) jammy; urgency=medium
* New upstream release

View File

@ -5,8 +5,8 @@ VCMI_LIB_NAMESPACE_BEGIN
namespace vstd
{
DLL_LINKAGE std::vector<std::string> split(std::string s, std::string separators);
DLL_LINKAGE std::pair<std::string, std::string> splitStringToPair(std::string input, char separator);
DLL_LINKAGE std::vector<std::string> split(std::string s, const std::string& separators);
DLL_LINKAGE std::pair<std::string, std::string> splitStringToPair(const std::string& input, char separator);
}

View File

@ -38,7 +38,8 @@
<url type="bugtracker">https://github.com/vcmi/vcmi/issues</url>
<url type="faq">https://vcmi.eu/faq/</url>
<releases>
<release version="1.2.0" date="2022-12-24" type="development" />
<release version="1.2.0" date="2023-02-04" type="development" />
<release version="1.1.1" date="2023-02-03" />
<release version="1.1.0" date="2022-12-23" />
<release version="1.0.0" date="2022-09-11" />
<release version="0.99" date="2016-11-01" />

View File

@ -611,8 +611,9 @@ std::vector<std::shared_ptr<Bonus>> SpecialtyInfoToBonuses(const SSpecialtyInfo
result.push_back(bonus);
break;
case 7: //maxed mastery for spell
bonus->type = Bonus::MAXED_SPELL;
bonus->type = Bonus::SPECIAL_FIXED_VALUE_ENCHANT;
bonus->subtype = spec.subtype; //spell id
bonus->val = 3; //to match MAXED_BONUS
result.push_back(bonus);
break;
case 8: //peculiar spells - enchantments

View File

@ -285,7 +285,7 @@ public:
BONUS_NAME(SPELL_DAMAGE) /*val = value*/\
BONUS_NAME(SPECIFIC_SPELL_DAMAGE) /*subtype = id of spell, val = value*/\
BONUS_NAME(SPECIAL_BLESS_DAMAGE) /*val = spell (bless), additionalInfo = value per level in percent*/\
BONUS_NAME(MAXED_SPELL) /*val = id*/\
BONUS_NAME(MAXED_SPELL) /*val = id. deprecated in favour of SPECIAL_FIXED_VALUE_ENCHANT*/\
BONUS_NAME(SPECIAL_PECULIAR_ENCHANT) /*blesses and curses with id = val dependent on unit's level, subtype = 0 or 1 for Coronius*/\
BONUS_NAME(SPECIAL_UPGRADE) /*subtype = base, additionalInfo = target */\
BONUS_NAME(DRAGON_NATURE) \

View File

@ -281,7 +281,6 @@
<Unit filename="VCMIDirs.h" />
<Unit filename="VCMI_Lib.cpp" />
<Unit filename="VCMI_Lib.h" />
<Unit filename="abilities/Ability.h" />
<Unit filename="battle/AccessibilityInfo.cpp" />
<Unit filename="battle/AccessibilityInfo.h" />
<Unit filename="battle/BattleAction.cpp" />

View File

@ -39,6 +39,10 @@ struct DLL_LINKAGE BattleHex //TODO: decide if this should be changed to class f
static const si16 CASTLE_BOTTOM_TOWER = -3;
static const si16 CASTLE_UPPER_TOWER = -4;
// hexes for interaction with heroes
static const si16 HERO_ATTACKER = 0;
static const si16 HERO_DEFENDER = GameConstants::BFIELD_WIDTH - 1;
// helpers for rendering
static const si16 HEX_BEFORE_ALL = std::numeric_limits<si16>::min();
static const si16 HEX_AFTER_ALL = std::numeric_limits<si16>::max();

View File

@ -44,13 +44,28 @@ struct DLL_LINKAGE AttackableTiles
enum class PossiblePlayerBattleAction // actions performed at l-click
{
INVALID = -1, CREATURE_INFO,
MOVE_TACTICS, CHOOSE_TACTICS_STACK,
MOVE_STACK, ATTACK, WALK_AND_ATTACK, ATTACK_AND_RETURN, SHOOT, //OPEN_GATE, //we can open castle gate during siege
NO_LOCATION, ANY_LOCATION, OBSTACLE, TELEPORT, SACRIFICE, RANDOM_GENIE_SPELL,
FREE_LOCATION, //used with Force Field and Fire Wall - all tiles affected by spell must be free
CATAPULT, HEAL,
AIMED_SPELL_CREATURE
INVALID = -1,
CREATURE_INFO,
HERO_INFO,
MOVE_TACTICS,
CHOOSE_TACTICS_STACK,
MOVE_STACK,
ATTACK,
WALK_AND_ATTACK,
ATTACK_AND_RETURN,
SHOOT,
CATAPULT,
HEAL,
NO_LOCATION, // massive spells that affect every possible target, automatic casts
ANY_LOCATION,
OBSTACLE,
TELEPORT,
SACRIFICE,
RANDOM_GENIE_SPELL, // random spell on a friendly creature
FREE_LOCATION, // used with Force Field and Fire Wall - all tiles affected by spell must be free
AIMED_SPELL_CREATURE, // spell targeted at creature
};
struct DLL_LINKAGE BattleClientInterfaceData

View File

@ -10,14 +10,12 @@
#include "StdInc.h"
#include "CBinaryReader.h"
//FIXME:library file depends on SDL - make cause troubles
#include <SDL_endian.h>
#include "CInputStream.h"
#include "../CGeneralTextHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#ifdef VCMI_ENDIAN_BIG
template <typename CData>
CData readLE(CData data)
{

View File

@ -647,10 +647,7 @@ int64_t CGHeroInstance::getSpecificSpellBonus(const spells::Spell * spell, int64
int32_t CGHeroInstance::getEffectLevel(const spells::Spell * spell) const
{
if(hasBonusOfType(Bonus::MAXED_SPELL, spell->getIndex()))
return 3;//todo: recheck specialty from where this bonus is. possible bug
else
return getSpellSchoolLevel(spell);
return getSpellSchoolLevel(spell);
}
int32_t CGHeroInstance::getEffectPower(const spells::Spell * spell) const

View File

@ -81,8 +81,8 @@ void CRandomRewardObjectInfo::configureLimiter(CRewardableObject * object, CRand
limiter.primary = JsonRandom::loadPrimary(source["primary"], rng);
limiter.secondary = JsonRandom::loadSecondary(source["secondary"], rng);
limiter.artifacts = JsonRandom::loadArtifacts(source["spells"], rng);
limiter.spells = JsonRandom::loadSpells(source["artifacts"], rng, spells);
limiter.artifacts = JsonRandom::loadArtifacts(source["artifacts"], rng);
limiter.spells = JsonRandom::loadSpells(source["spells"], rng, spells);
limiter.creatures = JsonRandom::loadCreatures(source["creatures"], rng);
limiter.allOf = configureSublimiters(object, rng, source["allOf"] );

Some files were not shown because too many files have changed in this diff Show More