mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-21 17:17:06 +02:00
Merge branch 'vcmi/beta' into 'vcmi/develop'
This commit is contained in:
commit
3bea383b59
26
.github/workflows/github.yml
vendored
26
.github/workflows/github.yml
vendored
@ -66,7 +66,7 @@ jobs:
|
||||
pack: 1
|
||||
pack_type: RelWithDebInfo
|
||||
extension: exe
|
||||
preset: windows-msvc-release-ccache
|
||||
preset: windows-msvc-release
|
||||
- platform: mingw
|
||||
os: ubuntu-22.04
|
||||
test: 0
|
||||
@ -207,8 +207,15 @@ jobs:
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
if [[ ${{matrix.preset}} == linux-gcc-test ]]; then GCC14=1; fi
|
||||
cmake -DENABLE_CCACHE:BOOL=ON --preset ${{ matrix.preset }} ${GCC14:+-DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14}
|
||||
if [[ ${{matrix.preset}} == linux-gcc-test ]]
|
||||
then
|
||||
cmake -DENABLE_CCACHE:BOOL=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 --preset ${{ matrix.preset }}
|
||||
elif [[ ${{matrix.platform}} != msvc ]]
|
||||
then
|
||||
cmake -DENABLE_CCACHE:BOOL=ON --preset ${{ matrix.preset }}
|
||||
else
|
||||
cmake --preset ${{ matrix.preset }}
|
||||
fi
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
@ -283,7 +290,7 @@ jobs:
|
||||
with:
|
||||
name: Android JNI ${{matrix.platform}}
|
||||
path: |
|
||||
${{ github.workspace }}/android/vcmi-app/src/main/jniLibs
|
||||
${{github.workspace}}/out/build/${{matrix.preset}}/android-build/libs
|
||||
|
||||
- name: Upload build
|
||||
if: ${{ (matrix.pack == 1 || startsWith(matrix.platform, 'android')) && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/beta' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/features/')) && matrix.platform != 'msvc' && matrix.platform != 'mingw-32' }}
|
||||
@ -306,7 +313,7 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- platform: android-32
|
||||
os: ubuntu-22.04
|
||||
os: macos-14
|
||||
preset: android-conan-ninja-release
|
||||
conan_profile: android-32
|
||||
conan_options: --conf tools.android:ndk_path=$ANDROID_NDK_ROOT
|
||||
@ -346,6 +353,12 @@ jobs:
|
||||
env:
|
||||
GENERATE_ONLY_BUILT_CONFIG: 1
|
||||
|
||||
- uses: actions/setup-java@v4
|
||||
if: ${{ startsWith(matrix.platform, 'android') }}
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '11'
|
||||
|
||||
- name: Build Number
|
||||
run: |
|
||||
source '${{github.workspace}}/CI/get_package_name.sh'
|
||||
@ -365,6 +378,9 @@ jobs:
|
||||
- name: Build Preset
|
||||
run: |
|
||||
cmake --build --preset ${{matrix.preset}}
|
||||
env:
|
||||
ANDROID_STORE_PASSWORD: ${{ secrets.ANDROID_STORE_PASSWORD }}
|
||||
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
||||
|
||||
- name: Download libs x64
|
||||
uses: actions/download-artifact@v4
|
||||
|
@ -259,27 +259,46 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector
|
||||
return BattleAction::makeDefend(stack);
|
||||
}
|
||||
|
||||
std::sort(hexes.begin(), hexes.end(), [&](BattleHex h1, BattleHex h2) -> bool
|
||||
{
|
||||
return reachability.distances[h1] < reachability.distances[h2];
|
||||
});
|
||||
std::vector<BattleHex> targetHexes = hexes;
|
||||
|
||||
for(auto hex : hexes)
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
if(vstd::contains(avHexes, hex))
|
||||
std::sort(targetHexes.begin(), targetHexes.end(), [&](BattleHex h1, BattleHex h2) -> bool
|
||||
{
|
||||
return reachability.distances[h1] < reachability.distances[h2];
|
||||
});
|
||||
|
||||
for(auto hex : targetHexes)
|
||||
{
|
||||
return BattleAction::makeMove(stack, hex);
|
||||
if(vstd::contains(avHexes, hex))
|
||||
{
|
||||
return BattleAction::makeMove(stack, hex);
|
||||
}
|
||||
|
||||
if(stack->coversPos(hex))
|
||||
{
|
||||
logAi->warn("Warning: already standing on neighbouring tile!");
|
||||
//We shouldn't even be here...
|
||||
return BattleAction::makeDefend(stack);
|
||||
}
|
||||
}
|
||||
|
||||
if(stack->coversPos(hex))
|
||||
if(reachability.distances[targetHexes.front()] <= GameConstants::BFIELD_SIZE)
|
||||
{
|
||||
logAi->warn("Warning: already standing on neighbouring tile!");
|
||||
//We shouldn't even be here...
|
||||
return BattleAction::makeDefend(stack);
|
||||
break;
|
||||
}
|
||||
|
||||
std::vector<BattleHex> copy = targetHexes;
|
||||
|
||||
for(auto hex : copy)
|
||||
{
|
||||
vstd::concatenate(targetHexes, hex.allNeighbouringTiles());
|
||||
}
|
||||
|
||||
vstd::removeDuplicates(targetHexes);
|
||||
}
|
||||
|
||||
BattleHex bestNeighbor = hexes.front();
|
||||
BattleHex bestNeighbor = targetHexes.front();
|
||||
|
||||
if(reachability.distances[bestNeighbor] > GameConstants::BFIELD_SIZE)
|
||||
{
|
||||
@ -602,10 +621,10 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
|
||||
ps.value = scoreEvaluator.evaluateExchange(*cachedAttack, 0, *targets, innerCache, state);
|
||||
}
|
||||
|
||||
for(auto unit : allUnits)
|
||||
for(const auto & unit : allUnits)
|
||||
{
|
||||
auto newHealth = unit->getAvailableHealth();
|
||||
auto oldHealth = healthOfStack[unit->unitId()];
|
||||
auto oldHealth = vstd::find_or(healthOfStack, unit->unitId(), 0); // old health value may not exist for newly summoned units
|
||||
|
||||
if(oldHealth != newHealth)
|
||||
{
|
||||
@ -732,6 +751,3 @@ void BattleEvaluator::print(const std::string & text) const
|
||||
{
|
||||
logAi->trace("%s Battle AI[%p]: %s", playerID.toString(), this, text);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -390,7 +390,7 @@ ReachabilityData BattleExchangeEvaluator::getExchangeUnits(
|
||||
const AttackPossibility & ap,
|
||||
uint8_t turn,
|
||||
PotentialTargets & targets,
|
||||
std::shared_ptr<HypotheticBattle> hb)
|
||||
std::shared_ptr<HypotheticBattle> hb) const
|
||||
{
|
||||
ReachabilityData result;
|
||||
|
||||
@ -402,7 +402,7 @@ ReachabilityData BattleExchangeEvaluator::getExchangeUnits(
|
||||
|
||||
for(auto hex : hexes)
|
||||
{
|
||||
vstd::concatenate(allReachableUnits, turn == 0 ? reachabilityMap[hex] : getOneTurnReachableUnits(turn, hex));
|
||||
vstd::concatenate(allReachableUnits, turn == 0 ? reachabilityMap.at(hex) : getOneTurnReachableUnits(turn, hex));
|
||||
}
|
||||
|
||||
vstd::removeDuplicates(allReachableUnits);
|
||||
@ -481,7 +481,7 @@ float BattleExchangeEvaluator::evaluateExchange(
|
||||
uint8_t turn,
|
||||
PotentialTargets & targets,
|
||||
DamageCache & damageCache,
|
||||
std::shared_ptr<HypotheticBattle> hb)
|
||||
std::shared_ptr<HypotheticBattle> hb) const
|
||||
{
|
||||
BattleScore score = calculateExchange(ap, turn, targets, damageCache, hb);
|
||||
|
||||
@ -502,7 +502,7 @@ BattleScore BattleExchangeEvaluator::calculateExchange(
|
||||
uint8_t turn,
|
||||
PotentialTargets & targets,
|
||||
DamageCache & damageCache,
|
||||
std::shared_ptr<HypotheticBattle> hb)
|
||||
std::shared_ptr<HypotheticBattle> hb) const
|
||||
{
|
||||
#if BATTLE_TRACE_LEVEL>=1
|
||||
logAi->trace("Battle exchange at %d", ap.attack.shooting ? ap.dest.hex : ap.from.hex);
|
||||
@ -613,7 +613,7 @@ BattleScore BattleExchangeEvaluator::calculateExchange(
|
||||
}
|
||||
else
|
||||
{
|
||||
auto reachable = exchangeBattle->battleGetUnitsIf([&](const battle::Unit * u) -> bool
|
||||
auto reachable = exchangeBattle->battleGetUnitsIf([this, &exchangeBattle, &attacker](const battle::Unit * u) -> bool
|
||||
{
|
||||
if(u->unitSide() == attacker->unitSide())
|
||||
return false;
|
||||
@ -621,7 +621,10 @@ BattleScore BattleExchangeEvaluator::calculateExchange(
|
||||
if(!exchangeBattle->getForUpdate(u->unitId())->alive())
|
||||
return false;
|
||||
|
||||
return vstd::contains_if(reachabilityMap[u->getPosition()], [&](const battle::Unit * other) -> bool
|
||||
if (!u->getPosition().isValid())
|
||||
return false; // e.g. tower shooters
|
||||
|
||||
return vstd::contains_if(reachabilityMap.at(u->getPosition()), [&attacker](const battle::Unit * other) -> bool
|
||||
{
|
||||
return attacker->unitId() == other->unitId();
|
||||
});
|
||||
@ -732,7 +735,7 @@ void BattleExchangeEvaluator::updateReachabilityMap(std::shared_ptr<HypotheticBa
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<const battle::Unit *> BattleExchangeEvaluator::getOneTurnReachableUnits(uint8_t turn, BattleHex hex)
|
||||
std::vector<const battle::Unit *> BattleExchangeEvaluator::getOneTurnReachableUnits(uint8_t turn, BattleHex hex) const
|
||||
{
|
||||
std::vector<const battle::Unit *> result;
|
||||
|
||||
@ -756,13 +759,10 @@ std::vector<const battle::Unit *> BattleExchangeEvaluator::getOneTurnReachableUn
|
||||
auto unitSpeed = unit->getMovementRange(turn);
|
||||
auto radius = unitSpeed * (turn + 1);
|
||||
|
||||
ReachabilityInfo unitReachability = vstd::getOrCompute(
|
||||
reachabilityCache,
|
||||
unit->unitId(),
|
||||
[&](ReachabilityInfo & data)
|
||||
{
|
||||
data = turnBattle.getReachability(unit);
|
||||
});
|
||||
auto reachabilityIter = reachabilityCache.find(unit->unitId());
|
||||
assert(reachabilityIter != reachabilityCache.end()); // missing updateReachabilityMap call?
|
||||
|
||||
ReachabilityInfo unitReachability = reachabilityIter != reachabilityCache.end() ? reachabilityIter->second : turnBattle.getReachability(unit);
|
||||
|
||||
bool reachable = unitReachability.distances[hex] <= radius;
|
||||
|
||||
|
@ -139,7 +139,7 @@ private:
|
||||
uint8_t turn,
|
||||
PotentialTargets & targets,
|
||||
DamageCache & damageCache,
|
||||
std::shared_ptr<HypotheticBattle> hb);
|
||||
std::shared_ptr<HypotheticBattle> hb) const;
|
||||
|
||||
bool canBeHitThisTurn(const AttackPossibility & ap);
|
||||
|
||||
@ -162,16 +162,16 @@ public:
|
||||
uint8_t turn,
|
||||
PotentialTargets & targets,
|
||||
DamageCache & damageCache,
|
||||
std::shared_ptr<HypotheticBattle> hb);
|
||||
std::shared_ptr<HypotheticBattle> hb) const;
|
||||
|
||||
std::vector<const battle::Unit *> getOneTurnReachableUnits(uint8_t turn, BattleHex hex);
|
||||
std::vector<const battle::Unit *> getOneTurnReachableUnits(uint8_t turn, BattleHex hex) const;
|
||||
void updateReachabilityMap(std::shared_ptr<HypotheticBattle> hb);
|
||||
|
||||
ReachabilityData getExchangeUnits(
|
||||
const AttackPossibility & ap,
|
||||
uint8_t turn,
|
||||
PotentialTargets & targets,
|
||||
std::shared_ptr<HypotheticBattle> hb);
|
||||
std::shared_ptr<HypotheticBattle> hb) const;
|
||||
|
||||
bool checkPositionBlocksOurStacks(HypotheticBattle & hb, const battle::Unit * unit, BattleHex position);
|
||||
|
||||
|
@ -1300,7 +1300,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
{
|
||||
destinationTeleport = exitId;
|
||||
if(exitPos.valid())
|
||||
destinationTeleportPos = h->convertFromVisitablePos(exitPos);
|
||||
destinationTeleportPos = exitPos;
|
||||
cb->moveHero(*h, h->pos, false);
|
||||
destinationTeleport = ObjectInstanceID();
|
||||
destinationTeleportPos = int3(-1);
|
||||
@ -1310,17 +1310,32 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
auto doChannelProbing = [&]() -> void
|
||||
{
|
||||
auto currentPos = h->visitablePos();
|
||||
auto currentExit = getObj(currentPos, true)->id;
|
||||
auto currentTeleport = getObj(currentPos, true);
|
||||
|
||||
status.setChannelProbing(true);
|
||||
for(auto exit : teleportChannelProbingList)
|
||||
doTeleportMovement(exit, int3(-1));
|
||||
teleportChannelProbingList.clear();
|
||||
status.setChannelProbing(false);
|
||||
if(currentTeleport)
|
||||
{
|
||||
auto currentExit = currentTeleport->id;
|
||||
|
||||
doTeleportMovement(currentExit, currentPos);
|
||||
status.setChannelProbing(true);
|
||||
for(auto exit : teleportChannelProbingList)
|
||||
doTeleportMovement(exit, int3(-1));
|
||||
teleportChannelProbingList.clear();
|
||||
status.setChannelProbing(false);
|
||||
|
||||
doTeleportMovement(currentExit, currentPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
logAi->debug("Unexpected channel probbing at " + currentPos.toString());
|
||||
|
||||
teleportChannelProbingList.clear();
|
||||
status.setChannelProbing(false);
|
||||
}
|
||||
};
|
||||
|
||||
teleportChannelProbingList.clear();
|
||||
status.setChannelProbing(false);
|
||||
|
||||
for(; i > 0; i--)
|
||||
{
|
||||
int3 currentCoord = path.nodes[i].coord;
|
||||
|
@ -17,10 +17,10 @@ namespace NKAI
|
||||
|
||||
struct ClusterObjectInfo
|
||||
{
|
||||
float priority;
|
||||
float movementCost;
|
||||
uint64_t danger;
|
||||
uint8_t turn;
|
||||
float priority = 0.f;
|
||||
float movementCost = 0.f;
|
||||
uint64_t danger = 0;
|
||||
uint8_t turn = 0;
|
||||
};
|
||||
|
||||
struct ObjectInstanceIDHash
|
||||
|
@ -1203,7 +1203,10 @@ void AINodeStorage::calculateTownPortalTeleportations(std::vector<CGPathNode *>
|
||||
std::vector<const ChainActor *> actorsVector(actorsOfInitial.begin(), actorsOfInitial.end());
|
||||
tbb::concurrent_vector<CGPathNode *> output;
|
||||
|
||||
if(actorsVector.size() * initialNodes.size() > 1000)
|
||||
// TODO: re-enable after fixing thread races. See issue for details:
|
||||
// https://github.com/vcmi/vcmi/pull/4130
|
||||
#if 0
|
||||
if (actorsVector.size() * initialNodes.size() > 1000)
|
||||
{
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>(0, actorsVector.size()), [&](const tbb::blocked_range<size_t> & r)
|
||||
{
|
||||
@ -1216,6 +1219,7 @@ void AINodeStorage::calculateTownPortalTeleportations(std::vector<CGPathNode *>
|
||||
std::copy(output.begin(), output.end(), std::back_inserter(initialNodes));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
for(auto actor : actorsVector)
|
||||
{
|
||||
|
@ -1874,7 +1874,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
{
|
||||
destinationTeleport = exitId;
|
||||
if(exitPos.valid())
|
||||
destinationTeleportPos = h->convertFromVisitablePos(exitPos);
|
||||
destinationTeleportPos = exitPos;
|
||||
cb->moveHero(*h, h->pos, false);
|
||||
destinationTeleport = ObjectInstanceID();
|
||||
destinationTeleportPos = int3(-1);
|
||||
|
76
ChangeLog.md
76
ChangeLog.md
@ -1,3 +1,79 @@
|
||||
# 1.5.2 -> 1.5.3
|
||||
|
||||
### Stability
|
||||
* Fixed possible crash when hero class has no valid commander.
|
||||
* Fixed crash when pressing spacebar or enter during combat when hero has no tactics skill.
|
||||
* Fixed crash when receiving a commander level-up after winning a battle in a garrison owned by an enemy player.
|
||||
* Fixed possible crash when exiting a multiplayer game.
|
||||
* Game will now display an error message and exit after loading instead of crashing silently if a creature's combat animation is missing.
|
||||
* Game should now generate crash dump on uncaught c++ exception throw
|
||||
* Fixed crash when player finishes game with negative score
|
||||
* Fixed crash when opening tavern window in some localisations
|
||||
* Fixed crash on loading previously generated random map when mods that add object with same name are used
|
||||
* Game will now display an error message instead of silent crash if game data directory is not accessible
|
||||
|
||||
### Mechanics
|
||||
* Transport Artefact victory condition will no longer trigger if another player has completed it.
|
||||
* Fixed wandering monster combat not triggering when landing in its zone of control when flying from above the monster using the Fly spell.
|
||||
* Fixed potentially infinite movement loop when the hero has Admiral's Hat whirlpool immunity and the hero tries to enter and exit the same whirlpool.
|
||||
* If game picks gold for a random resource pile that has predetermined by map amount, its amount will be correctly multiplied by 100
|
||||
* Fixed hero not being able to learn spells from a mod in some cases, even if they are available from the town's mage guild.
|
||||
* The game will now actually take resources from seers' huts with the Gather Resources mission instead of awarding them.
|
||||
* Heroes with double spell points will no longer trigger the Mana Vortex.
|
||||
* If turn timer runs out during pve battle game will end player turn after a battle instead of forcing retreat
|
||||
|
||||
### Interface
|
||||
* Fixed reversed button functions in Exchange Window
|
||||
* Fixed allied towns being missing from the list when using the advanced or expert Town Portal spell.
|
||||
* Fixed corrupted UI that could appear for a frame under certain conditions
|
||||
* The '*' symbol and non-printable characters can no longer be used in savegames due to Windows file system restrictions.
|
||||
* Pressing Ctrl while hovering over the adventure map will now display tile coordinates in the status bar.
|
||||
* Selection of another hero while hero is selected now requires Shift press instead of Ctrl
|
||||
* Fixed hero troops in the info box view flashing briefly during hero movement.
|
||||
* Reduced excessive memory usage on adventure map by several hundreds of megabytes (most noticeable on systems with large screen resolution)
|
||||
* Haptic feedback is now enabled by default on Android and on iOS
|
||||
* It is now possible to scroll through artifacts backpack using mouse wheel or swipe
|
||||
|
||||
### Launcher
|
||||
* Android now uses the same Qt-based launcher as other systems
|
||||
* Fixed attempt to install a submod when installing new mod that depends on a submod of another mod
|
||||
* Fixed wrong order of activating mods in chain when installing multiple mods at once
|
||||
* Mod list no longer shows mod version column. Version is now only shown in the mod description.
|
||||
* Launcher will now skip the Heroes 3 data import step if data has been found automatically
|
||||
* Fixed inport of existing data files on iOS. This option now requires iOS 13 or later
|
||||
* Fixed import using offline installer on iOS.
|
||||
* Buttons to open data directories in the Help tab are now hidden on mobile systems if they can't be opened with file browser
|
||||
* Added the configuration files directory to the Help tab as it is located separately on Linux systems
|
||||
* Removed H3 data language selection during setup in favor of auto-detection
|
||||
* Replaced checkboxes with toggle buttons for easier of access on touchscreens.
|
||||
* Added interface for configuring several previously existing but inaccessible options in Launcher:
|
||||
* Selection of input tolerance precision for all input types
|
||||
* Relative cursor mode for mobile systems (was only available on Android)
|
||||
* Haptic feedback toggle for mobile systems (was only available on Android)
|
||||
* Sound and music volume (was only available in game)
|
||||
* Selection of long touch interval (was only available in game)
|
||||
* Selection of upscaling filter used by SDL
|
||||
* Controller input sensitivity and acceleration.
|
||||
|
||||
### AI
|
||||
* Fixed crash when Nullkiller AI tries to explore after losing the hero in combat.
|
||||
* Fixed rare crash when Nullkiller AI tries to use portals
|
||||
* Fixed potential crash when Nullkiller AI has access to Town Portal spell
|
||||
* Fixed potential crash when Battle AI selects a spell to cast from a hero with summon spells.
|
||||
* Several fixes to Nullkiller AI exploration logic
|
||||
* Fixed bug leading to Battle AI doing nothing if targeted unit is unreachable
|
||||
|
||||
### Random Maps Generator
|
||||
* Fixed crash when player selects a random number of players and selects a different colour to play, resulting in a non-continuous list of players.
|
||||
* Fixed rare crash when generating maps with water
|
||||
|
||||
### Map Editor
|
||||
* Fixed crash on closing map editor
|
||||
|
||||
### Modding
|
||||
* Added new building type 'thievesGuild' which implements HotA building in Cove.
|
||||
* Creature terrain limiter now actually accepts terrain as parameter
|
||||
|
||||
# 1.5.1 -> 1.5.2
|
||||
|
||||
### Stability
|
||||
|
23
Global.h
23
Global.h
@ -348,6 +348,15 @@ namespace vstd
|
||||
return std::find(c.begin(),c.end(),i);
|
||||
}
|
||||
|
||||
// returns existing value from map, or default value if key does not exists
|
||||
template <typename Map>
|
||||
const typename Map::mapped_type & find_or(const Map& m, const typename Map::key_type& key, const typename Map::mapped_type& defaultValue) {
|
||||
auto it = m.find(key);
|
||||
if (it == m.end())
|
||||
return defaultValue;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
//returns first key that maps to given value if present, returns success via found if provided
|
||||
template <typename Key, typename T>
|
||||
Key findKey(const std::map<Key, T> & map, const T & value, bool * found = nullptr)
|
||||
@ -684,20 +693,6 @@ namespace vstd
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class M, class Key, class F>
|
||||
typename M::mapped_type & getOrCompute(M & m, const Key & k, F f)
|
||||
{
|
||||
typedef typename M::mapped_type V;
|
||||
|
||||
std::pair<typename M::iterator, bool> r = m.insert(typename M::value_type(k, V()));
|
||||
V & v = r.first->second;
|
||||
|
||||
if(r.second)
|
||||
f(v);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
//c++20 feature
|
||||
template<typename Arithmetic, typename Floating>
|
||||
Arithmetic lerp(const Arithmetic & a, const Arithmetic & b, const Floating & f)
|
||||
|
@ -252,6 +252,13 @@
|
||||
"vcmi.battleWindow.damageEstimation.damage.1" : "%d Schaden",
|
||||
"vcmi.battleWindow.damageEstimation.kills" : "%d werden verenden",
|
||||
"vcmi.battleWindow.damageEstimation.kills.1" : "%d werden verenden",
|
||||
|
||||
"vcmi.battleWindow.damageRetaliation.will" : "Wird Vergeltung üben ",
|
||||
"vcmi.battleWindow.damageRetaliation.may" : "Kann Vergeltung üben ",
|
||||
"vcmi.battleWindow.damageRetaliation.never" : "Wird keine Vergeltung üben.",
|
||||
"vcmi.battleWindow.damageRetaliation.damage" : "(%DAMAGE).",
|
||||
"vcmi.battleWindow.damageRetaliation.damageKills" : "(%DAMAGE, %KILLS).",
|
||||
|
||||
"vcmi.battleWindow.killed" : "Getötet",
|
||||
"vcmi.battleWindow.accurateShot.resultDescription.0" : "%d %s wurden durch gezielte Schüsse getötet!",
|
||||
"vcmi.battleWindow.accurateShot.resultDescription.1" : "%d %s wurde mit einem gezielten Schuss getötet!",
|
||||
|
@ -125,6 +125,13 @@
|
||||
"vcmi.lobby.mod.state.version" : "Розбіжність версій",
|
||||
"vcmi.lobby.mod.state.excessive" : "Має бути вимкнена",
|
||||
"vcmi.lobby.mod.state.missing" : "Не встановлена",
|
||||
"vcmi.lobby.pvp.coin.hover" : "Монетка.",
|
||||
"vcmi.lobby.pvp.coin.help" : "Підкинути монетку",
|
||||
"vcmi.lobby.pvp.randomTown.hover" : "Випадкове місто",
|
||||
"vcmi.lobby.pvp.randomTown.help" : "Написати в чаті випадкове місто",
|
||||
"vcmi.lobby.pvp.randomTownVs.hover" : "Випадкові міста",
|
||||
"vcmi.lobby.pvp.randomTownVs.help" : "Написати в чаті два випадкових міста",
|
||||
"vcmi.lobby.pvp.versus" : "проти",
|
||||
|
||||
"vcmi.client.errors.invalidMap" : "{Пошкоджена карта або кампанія}\n\nНе вдалося запустити гру! Вибрана карта або кампанія може бути невірною або пошкодженою. Причина:\n%s",
|
||||
"vcmi.client.errors.missingCampaigns" : "{Не вистачає файлів даних}\n\nФайли даних кампаній не знайдено! Можливо, ви використовуєте неповні або пошкоджені файли даних Heroes 3. Будь ласка, перевстановіть дані гри.",
|
||||
@ -253,7 +260,6 @@
|
||||
"vcmi.battleWindow.damageRetaliation.damageKills" : "(%DAMAGE, %KILLS).",
|
||||
|
||||
"vcmi.battleWindow.killed" : "Загинуло",
|
||||
|
||||
"vcmi.battleWindow.accurateShot.resultDescription.0" : "%d %s було вбито влучними пострілами!",
|
||||
"vcmi.battleWindow.accurateShot.resultDescription.1" : "%d %s було вбито влучним пострілом!",
|
||||
"vcmi.battleWindow.accurateShot.resultDescription.2" : "%d %s було вбито влучними пострілами!",
|
||||
@ -381,6 +387,14 @@
|
||||
"vcmi.optionsTab.simturns.months.1" : " %d місяць",
|
||||
"vcmi.optionsTab.simturns.months.2" : " %d місяці",
|
||||
|
||||
"vcmi.optionsTab.extraOptions.hover" : "Розширені опції",
|
||||
"vcmi.optionsTab.extraOptions.help" : "Додаткові налаштування для гри",
|
||||
|
||||
"vcmi.optionsTab.cheatAllowed.hover" : "Дозволити чит-коди",
|
||||
"vcmi.optionsTab.unlimitedReplay.hover" : "Необмежена кількість перегравань бою",
|
||||
"vcmi.optionsTab.cheatAllowed.help" : "{Дозволити чіт-коди}\nДозволяє вводити чит-коди під час гри.",
|
||||
"vcmi.optionsTab.unlimitedReplay.help" : "{Необмежена кількість перегравань бою}\nКількість перегравань боїв не обмежена.",
|
||||
|
||||
// Custom victory conditions for H3 campaigns and HotA maps
|
||||
"vcmi.map.victoryCondition.daysPassed.toOthers" : "Ворогу вдалося вижити до сьогоднішнього дня. Він переміг!",
|
||||
"vcmi.map.victoryCondition.daysPassed.toSelf" : "Вітаємо! Вам вдалося залишитися в живих. Перемога за вами!",
|
||||
@ -389,6 +403,84 @@
|
||||
"vcmi.map.victoryCondition.collectArtifacts.message" : "Здобути три артефакти",
|
||||
"vcmi.map.victoryCondition.angelicAlliance.toSelf" : "Вітаємо! Усі ваші вороги переможені, і ви маєте Альянс Ангелів! Перемога ваша!",
|
||||
"vcmi.map.victoryCondition.angelicAlliance.message" : "Перемогти всіх ворогів і створити Альянс Ангелів",
|
||||
"vcmi.map.victoryCondition.angelicAlliancePartLost.toSelf" : "На жаль, ви втратили частину Альянсу Ангелів. Все втрачено.",
|
||||
|
||||
// few strings from WoG used by vcmi
|
||||
// "vcmi.stackExperience.description" : "» S t a c k E x p e r i e n c e D e t a i l s «\n\nCreature Type ................... : %s\nExperience Rank ................. : %s (%i)\nExperience Points ............... : %i\nExperience Points to Next Rank .. : %i\nMaximum Experience per Battle ... : %i%% (%i)\nNumber of Creatures in stack .... : %i\nMaximum New Recruits\n without losing current Rank .... : %i\nExperience Multiplier ........... : %.2f\nUpgrade Multiplier .............. : %.2f\nExperience after Rank 10 ........ : %i\nMaximum New Recruits to remain at\n Rank 10 if at Maximum Experience : %i",
|
||||
"vcmi.stackExperience.rank.0" : "Базовий",
|
||||
"vcmi.stackExperience.rank.1" : "Початківець",
|
||||
"vcmi.stackExperience.rank.2" : "Підготовлений",
|
||||
"vcmi.stackExperience.rank.3" : "Кваліфікований",
|
||||
"vcmi.stackExperience.rank.4" : "Перевірений",
|
||||
"vcmi.stackExperience.rank.5" : "Ветеран",
|
||||
"vcmi.stackExperience.rank.6" : "Адепт",
|
||||
"vcmi.stackExperience.rank.7" : "Експерт",
|
||||
"vcmi.stackExperience.rank.8" : "Еліта",
|
||||
"vcmi.stackExperience.rank.9" : "Майстер",
|
||||
"vcmi.stackExperience.rank.10" : "Ас",
|
||||
|
||||
// Strings for HotA Seer Hut / Quest Guards
|
||||
"core.seerhut.quest.heroClass.complete.0" : "А, ти %s. Ось тобі подарунок. Приймаєш?",
|
||||
"core.seerhut.quest.heroClass.complete.1" : "А, ти %s. Ось тобі подарунок. Приймаєш?",
|
||||
"core.seerhut.quest.heroClass.complete.2" : "А, ти %s. Ось тобі подарунок. Приймаєш?",
|
||||
"core.seerhut.quest.heroClass.complete.3" : "Вартові помічають, що ви - %s, і пропонують вас пропустити. Чи погоджуєтесь ви?",
|
||||
"core.seerhut.quest.heroClass.complete.4" : "Вартові помічають, що ви - %s, і пропонують вас пропустити. Чи погоджуєтесь ви?",
|
||||
"core.seerhut.quest.heroClass.complete.5" : "Вартові помічають, що ви - %s, і пропонують вас пропустити. Чи погоджуєтесь ви?",
|
||||
"core.seerhut.quest.heroClass.description.0" : "Відправити %s до %s",
|
||||
"core.seerhut.quest.heroClass.description.1" : "Відправити %s до %s",
|
||||
"core.seerhut.quest.heroClass.description.2" : "Відправити %s до %s",
|
||||
"core.seerhut.quest.heroClass.description.3" : "Відправити %s до щоб відкрити ворота",
|
||||
"core.seerhut.quest.heroClass.description.4" : "Відправити %s до щоб відкрити ворота",
|
||||
"core.seerhut.quest.heroClass.description.5" : "Відправити %s до щоб відкрити ворота",
|
||||
"core.seerhut.quest.heroClass.hover.0" : "(шукає героя класу %s)",
|
||||
"core.seerhut.quest.heroClass.hover.1" : "(шукає героя класу %s)",
|
||||
"core.seerhut.quest.heroClass.hover.2" : "(шукає героя класу %s)",
|
||||
"core.seerhut.quest.heroClass.hover.3" : "(шукає героя класу %s)",
|
||||
"core.seerhut.quest.heroClass.hover.4" : "(шукає героя класу %s)",
|
||||
"core.seerhut.quest.heroClass.hover.5" : "(шукає героя класу %s)",
|
||||
"core.seerhut.quest.heroClass.receive.0" : "У мене є подарунок для %s.",
|
||||
"core.seerhut.quest.heroClass.receive.1" : "У мене є подарунок для %s.",
|
||||
"core.seerhut.quest.heroClass.receive.2" : "У мене є подарунок для %s.",
|
||||
"core.seerhut.quest.heroClass.receive.3" : "Вартові кажуть, що пропускають лише %s.",
|
||||
"core.seerhut.quest.heroClass.receive.4" : "Вартові кажуть, що пропускають лише %s.",
|
||||
"core.seerhut.quest.heroClass.receive.5" : "Вартові кажуть, що пропускають лише %s.",
|
||||
"core.seerhut.quest.heroClass.visit.0" : "Ти не %s. У мене для тебе нічого немає. Йди геть!",
|
||||
"core.seerhut.quest.heroClass.visit.1" : "Ти не %s. У мене для тебе нічого немає. Йди геть!",
|
||||
"core.seerhut.quest.heroClass.visit.2" : "Ти не %s. У мене для тебе нічого немає. Йди геть!",
|
||||
"core.seerhut.quest.heroClass.visit.3" : "Вартові пропускають лише %s.",
|
||||
"core.seerhut.quest.heroClass.visit.4" : "Вартові пропускають лише %s.",
|
||||
"core.seerhut.quest.heroClass.visit.5" : "Вартові пропускають лише %s.",
|
||||
|
||||
"core.seerhut.quest.reachDate.complete.0" : "Тепер я вільний. Ось що у мене є для тебе. Ти приймаєш?",
|
||||
"core.seerhut.quest.reachDate.complete.1" : "Тепер я вільний. Ось що у мене є для тебе. Ти приймаєш?",
|
||||
"core.seerhut.quest.reachDate.complete.2" : "Тепер я вільний. Ось що у мене є для тебе. Ти приймаєш?",
|
||||
"core.seerhut.quest.reachDate.complete.3" : "Тепер ви можете пройти. Бажаєте пройти?",
|
||||
"core.seerhut.quest.reachDate.complete.4" : "Тепер ви можете пройти. Бажаєте пройти?",
|
||||
"core.seerhut.quest.reachDate.complete.5" : "Тепер ви можете пройти. Бажаєте пройти?",
|
||||
"core.seerhut.quest.reachDate.description.0" : "Зачекайте до %s для %s",
|
||||
"core.seerhut.quest.reachDate.description.1" : "Зачекайте до %s для %s",
|
||||
"core.seerhut.quest.reachDate.description.2" : "Зачекайте до %s для %s",
|
||||
"core.seerhut.quest.reachDate.description.3" : "Зачекайте до %s, щоб відкрити ворота",
|
||||
"core.seerhut.quest.reachDate.description.4" : "Зачекайте до %s, щоб відкрити ворота",
|
||||
"core.seerhut.quest.reachDate.description.5" : "Зачекайте до %s, щоб відкрити ворота",
|
||||
"core.seerhut.quest.reachDate.hover.0" : "(Повертайтеся не раніше, ніж через %s)",
|
||||
"core.seerhut.quest.reachDate.hover.1" : "(Повертайтеся не раніше, ніж через %s)",
|
||||
"core.seerhut.quest.reachDate.hover.2" : "(Повертайтеся не раніше, ніж через %s)",
|
||||
"core.seerhut.quest.reachDate.hover.3" : "(Повертайтеся не раніше, ніж через %s)",
|
||||
"core.seerhut.quest.reachDate.hover.4" : "(Повертайтеся не раніше, ніж через %s)",
|
||||
"core.seerhut.quest.reachDate.hover.5" : "(Повертайтеся не раніше, ніж через %s)",
|
||||
"core.seerhut.quest.reachDate.receive.0" : "Я зайнят. Повертайтеся не раніше, ніж через %s",
|
||||
"core.seerhut.quest.reachDate.receive.1" : "Я зайнят. Повертайтеся не раніше, ніж через %s",
|
||||
"core.seerhut.quest.reachDate.receive.2" : "Я зайнят. Повертайтеся не раніше, ніж через %s",
|
||||
"core.seerhut.quest.reachDate.receive.3" : "Закрито до %s.",
|
||||
"core.seerhut.quest.reachDate.receive.4" : "Закрито до %s.",
|
||||
"core.seerhut.quest.reachDate.receive.5" : "Закрито до %s.",
|
||||
"core.seerhut.quest.reachDate.visit.0" : "Я зайнятий. Приходь не раніше, ніж %s",
|
||||
"core.seerhut.quest.reachDate.visit.1" : "Я зайнятий. Приходь не раніше, ніж %s",
|
||||
"core.seerhut.quest.reachDate.visit.2" : "Я зайнятий. Приходь не раніше, ніж %s",
|
||||
"core.seerhut.quest.reachDate.visit.3" : "Закрито до %s.",
|
||||
"core.seerhut.quest.reachDate.visit.4" : "Закрито до %s.",
|
||||
"core.seerhut.quest.reachDate.visit.5" : "Закрито до %s.",
|
||||
|
||||
"core.bonus.ADDITIONAL_ATTACK.name" : "Подвійний удар",
|
||||
"core.bonus.ADDITIONAL_ATTACK.description" : "Атакує двічі",
|
||||
|
@ -2,16 +2,9 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="eu.vcmi.vcmi">
|
||||
|
||||
<!-- %%INSERT_PERMISSIONS -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default permissions. -->
|
||||
<!-- %%INSERT_PERMISSIONS_DISABLED -->
|
||||
|
||||
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default features. -->
|
||||
<!-- %%INSERT_FEATURES -->
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<supports-screens
|
||||
android:largeScreens="true"
|
||||
|
@ -210,7 +210,14 @@ int main(int argc, char * argv[])
|
||||
logGlobal->info("The log file will be saved to %s", logPath);
|
||||
|
||||
// Init filesystem and settings
|
||||
preinitDLL(::console, false);
|
||||
try
|
||||
{
|
||||
preinitDLL(::console, false);
|
||||
}
|
||||
catch (const DataLoadingException & e)
|
||||
{
|
||||
handleFatalError(e.what(), true);
|
||||
}
|
||||
|
||||
Settings session = settings.write["session"];
|
||||
auto setSettingBool = [&](std::string key, std::string arg) {
|
||||
|
@ -245,8 +245,15 @@ void CPlayerInterface::performAutosave()
|
||||
int txtlen = TextOperations::getUnicodeCharactersCount(name);
|
||||
|
||||
TextOperations::trimRightUnicode(name, std::max(0, txtlen - 15));
|
||||
std::string forbiddenChars("\\/:*?\"<>| ");
|
||||
std::replace_if(name.begin(), name.end(), [&](char c) { return std::string::npos != forbiddenChars.find(c); }, '_' );
|
||||
auto const & isSymbolIllegal = [&](char c) {
|
||||
static const std::string forbiddenChars("\\/:*?\"<>| ");
|
||||
|
||||
bool charForbidden = forbiddenChars.find(c) != std::string::npos;
|
||||
bool charNonprintable = static_cast<unsigned char>(c) < static_cast<unsigned char>(' ');
|
||||
|
||||
return charForbidden || charNonprintable;
|
||||
};
|
||||
std::replace_if(name.begin(), name.end(), isSymbolIllegal, '_' );
|
||||
|
||||
prefix = name + "_" + cb->getStartInfo()->startTimeIso8601 + "/";
|
||||
}
|
||||
@ -1087,18 +1094,20 @@ void CPlayerInterface::showMapObjectSelectDialog(QueryID askID, const Component
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
|
||||
std::vector<ObjectInstanceID> tmpObjects;
|
||||
if(objects.size() && dynamic_cast<const CGTownInstance *>(cb->getObj(objects[0])))
|
||||
{
|
||||
// sorting towns (like in client)
|
||||
std::vector <const CGTownInstance*> Towns = LOCPLINT->localState->getOwnedTowns();
|
||||
for(auto town : Towns)
|
||||
for(auto item : objects)
|
||||
if(town == cb->getObj(item))
|
||||
tmpObjects.push_back(item);
|
||||
}
|
||||
else // other object list than town
|
||||
tmpObjects = objects;
|
||||
std::vector<ObjectInstanceID> objectGuiOrdered = objects;
|
||||
|
||||
std::map<ObjectInstanceID, int> townOrder;
|
||||
auto ownedTowns = localState->getOwnedTowns();
|
||||
|
||||
for (int i = 0; i < ownedTowns.size(); ++i)
|
||||
townOrder[ownedTowns[i]->id] = i;
|
||||
|
||||
auto townComparator = [&townOrder](const ObjectInstanceID & left, const ObjectInstanceID & right){
|
||||
uint32_t leftIndex= townOrder.count(left) ? townOrder.at(left) : std::numeric_limits<uint32_t>::max();
|
||||
uint32_t rightIndex = townOrder.count(right) ? townOrder.at(right) : std::numeric_limits<uint32_t>::max();
|
||||
return leftIndex < rightIndex;
|
||||
};
|
||||
std::stable_sort(objectGuiOrdered.begin(), objectGuiOrdered.end(), townComparator);
|
||||
|
||||
auto selectCallback = [=](int selection)
|
||||
{
|
||||
@ -1114,9 +1123,9 @@ void CPlayerInterface::showMapObjectSelectDialog(QueryID askID, const Component
|
||||
const std::string localDescription = description.toString();
|
||||
|
||||
std::vector<int> tempList;
|
||||
tempList.reserve(tmpObjects.size());
|
||||
tempList.reserve(objectGuiOrdered.size());
|
||||
|
||||
for(auto item : tmpObjects)
|
||||
for(auto item : objectGuiOrdered)
|
||||
tempList.push_back(item.getNum());
|
||||
|
||||
CComponent localIconC(icon);
|
||||
@ -1125,7 +1134,7 @@ void CPlayerInterface::showMapObjectSelectDialog(QueryID askID, const Component
|
||||
localIconC.removeChild(localIcon.get(), false);
|
||||
|
||||
std::vector<std::shared_ptr<IImage>> images;
|
||||
for(auto & obj : tmpObjects)
|
||||
for(auto & obj : objectGuiOrdered)
|
||||
{
|
||||
if(!settings["general"]["enableUiEnhancements"].Bool())
|
||||
break;
|
||||
@ -1140,8 +1149,8 @@ void CPlayerInterface::showMapObjectSelectDialog(QueryID askID, const Component
|
||||
|
||||
auto wnd = std::make_shared<CObjectListWindow>(tempList, localIcon, localTitle, localDescription, selectCallback, 0, images);
|
||||
wnd->onExit = cancelCallback;
|
||||
wnd->onPopup = [this, tmpObjects](int index) { CRClickPopup::createAndPush(cb->getObj(tmpObjects[index]), GH.getCursorPosition()); };
|
||||
wnd->onClicked = [this, tmpObjects](int index) { adventureInt->centerOnObject(cb->getObj(tmpObjects[index])); GH.windows().totalRedraw(); };
|
||||
wnd->onPopup = [this, objectGuiOrdered](int index) { CRClickPopup::createAndPush(cb->getObj(objectGuiOrdered[index]), GH.getCursorPosition()); };
|
||||
wnd->onClicked = [this, objectGuiOrdered](int index) { adventureInt->centerOnObject(cb->getObj(objectGuiOrdered[index])); GH.windows().totalRedraw(); };
|
||||
GH.windows().pushWindow(wnd);
|
||||
}
|
||||
|
||||
|
@ -607,9 +607,18 @@ void CClient::removeGUI() const
|
||||
#ifdef VCMI_ANDROID
|
||||
extern "C" JNIEXPORT jboolean JNICALL Java_eu_vcmi_vcmi_NativeMethods_tryToSaveTheGame(JNIEnv * env, jclass cls)
|
||||
{
|
||||
boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
|
||||
|
||||
logGlobal->info("Received emergency save game request");
|
||||
if(!LOCPLINT || !LOCPLINT->cb)
|
||||
{
|
||||
logGlobal->info("... but no active player interface found!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CSH || !CSH->logicConnection)
|
||||
{
|
||||
logGlobal->info("... but no active connection found!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -91,9 +91,7 @@ void HeroMovementController::showTeleportDialog(const CGHeroInstance * hero, Tel
|
||||
|
||||
for(size_t i = 0; i < exits.size(); ++i)
|
||||
{
|
||||
const auto * teleporter = LOCPLINT->cb->getObj(exits[i].first);
|
||||
|
||||
if(teleporter && teleporter->visitableAt(nextNode.coord))
|
||||
if(exits[i].second == nextNode.coord)
|
||||
{
|
||||
// Remove this node from path - it will be covered by teleportation
|
||||
//LOCPLINT->localState->removeLastNode(hero);
|
||||
|
@ -564,7 +564,7 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &targetPosition)
|
||||
}
|
||||
else
|
||||
{
|
||||
if(GH.isKeyboardCmdDown()) //normal click behaviour (as no hero selected)
|
||||
if(GH.isKeyboardShiftDown()) //normal click behaviour (as no hero selected)
|
||||
{
|
||||
if(canSelect)
|
||||
LOCPLINT->localState->setSelection(static_cast<const CArmedInstance*>(topBlocking));
|
||||
@ -643,19 +643,19 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
|
||||
objRelations = LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, objAtTile->tempOwner);
|
||||
std::string text = LOCPLINT->localState->getCurrentHero() ? objAtTile->getHoverText(LOCPLINT->localState->getCurrentHero()) : objAtTile->getHoverText(LOCPLINT->playerID);
|
||||
boost::replace_all(text,"\n"," ");
|
||||
if (GH.isKeyboardShiftDown())
|
||||
if (GH.isKeyboardCmdDown())
|
||||
text.append(" (" + std::to_string(targetPosition.x) + ", " + std::to_string(targetPosition.y) + ")");
|
||||
GH.statusbar()->write(text);
|
||||
}
|
||||
else if(isTargetPositionVisible)
|
||||
{
|
||||
std::string tileTooltipText = CGI->mh->getTerrainDescr(targetPosition, false);
|
||||
if (GH.isKeyboardShiftDown())
|
||||
if (GH.isKeyboardCmdDown())
|
||||
tileTooltipText.append(" (" + std::to_string(targetPosition.x) + ", " + std::to_string(targetPosition.y) + ")");
|
||||
GH.statusbar()->write(tileTooltipText);
|
||||
}
|
||||
|
||||
if(LOCPLINT->localState->getCurrentArmy()->ID == Obj::TOWN || GH.isKeyboardCtrlDown())
|
||||
if(LOCPLINT->localState->getCurrentArmy()->ID == Obj::TOWN || GH.isKeyboardShiftDown())
|
||||
{
|
||||
if(objAtTile)
|
||||
{
|
||||
|
@ -118,9 +118,9 @@ void CGuiHandler::renderFrame()
|
||||
|
||||
if (settings["video"]["showfps"].Bool())
|
||||
drawFPSCounter();
|
||||
}
|
||||
|
||||
SDL_UpdateTexture(screenTexture, nullptr, screen->pixels, screen->pitch);
|
||||
SDL_UpdateTexture(screenTexture, nullptr, screen->pixels, screen->pitch);
|
||||
}
|
||||
|
||||
SDL_RenderClear(mainRenderer);
|
||||
SDL_RenderCopy(mainRenderer, screenTexture, nullptr, nullptr);
|
||||
|
@ -63,17 +63,43 @@ auto HighScoreCalculation::calculate()
|
||||
return summary;
|
||||
}
|
||||
|
||||
struct HighScoreCreature
|
||||
{
|
||||
CreatureID creature;
|
||||
int min;
|
||||
int max;
|
||||
};
|
||||
|
||||
static std::vector<HighScoreCreature> getHighscoreCreaturesList()
|
||||
{
|
||||
JsonNode configCreatures(JsonPath::builtin("CONFIG/highscoreCreatures.json"));
|
||||
|
||||
std::vector<HighScoreCreature> ret;
|
||||
|
||||
for(auto & json : configCreatures["creatures"].Vector())
|
||||
{
|
||||
HighScoreCreature entry;
|
||||
entry.creature = CreatureID::decode(json["creature"].String());
|
||||
entry.max = json["max"].isNull() ? std::numeric_limits<int>::max() : json["max"].Integer();
|
||||
entry.min = json["min"].isNull() ? std::numeric_limits<int>::min() : json["min"].Integer();
|
||||
|
||||
ret.push_back(entry);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CreatureID HighScoreCalculation::getCreatureForPoints(int points, bool campaign)
|
||||
{
|
||||
static const JsonNode configCreatures(JsonPath::builtin("CONFIG/highscoreCreatures.json"));
|
||||
auto creatures = configCreatures["creatures"].Vector();
|
||||
static const std::vector<HighScoreCreature> creatures = getHighscoreCreaturesList();
|
||||
|
||||
int divide = campaign ? 5 : 1;
|
||||
|
||||
for(auto & creature : creatures)
|
||||
if(points / divide <= creature["max"].Integer() && points / divide >= creature["min"].Integer())
|
||||
return CreatureID::decode(creature["creature"].String());
|
||||
if(points / divide <= creature.max && points / divide >= creature.min)
|
||||
return creature.creature;
|
||||
|
||||
return -1;
|
||||
throw std::runtime_error("Unable to find creature for score " + std::to_string(points));
|
||||
}
|
||||
|
||||
CHighScoreScreen::CHighScoreScreen(HighScorePage highscorepage, int highlighted)
|
||||
|
@ -60,7 +60,7 @@
|
||||
#include "../../lib/CRandomGenerator.h"
|
||||
|
||||
std::shared_ptr<CMainMenu> CMM;
|
||||
ISelectionScreenInfo * SEL;
|
||||
ISelectionScreenInfo * SEL = nullptr;
|
||||
|
||||
static void do_quit()
|
||||
{
|
||||
|
@ -235,7 +235,10 @@ void SDLImage::setFlagColor(PlayerColor player)
|
||||
|
||||
bool SDLImage::isTransparent(const Point & coords) const
|
||||
{
|
||||
return CSDL_Ext::isTransparent(surf, coords.x, coords.y);
|
||||
if (surf)
|
||||
return CSDL_Ext::isTransparent(surf, coords.x, coords.y);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
Point SDLImage::dimensions() const
|
||||
|
@ -83,6 +83,9 @@ void CArtifactsOfHeroBase::init(
|
||||
leftBackpackRoll->block(true);
|
||||
rightBackpackRoll->block(true);
|
||||
|
||||
backpackScroller = std::make_shared<BackpackScroller>(this, Rect(380, 30, 278, 382));
|
||||
backpackScroller->setScrollingEnabled(false);
|
||||
|
||||
setRedrawParent(true);
|
||||
}
|
||||
|
||||
@ -208,6 +211,8 @@ void CArtifactsOfHeroBase::updateBackpackSlots()
|
||||
leftBackpackRoll->block(!scrollingPossible);
|
||||
if(rightBackpackRoll)
|
||||
rightBackpackRoll->block(!scrollingPossible);
|
||||
if (backpackScroller)
|
||||
backpackScroller->setScrollingEnabled(scrollingPossible);
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroBase::updateSlot(const ArtifactPosition & slot)
|
||||
@ -277,3 +282,17 @@ void CArtifactsOfHeroBase::setSlotData(ArtPlacePtr artPlace, const ArtifactPosit
|
||||
artPlace->setArtifact(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
BackpackScroller::BackpackScroller(CArtifactsOfHeroBase * owner, const Rect & dimensions)
|
||||
: Scrollable(0, Point(), Orientation::HORIZONTAL)
|
||||
, owner(owner)
|
||||
{
|
||||
pos = dimensions + pos.topLeft();
|
||||
setPanningStep(46);
|
||||
}
|
||||
|
||||
void BackpackScroller::scrollBy(int distance)
|
||||
{
|
||||
if (distance != 0)
|
||||
owner->scrollBackpack(distance < 0);
|
||||
}
|
||||
|
@ -10,10 +10,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "CArtPlace.h"
|
||||
#include "Scrollable.h"
|
||||
|
||||
#include "../gui/Shortcut.h"
|
||||
|
||||
class CButton;
|
||||
class BackpackScroller;
|
||||
|
||||
class CArtifactsOfHeroBase : virtual public CIntObject, public CKeyShortcut
|
||||
{
|
||||
@ -54,6 +56,7 @@ public:
|
||||
std::vector<ArtPlacePtr> backpack;
|
||||
std::shared_ptr<CButton> leftBackpackRoll;
|
||||
std::shared_ptr<CButton> rightBackpackRoll;
|
||||
std::shared_ptr<BackpackScroller> backpackScroller;
|
||||
|
||||
const std::vector<Point> slotPos =
|
||||
{
|
||||
@ -71,3 +74,13 @@ protected:
|
||||
// Assigns an artifacts to an artifact place depending on it's new slot ID
|
||||
virtual void setSlotData(ArtPlacePtr artPlace, const ArtifactPosition & slot);
|
||||
};
|
||||
|
||||
class BackpackScroller : public Scrollable
|
||||
{
|
||||
CArtifactsOfHeroBase * owner;
|
||||
|
||||
void scrollBy(int distance) override;
|
||||
|
||||
public:
|
||||
BackpackScroller(CArtifactsOfHeroBase * owner, const Rect & dimensions);
|
||||
};
|
||||
|
@ -637,6 +637,9 @@ CCreaturePic::CCreaturePic(int x, int y, const CCreature * cre, bool Big, bool A
|
||||
|
||||
assert(CGI->townh->size() > faction);
|
||||
|
||||
if (cre->animDefName.empty())
|
||||
throw std::runtime_error("Creature " + cre->getJsonKey() + " has no valid combat animation!");
|
||||
|
||||
if(Big)
|
||||
bg = std::make_shared<CPicture>((*CGI->townh)[faction]->creatureBg130);
|
||||
else
|
||||
|
@ -1548,6 +1548,9 @@ CHallInterface::CHallInterface(const CGTownInstance * Town):
|
||||
const CBuilding * building = nullptr;
|
||||
for(auto & buildingID : boxList[row][col])//we are looking for the first not built structure
|
||||
{
|
||||
if (town->town->buildings.count(buildingID) == 0)
|
||||
throw std::runtime_error("Town " + Town->town->faction->getJsonKey() + " has no building with ID " + std::to_string(buildingID.getNum()));
|
||||
|
||||
const CBuilding * current = town->town->buildings.at(buildingID);
|
||||
if(vstd::contains(town->builtBuildings, buildingID))
|
||||
{
|
||||
|
@ -491,14 +491,21 @@ CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj, const std::func
|
||||
}
|
||||
else if(LOCPLINT->cb->howManyHeroes(true) >= CGI->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_TOTAL_CAP))
|
||||
{
|
||||
MetaString message;
|
||||
message.appendTextID("core.tvrninfo.1");
|
||||
message.replaceNumber(LOCPLINT->cb->howManyHeroes(true));
|
||||
|
||||
//Cannot recruit. You already have %d Heroes.
|
||||
recruit->addHoverText(EButtonState::NORMAL, boost::str(boost::format(CGI->generaltexth->tavernInfo[1]) % LOCPLINT->cb->howManyHeroes(true)));
|
||||
recruit->addHoverText(EButtonState::NORMAL, message.toString());
|
||||
recruit->block(true);
|
||||
}
|
||||
else if(LOCPLINT->cb->howManyHeroes(false) >= CGI->settings()->getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP))
|
||||
{
|
||||
//Cannot recruit. You already have %d Heroes.
|
||||
recruit->addHoverText(EButtonState::NORMAL, boost::str(boost::format(CGI->generaltexth->tavernInfo[1]) % LOCPLINT->cb->howManyHeroes(false)));
|
||||
MetaString message;
|
||||
message.appendTextID("core.tvrninfo.1");
|
||||
message.replaceNumber(LOCPLINT->cb->howManyHeroes(false));
|
||||
|
||||
recruit->addHoverText(EButtonState::NORMAL, message.toString());
|
||||
recruit->block(true);
|
||||
}
|
||||
else if(dynamic_cast<const CGTownInstance *>(TavernObj) && dynamic_cast<const CGTownInstance *>(TavernObj)->visitingHero)
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"creatures": [
|
||||
{ "min" : 1, "max" : 4, "creature": "imp" },
|
||||
{ "max" : 4, "creature": "imp" },
|
||||
{ "min" : 5, "max" : 8, "creature": "gremlin" },
|
||||
{ "min" : 9, "max" : 12, "creature": "gnoll" },
|
||||
{ "min" : 13, "max" : 16, "creature": "troglodyte" },
|
||||
@ -117,6 +117,6 @@
|
||||
{ "min" : 389, "max" : 391, "creature": "titan" },
|
||||
{ "min" : 392, "max" : 394, "creature": "goldDragon" },
|
||||
{ "min" : 395, "max" : 397, "creature": "blackDragon" },
|
||||
{ "min" : 398, "max" : 500, "creature": "archangel" }
|
||||
{ "min" : 398, "creature": "archangel" }
|
||||
]
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.0/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.0)
|
||||
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.1/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.1)
|
||||
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.2/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.2)
|
||||
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.3/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.3)
|
||||
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/total)](https://github.com/vcmi/vcmi/releases)
|
||||
|
||||
# VCMI Project
|
||||
|
@ -349,10 +349,10 @@ Negates all natural immunities for affected stacks. (Orb of Vulnerability)
|
||||
|
||||
### OPENING_BATTLE_SPELL
|
||||
|
||||
In battle, army affected by this bonus will cast spell at the very start of the battle
|
||||
In battle, army affected by this bonus will cast spell at the very start of the battle. Spell is always cast at expert level.
|
||||
|
||||
- subtype: spell identifer
|
||||
- val: spell mastery level
|
||||
- val: duration of the spell, in rounds
|
||||
|
||||
### FREE_SHIP_BOARDING
|
||||
|
||||
|
@ -26,6 +26,8 @@ set(launcher_SRCS
|
||||
if(APPLE_IOS)
|
||||
list(APPEND launcher_SRCS
|
||||
ios/launchGame.m
|
||||
ios/revealdirectoryinfiles.h
|
||||
ios/revealdirectoryinfiles.mm
|
||||
ios/selectdirectory.h
|
||||
ios/selectdirectory.mm
|
||||
)
|
||||
@ -110,12 +112,9 @@ endif()
|
||||
|
||||
assign_source_group(${launcher_SRCS} ${launcher_HEADERS} ${launcher_RESOURCES} ${launcher_TS} ${launcher_ICON})
|
||||
|
||||
# TODO: enabling AUTORCC breaks msvc build on CI
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
if(NOT (MSVC AND "$ENV{GITHUB_ACTIONS}" STREQUAL true))
|
||||
set(CMAKE_AUTORCC ON)
|
||||
endif()
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
if(POLICY CMP0071)
|
||||
cmake_policy(SET CMP0071 NEW)
|
||||
|
@ -16,6 +16,24 @@
|
||||
#include "../../lib/GameConstants.h"
|
||||
#include "../../lib/VCMIDirs.h"
|
||||
|
||||
#ifdef VCMI_IOS
|
||||
#include "ios/revealdirectoryinfiles.h"
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
void revealDirectoryInFileBrowser(QLineEdit * dirLineEdit)
|
||||
{
|
||||
const auto dirUrl = QUrl::fromLocalFile(QFileInfo{dirLineEdit->text()}.absoluteFilePath());
|
||||
#ifdef VCMI_IOS
|
||||
iOS_utils::revealDirectoryInFiles(dirUrl);
|
||||
#else
|
||||
QDesktopServices::openUrl(dirUrl);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AboutProjectView::hideAndStretchWidget(QGridLayout * layout, QWidget * toHide, QWidget * toStretch)
|
||||
{
|
||||
toHide->hide();
|
||||
@ -47,10 +65,12 @@ AboutProjectView::AboutProjectView(QWidget * parent)
|
||||
// On mobile platforms these directories are generally not accessible from phone itself, only via USB connection from PC
|
||||
// Remove "Open" buttons and stretch line with text into now-empty space
|
||||
hideAndStretchWidget(ui->gridLayout, ui->openGameDataDir, ui->lineEditGameDir);
|
||||
#ifdef VCMI_ANDROID
|
||||
hideAndStretchWidget(ui->gridLayout, ui->openUserDataDir, ui->lineEditUserDataDir);
|
||||
hideAndStretchWidget(ui->gridLayout, ui->openTempDir, ui->lineEditTempDir);
|
||||
hideAndStretchWidget(ui->gridLayout, ui->openConfigDir, ui->lineEditConfigDir);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void AboutProjectView::changeEvent(QEvent *event)
|
||||
@ -68,22 +88,22 @@ void AboutProjectView::on_updatesButton_clicked()
|
||||
|
||||
void AboutProjectView::on_openGameDataDir_clicked()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(ui->lineEditGameDir->text()).absoluteFilePath()));
|
||||
revealDirectoryInFileBrowser(ui->lineEditGameDir);
|
||||
}
|
||||
|
||||
void AboutProjectView::on_openUserDataDir_clicked()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(ui->lineEditUserDataDir->text()).absoluteFilePath()));
|
||||
revealDirectoryInFileBrowser(ui->lineEditUserDataDir);
|
||||
}
|
||||
|
||||
void AboutProjectView::on_openTempDir_clicked()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(ui->lineEditTempDir->text()).absoluteFilePath()));
|
||||
revealDirectoryInFileBrowser(ui->lineEditTempDir);
|
||||
}
|
||||
|
||||
void AboutProjectView::on_openConfigDir_clicked()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(ui->lineEditConfigDir->text()).absoluteFilePath()));
|
||||
revealDirectoryInFileBrowser(ui->lineEditConfigDir);
|
||||
}
|
||||
|
||||
void AboutProjectView::on_pushButtonDiscord_clicked()
|
||||
@ -106,7 +126,6 @@ void AboutProjectView::on_pushButtonHomepage_clicked()
|
||||
QDesktopServices::openUrl(QUrl("https://vcmi.eu/"));
|
||||
}
|
||||
|
||||
|
||||
void AboutProjectView::on_pushButtonBugreport_clicked()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl("https://github.com/vcmi/vcmi/issues"));
|
||||
|
@ -25,14 +25,11 @@ class AboutProjectView : public QWidget
|
||||
|
||||
/// Hides a widget and expands second widgets to take place of first widget in layout
|
||||
void hideAndStretchWidget(QGridLayout * layout, QWidget * toHide, QWidget * toStretch);
|
||||
|
||||
public:
|
||||
explicit AboutProjectView(QWidget * parent = nullptr);
|
||||
|
||||
public slots:
|
||||
|
||||
private slots:
|
||||
|
||||
|
||||
void on_updatesButton_clicked();
|
||||
|
||||
void on_openGameDataDir_clicked();
|
||||
@ -55,5 +52,4 @@ private slots:
|
||||
|
||||
private:
|
||||
Ui::AboutProjectView * ui;
|
||||
|
||||
};
|
||||
|
17
launcher/ios/revealdirectoryinfiles.h
Normal file
17
launcher/ios/revealdirectoryinfiles.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* revealdirectoryinfiles.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QUrl>
|
||||
|
||||
namespace iOS_utils
|
||||
{
|
||||
void revealDirectoryInFiles(QUrl dirUrl);
|
||||
}
|
22
launcher/ios/revealdirectoryinfiles.mm
Normal file
22
launcher/ios/revealdirectoryinfiles.mm
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* revealdirectoryinfiles.mm, 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 "revealdirectoryinfiles.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
namespace iOS_utils
|
||||
{
|
||||
void revealDirectoryInFiles(QUrl dirUrl)
|
||||
{
|
||||
auto urlComponents = [NSURLComponents componentsWithURL:dirUrl.toNSURL() resolvingAgainstBaseURL:NO];
|
||||
urlComponents.scheme = @"shareddocuments";
|
||||
[UIApplication.sharedApplication openURL:urlComponents.URL options:@{} completionHandler:nil];
|
||||
}
|
||||
}
|
@ -87,8 +87,6 @@ void CSettingsView::updateCheckbuttonText(QToolButton * button)
|
||||
|
||||
void CSettingsView::loadSettings()
|
||||
{
|
||||
setCheckbuttonState(ui->buttonShowIntro, settings["video"]["showIntro"].Bool());
|
||||
|
||||
#ifdef VCMI_MOBILE
|
||||
ui->comboBoxFullScreen->hide();
|
||||
ui->labelFullScreen->hide();
|
||||
@ -111,7 +109,6 @@ void CSettingsView::loadSettings()
|
||||
ui->spinBoxInterfaceScaling->setValue(settings["video"]["resolution"]["scaling"].Float());
|
||||
ui->spinBoxFramerateLimit->setValue(settings["video"]["targetfps"].Float());
|
||||
ui->spinBoxFramerateLimit->setDisabled(settings["video"]["vsync"].Bool());
|
||||
setCheckbuttonState(ui->buttonVSync, settings["video"]["vsync"].Bool());
|
||||
ui->sliderReservedArea->setValue(std::round(settings["video"]["reservedWidth"].Float() * 100));
|
||||
|
||||
ui->comboBoxFriendlyAI->setCurrentText(QString::fromStdString(settings["server"]["friendlyAI"].String()));
|
||||
@ -123,43 +120,27 @@ void CSettingsView::loadSettings()
|
||||
|
||||
ui->spinBoxNetworkPort->setValue(settings["server"]["localPort"].Integer());
|
||||
|
||||
setCheckbuttonState(ui->buttonAutoCheck, settings["launcher"]["autoCheckRepositories"].Bool());
|
||||
|
||||
ui->lineEditRepositoryDefault->setText(QString::fromStdString(settings["launcher"]["defaultRepositoryURL"].String()));
|
||||
ui->lineEditRepositoryExtra->setText(QString::fromStdString(settings["launcher"]["extraRepositoryURL"].String()));
|
||||
|
||||
ui->lineEditRepositoryDefault->setEnabled(settings["launcher"]["defaultRepositoryEnabled"].Bool());
|
||||
ui->lineEditRepositoryExtra->setEnabled(settings["launcher"]["extraRepositoryEnabled"].Bool());
|
||||
|
||||
setCheckbuttonState(ui->buttonRepositoryDefault, settings["launcher"]["defaultRepositoryEnabled"].Bool());
|
||||
setCheckbuttonState(ui->buttonRepositoryExtra, settings["launcher"]["extraRepositoryEnabled"].Bool());
|
||||
|
||||
setCheckbuttonState(ui->buttonIgnoreSslErrors, settings["launcher"]["ignoreSslErrors"].Bool());
|
||||
setCheckbuttonState(ui->buttonAutoSave, settings["general"]["saveFrequency"].Integer() > 0);
|
||||
|
||||
ui->spinBoxAutoSaveLimit->setValue(settings["general"]["autosaveCountLimit"].Integer());
|
||||
|
||||
setCheckbuttonState(ui->buttonAutoSavePrefix, settings["general"]["useSavePrefix"].Bool());
|
||||
|
||||
ui->lineEditAutoSavePrefix->setText(QString::fromStdString(settings["general"]["savePrefix"].String()));
|
||||
ui->lineEditAutoSavePrefix->setEnabled(settings["general"]["useSavePrefix"].Bool());
|
||||
|
||||
Languages::fillLanguages(ui->comboBoxLanguage, false);
|
||||
fillValidRenderers();
|
||||
|
||||
std::string cursorType = settings["video"]["cursor"].String();
|
||||
int cursorTypeIndex = vstd::find_pos(cursorTypesList, cursorType);
|
||||
setCheckbuttonState(ui->buttonCursorType, cursorTypeIndex);
|
||||
|
||||
std::string upscalingFilter = settings["video"]["scalingMode"].String();
|
||||
int upscalingFilterIndex = vstd::find_pos(upscalingFilterTypes, upscalingFilter);
|
||||
ui->comboBoxUpscalingFilter->setCurrentIndex(upscalingFilterIndex);
|
||||
|
||||
ui->sliderMusicVolume->setValue(settings["general"]["music"].Integer());
|
||||
ui->sliderSoundVolume->setValue(settings["general"]["sound"].Integer());
|
||||
setCheckbuttonState(ui->buttonRelativeCursorMode, settings["general"]["userRelativePointer"].Bool());
|
||||
ui->sliderRelativeCursorSpeed->setValue(settings["general"]["relativePointerSpeedMultiplier"].Integer());
|
||||
setCheckbuttonState(ui->buttonHapticFeedback, settings["launcher"]["hapticFeedback"].Bool());
|
||||
ui->sliderLongTouchDuration->setValue(settings["general"]["longTouchTimeMilliseconds"].Integer());
|
||||
ui->slideToleranceDistanceMouse->setValue(settings["input"]["mouseToleranceDistance"].Integer());
|
||||
ui->sliderToleranceDistanceTouch->setValue(settings["input"]["touchToleranceDistance"].Integer());
|
||||
@ -168,6 +149,30 @@ void CSettingsView::loadSettings()
|
||||
ui->sliderControllerSticksAcceleration->setValue(settings["input"]["controllerAxisScale"].Float() * 100);
|
||||
ui->lineEditGameLobbyHost->setText(QString::fromStdString(settings["lobby"]["hostname"].String()));
|
||||
ui->spinBoxNetworkPortLobby->setValue(settings["lobby"]["port"].Integer());
|
||||
|
||||
loadToggleButtonSettings();
|
||||
}
|
||||
|
||||
void CSettingsView::loadToggleButtonSettings()
|
||||
{
|
||||
setCheckbuttonState(ui->buttonShowIntro, settings["video"]["showIntro"].Bool());
|
||||
setCheckbuttonState(ui->buttonVSync, settings["video"]["vsync"].Bool());
|
||||
setCheckbuttonState(ui->buttonAutoCheck, settings["launcher"]["autoCheckRepositories"].Bool());
|
||||
|
||||
setCheckbuttonState(ui->buttonRepositoryDefault, settings["launcher"]["defaultRepositoryEnabled"].Bool());
|
||||
setCheckbuttonState(ui->buttonRepositoryExtra, settings["launcher"]["extraRepositoryEnabled"].Bool());
|
||||
|
||||
setCheckbuttonState(ui->buttonIgnoreSslErrors, settings["launcher"]["ignoreSslErrors"].Bool());
|
||||
setCheckbuttonState(ui->buttonAutoSave, settings["general"]["saveFrequency"].Integer() > 0);
|
||||
|
||||
setCheckbuttonState(ui->buttonAutoSavePrefix, settings["general"]["useSavePrefix"].Bool());
|
||||
|
||||
setCheckbuttonState(ui->buttonRelativeCursorMode, settings["general"]["userRelativePointer"].Bool());
|
||||
setCheckbuttonState(ui->buttonHapticFeedback, settings["general"]["hapticFeedback"].Bool());
|
||||
|
||||
std::string cursorType = settings["video"]["cursor"].String();
|
||||
int cursorTypeIndex = vstd::find_pos(cursorTypesList, cursorType);
|
||||
setCheckbuttonState(ui->buttonCursorType, cursorTypeIndex);
|
||||
}
|
||||
|
||||
void CSettingsView::fillValidResolutions()
|
||||
@ -431,6 +436,7 @@ void CSettingsView::changeEvent(QEvent *event)
|
||||
ui->retranslateUi(this);
|
||||
Languages::fillLanguages(ui->comboBoxLanguage, false);
|
||||
loadTranslation();
|
||||
loadToggleButtonSettings();
|
||||
}
|
||||
QWidget::changeEvent(event);
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ public:
|
||||
~CSettingsView();
|
||||
|
||||
void loadSettings();
|
||||
void loadToggleButtonSettings();
|
||||
void loadTranslation();
|
||||
void setDisplayList();
|
||||
void changeEvent(QEvent *event) override;
|
||||
|
@ -79,7 +79,7 @@
|
||||
<message>
|
||||
<location filename="../aboutProject/aboutproject_moc.ui" line="234"/>
|
||||
<source>Configuration files directory</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Verzeichnis der Konfiguarions-Dateien</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../aboutProject/aboutproject_moc.ui" line="297"/>
|
||||
@ -294,7 +294,7 @@
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.ui" line="105"/>
|
||||
<source>Reload repositories</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Verzeichnis aktualisieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.ui" line="340"/>
|
||||
@ -669,62 +669,62 @@ Installation erfolgreich heruntergeladen?</translation>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="59"/>
|
||||
<source>Online Lobby port</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Online-Lobby-Port</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="66"/>
|
||||
<source>Autocombat AI in battles</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Autokampf-KI in Kämpfen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="73"/>
|
||||
<source>Sticks Sensitivity</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Sticks Empfindlichkeit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="87"/>
|
||||
<source>Haptic Feedback</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Haptisches Feedback</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="94"/>
|
||||
<source>Software Cursor</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Software-Cursor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="108"/>
|
||||
<source>Online Lobby address</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Adresse der Online-Lobby</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="115"/>
|
||||
<source>Upscaling Filter</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Hochskalierungsfilter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="122"/>
|
||||
<source>Use Relative Pointer Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Relativen Zeigermodus verwenden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="195"/>
|
||||
<source>Nearest</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Nearest</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="200"/>
|
||||
<source>Linear</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Linear</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="205"/>
|
||||
<source>Best (Linear)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Bester (Linear)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="231"/>
|
||||
<source>Input - Touchscreen</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Eingabe - Touchscreen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="440"/>
|
||||
@ -734,62 +734,62 @@ Installation erfolgreich heruntergeladen?</translation>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="474"/>
|
||||
<source>Network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Netzwerk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="540"/>
|
||||
<source>Audio</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Audio</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="578"/>
|
||||
<source>Relative Pointer Speed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Relative Zeigergeschwindigkeit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="585"/>
|
||||
<source>Music Volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Musik Lautstärke</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="606"/>
|
||||
<source>Ignore SSL errors</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>SSL-Fehler ignorieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="618"/>
|
||||
<source>Input - Mouse</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Eingabe - Maus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="628"/>
|
||||
<source>Long Touch Duration</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Dauer der Berührung für "lange Berührung"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="635"/>
|
||||
<source>%</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="658"/>
|
||||
<source>Controller Click Tolerance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Toleranz bei Controller Klick</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="665"/>
|
||||
<source>Touch Tap Tolerance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Toleranz bei Berührungen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="704"/>
|
||||
<source>Input - Controller</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Eingabe - Controller</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="771"/>
|
||||
<source>Sound Volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Sound-Lautstärke</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="801"/>
|
||||
@ -828,12 +828,12 @@ Installation erfolgreich heruntergeladen?</translation>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="839"/>
|
||||
<source>Mouse Click Tolerance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Toleranz bei Mausklick</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="853"/>
|
||||
<source>Sticks Acceleration</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Sticks Beschleunigung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="995"/>
|
||||
@ -1064,12 +1064,12 @@ Heroes III: HD Edition wird derzeit nicht unterstützt!</translation>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="304"/>
|
||||
<source>Use offline installer from gog.com</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Offline-Installer von gog.com verwenden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="317"/>
|
||||
<source>You can manually copy directories Maps, Data and Mp3 from the original game directory to VCMI data directory that you can see on top of this page</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Es können die Verzeichnisse Maps, Data und Mp3 manuell aus dem ursprünglichen Spielverzeichnis in das VCMI-Datenverzeichnis kopiert werden, das oben auf dieser Seite gesehen werden kann</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="336"/>
|
||||
@ -1106,23 +1106,24 @@ Heroes III: HD Edition wird derzeit nicht unterstützt!</translation>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="395"/>
|
||||
<source>Installing... %p%</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Installation... %p%</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="424"/>
|
||||
<source>If you already have Heroes III files on your device, you can select this directory and VCMI will copy the existing data automatically.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Wenn bereits Heroes III-Dateien auf Ihrem Gerät sind, kann dieses Verzeichnis auswählt werden und VCMI wird die vorhandenen Daten automatisch kopieren.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="466"/>
|
||||
<source>Copy existing files</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Vorhandene Dateien kopieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="511"/>
|
||||
<source>If you own Heroes III on gog.com you can download backup offline installer from gog.com, and VCMI will import Heroes III data using offline installer.
|
||||
Offline installer consists of two parts, .exe and .bin. Make sure you download both of them.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Wenn Sie Heroes III auf gog.com besitzen, können Sie den Backup-Offline-Installer von gog.com herunterladen, und VCMI wird die Daten von Heroes III mit dem Offline-Installer importieren.
|
||||
Der Offline-Installer besteht aus zwei Teilen, .exe und .bin. Stellen Sie sicher, dass Sie beide Teile herunterladen.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="696"/>
|
||||
@ -1173,7 +1174,7 @@ Offline installer consists of two parts, .exe and .bin. Make sure you download b
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="354"/>
|
||||
<source>Manual Installation</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Manuelle Installation</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="367"/>
|
||||
@ -1487,13 +1488,14 @@ Bitte wählen Sie ein Verzeichnis mit Heroes III: Complete Edition oder Heroes I
|
||||
<message>
|
||||
<location filename="../main.cpp" line="121"/>
|
||||
<source>Error starting executable</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Fehler beim Starten der ausführbaren Datei</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.cpp" line="122"/>
|
||||
<source>Failed to start %1
|
||||
Reason: %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Start von %1 fehlgeschlagen
|
||||
Grund: %2</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -64,7 +64,7 @@
|
||||
<message>
|
||||
<location filename="../aboutProject/aboutproject_moc.ui" line="114"/>
|
||||
<source>Data Directories</source>
|
||||
<translation>Теки даних гри</translation>
|
||||
<translation>Теки гри</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../aboutProject/aboutproject_moc.ui" line="175"/>
|
||||
@ -79,7 +79,7 @@
|
||||
<message>
|
||||
<location filename="../aboutProject/aboutproject_moc.ui" line="234"/>
|
||||
<source>Configuration files directory</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Тека файлів конфігурації</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../aboutProject/aboutproject_moc.ui" line="297"/>
|
||||
@ -294,7 +294,7 @@
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.ui" line="105"/>
|
||||
<source>Reload repositories</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Обновити репозиторії</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.ui" line="340"/>
|
||||
@ -630,7 +630,7 @@ Install successfully downloaded?</source>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.cpp" line="85"/>
|
||||
<source>Off</source>
|
||||
<translation>Вимкнено</translation>
|
||||
<translation>Ні</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="452"/>
|
||||
@ -669,62 +669,62 @@ Install successfully downloaded?</source>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="59"/>
|
||||
<source>Online Lobby port</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Порт онлайн лобі</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="66"/>
|
||||
<source>Autocombat AI in battles</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>ШІ автобою</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="73"/>
|
||||
<source>Sticks Sensitivity</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Чутливість стиків</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="87"/>
|
||||
<source>Haptic Feedback</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="94"/>
|
||||
<source>Software Cursor</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Програмний курсор</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="108"/>
|
||||
<source>Online Lobby address</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Адреса онлайн-лобі</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="115"/>
|
||||
<source>Upscaling Filter</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Фільтр масштабування</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="122"/>
|
||||
<source>Use Relative Pointer Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Режим відносного вказівника</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="195"/>
|
||||
<source>Nearest</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Найближчий</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="200"/>
|
||||
<source>Linear</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Лінійний</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="205"/>
|
||||
<source>Best (Linear)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Найкращий (лінійний)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="231"/>
|
||||
<source>Input - Touchscreen</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Введення - Сенсорний екран</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="440"/>
|
||||
@ -734,62 +734,62 @@ Install successfully downloaded?</source>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="474"/>
|
||||
<source>Network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Мережа</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="540"/>
|
||||
<source>Audio</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Аудіо</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="578"/>
|
||||
<source>Relative Pointer Speed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Швидкість відносного вказівника</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="585"/>
|
||||
<source>Music Volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Гучність музики</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="606"/>
|
||||
<source>Ignore SSL errors</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ігнорувати помилки SSL</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="618"/>
|
||||
<source>Input - Mouse</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Введення - Миша</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="628"/>
|
||||
<source>Long Touch Duration</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Тривалість довгого дотику</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="635"/>
|
||||
<source>%</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="658"/>
|
||||
<source>Controller Click Tolerance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Допуск на натискання контролера</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="665"/>
|
||||
<source>Touch Tap Tolerance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Допуск на натискання дотиком</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="704"/>
|
||||
<source>Input - Controller</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Введення - Контролер</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="771"/>
|
||||
<source>Sound Volume</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Гучність звуку</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="801"/>
|
||||
@ -828,12 +828,12 @@ Install successfully downloaded?</source>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="839"/>
|
||||
<source>Mouse Click Tolerance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Допуск кліків миші</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="853"/>
|
||||
<source>Sticks Acceleration</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Прискорення стиків</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="995"/>
|
||||
@ -858,7 +858,7 @@ Install successfully downloaded?</source>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.cpp" line="83"/>
|
||||
<source>On</source>
|
||||
<translation>Увімкнено</translation>
|
||||
<translation>Так</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cursor</source>
|
||||
@ -1064,12 +1064,12 @@ Heroes® of Might and Magic® III HD наразі не підтримуєтьс
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="304"/>
|
||||
<source>Use offline installer from gog.com</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Використати офлайн-інсталятор з gog.com</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="317"/>
|
||||
<source>You can manually copy directories Maps, Data and Mp3 from the original game directory to VCMI data directory that you can see on top of this page</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ви можете вручну скопіювати теки Maps, Data та Mp3 з теки оригінальної гри до теки даних VCMI, яку ви можете побачити вгорі цієї сторінки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="336"/>
|
||||
@ -1106,23 +1106,24 @@ Heroes® of Might and Magic® III HD наразі не підтримуєтьс
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="395"/>
|
||||
<source>Installing... %p%</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Встановлюємо... %p%</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="424"/>
|
||||
<source>If you already have Heroes III files on your device, you can select this directory and VCMI will copy the existing data automatically.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Якщо на вашому пристрої вже є файли Heroes III, ви можете вибрати цю теку і VCMI автоматично скопіює наявні дані.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="466"/>
|
||||
<source>Copy existing files</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Скопіювати існуючі файли</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="511"/>
|
||||
<source>If you own Heroes III on gog.com you can download backup offline installer from gog.com, and VCMI will import Heroes III data using offline installer.
|
||||
Offline installer consists of two parts, .exe and .bin. Make sure you download both of them.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Якщо у вас є Heroes III на gog.com, ви можете завантажити резервну копію офлайн-інсталятора з gog.com, і VCMI імпортує дані Heroes III за допомогою офлайн-інсталятора.
|
||||
Офлайн-інсталятор складається з двох частин, .exe та .bin. Переконайтеся, що ви завантажили обидві частини.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="696"/>
|
||||
@ -1173,7 +1174,7 @@ Offline installer consists of two parts, .exe and .bin. Make sure you download b
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="354"/>
|
||||
<source>Manual Installation</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ручне встановлення</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="367"/>
|
||||
@ -1487,13 +1488,14 @@ Please select directory with Heroes III: Complete Edition or Heroes III: Shadow
|
||||
<message>
|
||||
<location filename="../main.cpp" line="121"/>
|
||||
<source>Error starting executable</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Помилка запуску виконуваного файлу</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../main.cpp" line="122"/>
|
||||
<source>Failed to start %1
|
||||
Reason: %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Не вдалося запустити %1
|
||||
Причина: %2</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -648,7 +648,9 @@ std::shared_ptr<CCreature> CCreatureHandler::loadFromJson(const std::string & sc
|
||||
|
||||
if (!cre->special &&
|
||||
!CResourceHandler::get()->existsResource(cre->animDefName) &&
|
||||
!CResourceHandler::get()->existsResource(cre->animDefName.addPrefix("SPRITES/")))
|
||||
!CResourceHandler::get()->existsResource(cre->animDefName.toType<EResType::JSON>()) &&
|
||||
!CResourceHandler::get()->existsResource(cre->animDefName.addPrefix("SPRITES/")) &&
|
||||
!CResourceHandler::get()->existsResource(cre->animDefName.addPrefix("SPRITES/").toType<EResType::JSON>()))
|
||||
throw ModLoadingException(scope, "creature " + cre->getJsonKey() + " has no combat animation but is not marked as special!" );
|
||||
|
||||
JsonNode advMapFile = node["graphics"]["map"];
|
||||
|
@ -158,17 +158,17 @@ void CPrivilegedInfoCallback::pickAllowedArtsSet(std::vector<const CArtifact *>
|
||||
|
||||
void CPrivilegedInfoCallback::getAllowedSpells(std::vector<SpellID> & out, std::optional<ui16> level)
|
||||
{
|
||||
for (ui32 i = 0; i < gs->map->allowedSpells.size(); i++) //spellh size appears to be greater (?)
|
||||
for (auto const & spellID : gs->map->allowedSpells)
|
||||
{
|
||||
const spells::Spell * spell = SpellID(i).toSpell();
|
||||
const auto * spell = spellID.toEntity(VLC);
|
||||
|
||||
if (!isAllowed(spell->getId()))
|
||||
if (!isAllowed(spellID))
|
||||
continue;
|
||||
|
||||
if (level.has_value() && spell->getLevel() != level)
|
||||
continue;
|
||||
|
||||
out.push_back(spell->getId());
|
||||
out.push_back(spellID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>, public Se
|
||||
BonusSubtypeID subtype;
|
||||
|
||||
BonusSource source = BonusSource::OTHER; //source type" uses BonusSource values - what gave that bonus
|
||||
BonusSource targetSourceType;//Bonuses of what origin this amplifies, uses BonusSource values. Needed for PERCENT_TO_TARGET_TYPE.
|
||||
BonusSource targetSourceType = BonusSource::OTHER;//Bonuses of what origin this amplifies, uses BonusSource values. Needed for PERCENT_TO_TARGET_TYPE.
|
||||
si32 val = 0;
|
||||
BonusSourceID sid; //source id: id of object/artifact/spell
|
||||
BonusValueType valType = BonusValueType::ADDITIVE_VALUE;
|
||||
|
@ -51,8 +51,15 @@ namespace Selector
|
||||
return seffectRange;
|
||||
}
|
||||
|
||||
DLL_LINKAGE CWillLastTurns turns;
|
||||
DLL_LINKAGE CWillLastDays days;
|
||||
DLL_LINKAGE CWillLastTurns turns(int turns)
|
||||
{
|
||||
return CWillLastTurns(turns);
|
||||
}
|
||||
|
||||
DLL_LINKAGE CWillLastDays days(int days)
|
||||
{
|
||||
return CWillLastDays(days);
|
||||
}
|
||||
|
||||
CSelector DLL_LINKAGE typeSubtype(BonusType Type, BonusSubtypeID Subtype)
|
||||
{
|
||||
|
@ -81,8 +81,11 @@ public:
|
||||
|
||||
class DLL_LINKAGE CWillLastTurns
|
||||
{
|
||||
public:
|
||||
int turnsRequested;
|
||||
public:
|
||||
CWillLastTurns(int turnsRequested):
|
||||
turnsRequested(turnsRequested)
|
||||
{}
|
||||
|
||||
bool operator()(const Bonus *bonus) const
|
||||
{
|
||||
@ -90,18 +93,17 @@ public:
|
||||
|| !Bonus::NTurns(bonus) //so do every not expriing after N-turns effect
|
||||
|| bonus->turnsRemain > turnsRequested;
|
||||
}
|
||||
CWillLastTurns& operator()(const int &setVal)
|
||||
{
|
||||
turnsRequested = setVal;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CWillLastDays
|
||||
{
|
||||
public:
|
||||
int daysRequested;
|
||||
|
||||
public:
|
||||
CWillLastDays(int daysRequested):
|
||||
daysRequested(daysRequested)
|
||||
{}
|
||||
|
||||
bool operator()(const Bonus *bonus) const
|
||||
{
|
||||
if(daysRequested <= 0 || Bonus::Permanent(bonus) || Bonus::OneBattle(bonus))
|
||||
@ -112,14 +114,8 @@ public:
|
||||
{
|
||||
return bonus->turnsRemain > daysRequested;
|
||||
}
|
||||
|
||||
return false; // TODO: ONE_WEEK need support for turnsRemain, but for now we'll exclude all unhandled durations
|
||||
}
|
||||
CWillLastDays& operator()(const int &setVal)
|
||||
{
|
||||
daysRequested = setVal;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -131,8 +127,8 @@ namespace Selector
|
||||
extern DLL_LINKAGE const CSelectFieldEqual<BonusSource> & sourceType();
|
||||
extern DLL_LINKAGE const CSelectFieldEqual<BonusSource> & targetSourceType();
|
||||
extern DLL_LINKAGE const CSelectFieldEqual<BonusLimitEffect> & effectRange();
|
||||
extern DLL_LINKAGE CWillLastTurns turns;
|
||||
extern DLL_LINKAGE CWillLastDays days;
|
||||
CWillLastTurns DLL_LINKAGE turns(int turns);
|
||||
CWillLastDays DLL_LINKAGE days(int days);
|
||||
|
||||
CSelector DLL_LINKAGE typeSubtype(BonusType Type, BonusSubtypeID Subtype);
|
||||
CSelector DLL_LINKAGE typeSubtypeInfo(BonusType type, BonusSubtypeID subtype, const CAddInfo & info);
|
||||
|
@ -118,7 +118,7 @@ class DLL_LINKAGE HasAnotherBonusLimiter : public ILimiter //applies only to nod
|
||||
public:
|
||||
BonusType type;
|
||||
BonusSubtypeID subtype;
|
||||
BonusSource source;
|
||||
BonusSource source = BonusSource::OTHER;
|
||||
BonusSourceID sid;
|
||||
bool isSubtypeRelevant; //check for subtype only if this is true
|
||||
bool isSourceRelevant; //check for bonus source only if this is true
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include "StdInc.h"
|
||||
#include "CFileInputStream.h"
|
||||
|
||||
#include "../ExceptionsCommon.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
CFileInputStream::CFileInputStream(const boost::filesystem::path & file, si64 start, si64 size)
|
||||
@ -18,7 +20,7 @@ CFileInputStream::CFileInputStream(const boost::filesystem::path & file, si64 st
|
||||
fileStream{file.c_str(), std::ios::in | std::ios::binary}
|
||||
{
|
||||
if (fileStream.fail())
|
||||
throw std::runtime_error("File " + file.string() + " isn't available.");
|
||||
throw DataLoadingException("Failed to open file '" + file.string() + "'. Reason: " + strerror(errno) );
|
||||
|
||||
if (dataSize == 0)
|
||||
{
|
||||
|
@ -12,14 +12,22 @@
|
||||
|
||||
#include "CFileInputStream.h"
|
||||
|
||||
#include "../ExceptionsCommon.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
CFilesystemLoader::CFilesystemLoader(std::string _mountPoint, boost::filesystem::path baseDirectory, size_t depth, bool initial):
|
||||
baseDirectory(std::move(baseDirectory)),
|
||||
mountPoint(std::move(_mountPoint)),
|
||||
fileList(listFiles(mountPoint, depth, initial)),
|
||||
recursiveDepth(depth)
|
||||
{
|
||||
try {
|
||||
fileList = listFiles(mountPoint, depth, initial);
|
||||
}
|
||||
catch (const boost::filesystem::filesystem_error & e) {
|
||||
throw DataLoadingException("Failed to load content of '" + baseDirectory.string() + "'. Reason: " + e.what());
|
||||
}
|
||||
|
||||
logGlobal->trace("File system loaded, %d files found", fileList.size());
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ void AObjectTypeHandler::preInitObject(CGObjectInstance * obj) const
|
||||
obj->ID = Obj(type);
|
||||
obj->subID = subtype;
|
||||
obj->typeName = typeName;
|
||||
obj->subTypeName = subTypeName;
|
||||
obj->subTypeName = getJsonKey();
|
||||
obj->blockVisit = blockVisit;
|
||||
obj->removable = removable;
|
||||
}
|
||||
|
@ -181,13 +181,14 @@ void COPWBonus::onHeroVisit (const CGHeroInstance * h) const
|
||||
if(visitors.empty())
|
||||
{
|
||||
if(h->mana < h->manaLimit() * 2)
|
||||
{
|
||||
cb->setManaPoints (heroID, 2 * h->manaLimit());
|
||||
//TODO: investigate line below
|
||||
//cb->setObjProperty (town->id, ObjProperty::VISITED, true);
|
||||
iw.text.appendRawString(getVisitingBonusGreeting());
|
||||
cb->showInfoDialog(&iw);
|
||||
//extra visit penalty if hero alredy had double mana points (or even more?!)
|
||||
town->addHeroToStructureVisitors(h, indexOnTV);
|
||||
//TODO: investigate line below
|
||||
//cb->setObjProperty (town->id, ObjProperty::VISITED, true);
|
||||
iw.text.appendRawString(getVisitingBonusGreeting());
|
||||
cb->showInfoDialog(&iw);
|
||||
town->addHeroToStructureVisitors(h, indexOnTV);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -141,6 +141,8 @@ bool CQuest::checkQuest(const CGHeroInstance * h) const
|
||||
|
||||
void CQuest::completeQuest(IGameCallback * cb, const CGHeroInstance *h) const
|
||||
{
|
||||
// FIXME: this should be part of 'reward', and not hacking into limiter state that should only limit access to such reward
|
||||
|
||||
for(auto & elem : mission.artifacts)
|
||||
{
|
||||
if(h->hasArt(elem))
|
||||
@ -164,9 +166,9 @@ void CQuest::completeQuest(IGameCallback * cb, const CGHeroInstance *h) const
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cb->takeCreatures(h->id, mission.creatures);
|
||||
cb->giveResources(h->getOwner(), mission.resources);
|
||||
cb->giveResources(h->getOwner(), -mission.resources);
|
||||
}
|
||||
|
||||
void CQuest::addTextReplacements(IGameCallback * cb, MetaString & text, std::vector<Component> & components) const
|
||||
|
@ -263,6 +263,9 @@ void CGResource::pickRandomObject(CRandomGenerator & rand)
|
||||
ID = Obj::RESOURCE;
|
||||
subID = rand.nextInt(EGameResID::WOOD, EGameResID::GOLD);
|
||||
setType(ID, subID);
|
||||
|
||||
if (subID == EGameResID::GOLD && amount != CGResource::RANDOM_AMOUNT)
|
||||
amount *= CGResource::GOLD_AMOUNT_MULTIPLIER;
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,7 +278,7 @@ void CGResource::initObj(CRandomGenerator & rand)
|
||||
switch(resourceID().toEnum())
|
||||
{
|
||||
case EGameResID::GOLD:
|
||||
amount = rand.nextInt(5, 10) * 100;
|
||||
amount = rand.nextInt(5, 10) * CGResource::GOLD_AMOUNT_MULTIPLIER;
|
||||
break;
|
||||
case EGameResID::WOOD: case EGameResID::ORE:
|
||||
amount = rand.nextInt(6, 10);
|
||||
@ -490,7 +493,7 @@ void CGMonolith::onHeroVisit( const CGHeroInstance * h ) const
|
||||
auto exits = cb->getTeleportChannelExits(channel);
|
||||
for(const auto & exit : exits)
|
||||
{
|
||||
td.exits.push_back(std::make_pair(exit, h->convertFromVisitablePos(cb->getObj(exit)->visitablePos())));
|
||||
td.exits.push_back(std::make_pair(exit, cb->getObj(exit)->visitablePos()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -522,9 +525,9 @@ void CGMonolith::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer,
|
||||
else if(vstd::isValidIndex(exits, answer))
|
||||
dPos = exits[answer].second;
|
||||
else
|
||||
dPos = hero->convertFromVisitablePos(cb->getObj(randomExit)->visitablePos());
|
||||
dPos = cb->getObj(randomExit)->visitablePos();
|
||||
|
||||
cb->moveHero(hero->id, dPos, EMovementMode::MONOLITH);
|
||||
cb->moveHero(hero->id, hero->convertFromVisitablePos(dPos), EMovementMode::MONOLITH);
|
||||
}
|
||||
|
||||
void CGMonolith::initObj(CRandomGenerator & rand)
|
||||
@ -566,7 +569,7 @@ void CGSubterraneanGate::onHeroVisit( const CGHeroInstance * h ) const
|
||||
else
|
||||
{
|
||||
auto exit = getRandomExit(h);
|
||||
td.exits.push_back(std::make_pair(exit, h->convertFromVisitablePos(cb->getObj(exit)->visitablePos())));
|
||||
td.exits.push_back(std::make_pair(exit, cb->getObj(exit)->visitablePos()));
|
||||
}
|
||||
|
||||
cb->showTeleportDialog(&td);
|
||||
@ -676,7 +679,7 @@ void CGWhirlpool::onHeroVisit( const CGHeroInstance * h ) const
|
||||
{
|
||||
auto blockedPosList = cb->getObj(exit)->getBlockedPos();
|
||||
for(const auto & bPos : blockedPosList)
|
||||
td.exits.push_back(std::make_pair(exit, h->convertFromVisitablePos(bPos)));
|
||||
td.exits.push_back(std::make_pair(exit, bPos));
|
||||
}
|
||||
}
|
||||
|
||||
@ -700,10 +703,10 @@ void CGWhirlpool::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer
|
||||
|
||||
const auto * obj = cb->getObj(exit);
|
||||
std::set<int3> tiles = obj->getBlockedPos();
|
||||
dPos = hero->convertFromVisitablePos(*RandomGeneratorUtil::nextItem(tiles, CRandomGenerator::getDefault()));
|
||||
dPos = *RandomGeneratorUtil::nextItem(tiles, CRandomGenerator::getDefault());
|
||||
}
|
||||
|
||||
cb->moveHero(hero->id, dPos, EMovementMode::MONOLITH);
|
||||
cb->moveHero(hero->id, hero->convertFromVisitablePos(dPos), EMovementMode::MONOLITH);
|
||||
}
|
||||
|
||||
bool CGWhirlpool::isProtected(const CGHeroInstance * h)
|
||||
|
@ -122,8 +122,9 @@ class DLL_LINKAGE CGResource : public CArmedInstance
|
||||
public:
|
||||
using CArmedInstance::CArmedInstance;
|
||||
|
||||
static constexpr ui32 RANDOM_AMOUNT = 0;
|
||||
ui32 amount = RANDOM_AMOUNT; //0 if random
|
||||
static constexpr uint32_t RANDOM_AMOUNT = 0;
|
||||
static constexpr uint32_t GOLD_AMOUNT_MULTIPLIER = 100;
|
||||
uint32_t amount = RANDOM_AMOUNT; //0 if random
|
||||
|
||||
MetaString message;
|
||||
|
||||
|
@ -208,13 +208,13 @@ class DLL_LINKAGE CMapHeader: public Serializeable
|
||||
void setupEvents();
|
||||
public:
|
||||
|
||||
static const int MAP_SIZE_SMALL = 36;
|
||||
static const int MAP_SIZE_MIDDLE = 72;
|
||||
static const int MAP_SIZE_LARGE = 108;
|
||||
static const int MAP_SIZE_XLARGE = 144;
|
||||
static const int MAP_SIZE_HUGE = 180;
|
||||
static const int MAP_SIZE_XHUGE = 216;
|
||||
static const int MAP_SIZE_GIANT = 252;
|
||||
static constexpr int MAP_SIZE_SMALL = 36;
|
||||
static constexpr int MAP_SIZE_MIDDLE = 72;
|
||||
static constexpr int MAP_SIZE_LARGE = 108;
|
||||
static constexpr int MAP_SIZE_XLARGE = 144;
|
||||
static constexpr int MAP_SIZE_HUGE = 180;
|
||||
static constexpr int MAP_SIZE_XHUGE = 216;
|
||||
static constexpr int MAP_SIZE_GIANT = 252;
|
||||
|
||||
CMapHeader();
|
||||
virtual ~CMapHeader();
|
||||
|
@ -1315,7 +1315,7 @@ CGObjectInstance * CMapLoaderH3M::readResource(const int3 & mapPosition, std::sh
|
||||
if(GameResID(objectTemplate->subid) == GameResID(EGameResID::GOLD))
|
||||
{
|
||||
// Gold is multiplied by 100.
|
||||
object->amount *= 100;
|
||||
object->amount *= CGResource::GOLD_AMOUNT_MULTIPLIER;
|
||||
}
|
||||
reader->skipZero(4);
|
||||
return object;
|
||||
|
@ -227,10 +227,7 @@ void CModHandler::loadOneMod(std::string modName, const std::string & parent, co
|
||||
|
||||
if(CResourceHandler::get("initial")->existsResource(CModInfo::getModFile(modFullName)))
|
||||
{
|
||||
JsonParsingSettings settings;
|
||||
settings.mode = JsonParsingSettings::JsonFormatMode::JSON; // TODO: remove once Android launcher with its strict parser is gone
|
||||
|
||||
CModInfo mod(modFullName, modSettings[modName], JsonNode(CModInfo::getModFile(modFullName), settings));
|
||||
CModInfo mod(modFullName, modSettings[modName], JsonNode(CModInfo::getModFile(modFullName)));
|
||||
if (!parent.empty()) // this is submod, add parent to dependencies
|
||||
mod.dependencies.insert(parent);
|
||||
|
||||
|
@ -284,9 +284,12 @@ void CMapGenOptions::resetPlayersMap()
|
||||
|
||||
while (players.size() > realPlayersCnt)
|
||||
{
|
||||
while (eraseLastPlayer(EPlayerType::AI));
|
||||
while (eraseLastPlayer(EPlayerType::COMP_ONLY));
|
||||
while (eraseLastPlayer(EPlayerType::HUMAN));
|
||||
if (eraseLastPlayer(EPlayerType::AI))
|
||||
continue;
|
||||
if (eraseLastPlayer(EPlayerType::COMP_ONLY))
|
||||
continue;
|
||||
if (eraseLastPlayer(EPlayerType::HUMAN))
|
||||
continue;
|
||||
}
|
||||
|
||||
//First colors from the list are assigned to human players, then to CPU players
|
||||
@ -503,8 +506,9 @@ void CMapGenOptions::finalize(CRandomGenerator & rand)
|
||||
if (getHumanOrCpuPlayerCount() == RANDOM_SIZE)
|
||||
{
|
||||
auto possiblePlayers = mapTemplate->getPlayers().getNumbers();
|
||||
int requiredPlayers = countHumanPlayers() + countCompOnlyPlayers();
|
||||
//ignore all non-randomized players, make sure these players will not be missing after roll
|
||||
possiblePlayers.erase(possiblePlayers.begin(), possiblePlayers.lower_bound(countHumanPlayers() + countCompOnlyPlayers()));
|
||||
possiblePlayers.erase(possiblePlayers.begin(), possiblePlayers.lower_bound(requiredPlayers));
|
||||
|
||||
vstd::erase_if(possiblePlayers, [maxPlayers](int i)
|
||||
{
|
||||
@ -598,7 +602,9 @@ void CMapGenOptions::updatePlayers()
|
||||
{
|
||||
auto it = itrev;
|
||||
--it;
|
||||
if (players.size() == getHumanOrCpuPlayerCount()) break;
|
||||
if (players.size() == getHumanOrCpuPlayerCount())
|
||||
break;
|
||||
|
||||
if(it->second.getPlayerType() != EPlayerType::HUMAN)
|
||||
{
|
||||
players.erase(it);
|
||||
|
@ -455,9 +455,9 @@ void CZonePlacer::prepareZones(TZoneMap &zones, TZoneVector &zonesVector, const
|
||||
auto player = PlayerColor(*owner - 1);
|
||||
auto playerSettings = map.getMapGenOptions().getPlayersSettings();
|
||||
FactionID faction = FactionID::RANDOM;
|
||||
if (vstd::contains(playerSettings, player))
|
||||
if (playerSettings.size() > player)
|
||||
{
|
||||
faction = playerSettings[player].getStartingTown();
|
||||
faction = std::next(playerSettings.begin(), player)->second.getStartingTown();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -369,12 +369,7 @@ ui32 RmgMap::getTotalZoneCount() const
|
||||
bool RmgMap::isAllowedSpell(const SpellID & sid) const
|
||||
{
|
||||
assert(sid.getNum() >= 0);
|
||||
if (sid.getNum() < mapInstance->allowedSpells.size())
|
||||
{
|
||||
return mapInstance->allowedSpells.count(sid);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
return mapInstance->allowedSpells.count(sid);
|
||||
}
|
||||
|
||||
void RmgMap::dump(bool zoneId) const
|
||||
|
@ -54,12 +54,14 @@ void TownPlacer::placeTowns(ObjectManager & manager)
|
||||
//set zone types to player faction, generate main town
|
||||
logGlobal->info("Preparing playing zone");
|
||||
int player_id = *zone.getOwner() - 1;
|
||||
auto& playerInfo = map.getPlayer(player_id);
|
||||
PlayerColor player(player_id);
|
||||
if(playerInfo.canAnyonePlay())
|
||||
const auto & playerSettings = map.getMapGenOptions().getPlayersSettings();
|
||||
PlayerColor player;
|
||||
|
||||
if (playerSettings.size() > player_id)
|
||||
{
|
||||
player = PlayerColor(player_id);
|
||||
zone.setTownType(map.getMapGenOptions().getPlayersSettings().find(player)->second.getStartingTown());
|
||||
const auto & currentPlayerSettings = std::next(playerSettings.begin(), player_id);
|
||||
player = currentPlayerSettings->first;
|
||||
zone.setTownType(currentPlayerSettings->second.getStartingTown());
|
||||
|
||||
if(zone.getTownType() == FactionID::RANDOM)
|
||||
zone.setTownType(getRandomTownType(true));
|
||||
@ -87,11 +89,12 @@ void TownPlacer::placeTowns(ObjectManager & manager)
|
||||
//register MAIN town of zone only
|
||||
map.registerZone(town->getFaction());
|
||||
|
||||
if(playerInfo.canAnyonePlay()) //configure info for owning player
|
||||
if(player.isValidPlayer()) //configure info for owning player
|
||||
{
|
||||
logGlobal->trace("Fill player info %d", player_id);
|
||||
|
||||
// Update player info
|
||||
auto & playerInfo = map.getPlayer(player.getNum());
|
||||
playerInfo.allowedFactions.clear();
|
||||
playerInfo.allowedFactions.insert(zone.getTownType());
|
||||
playerInfo.hasMainTown = true;
|
||||
|
@ -219,6 +219,7 @@ bool WaterProxy::waterKeepConnection(const rmg::ZoneConnection & connection, boo
|
||||
const auto & zoneA = connection.getZoneA();
|
||||
const auto & zoneB = connection.getZoneB();
|
||||
|
||||
RecursiveLock lock(externalAccessMutex);
|
||||
for(auto & lake : lakes)
|
||||
{
|
||||
if(lake.neighbourZones.count(zoneA) && lake.neighbourZones.count(zoneB))
|
||||
|
@ -77,6 +77,7 @@ void CConnection::sendPack(const CPack * pack)
|
||||
if (!connectionPtr)
|
||||
throw std::runtime_error("Attempt to send packet on a closed connection!");
|
||||
|
||||
packWriter->buffer.clear();
|
||||
*serializer & pack;
|
||||
|
||||
logNetwork->trace("Sending a pack of type %s", typeid(*pack).name());
|
||||
|
@ -8,6 +8,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "mapcontroller.h"
|
||||
|
||||
#include "../lib/ArtifactUtils.h"
|
||||
@ -57,6 +58,7 @@ void MapController::connectScenes()
|
||||
|
||||
MapController::~MapController()
|
||||
{
|
||||
main = nullptr;
|
||||
}
|
||||
|
||||
const std::unique_ptr<CMap> & MapController::getMapUniquePtr() const
|
||||
@ -228,6 +230,8 @@ void MapController::setMap(std::unique_ptr<CMap> cmap)
|
||||
|
||||
_map->getEditManager()->getUndoManager().setUndoCallback([this](bool allowUndo, bool allowRedo)
|
||||
{
|
||||
if(!main)
|
||||
return;
|
||||
main->enableUndo(allowUndo);
|
||||
main->enableRedo(allowRedo);
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
#pragma once
|
||||
//code is copied from vcmiclient/mapHandler.h with minimal changes
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "../lib/int3.h"
|
||||
#include "Animation.h"
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "StdInc.h"
|
||||
#include <QDialog>
|
||||
#include "playerparams.h"
|
||||
|
||||
|
@ -129,37 +129,37 @@
|
||||
<message>
|
||||
<location filename="../inspector/herospellwidget.ui" line="29"/>
|
||||
<source>Spells</source>
|
||||
<translation type="unfinished">Zaubersprüche</translation>
|
||||
<translation>Zaubersprüche</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/herospellwidget.ui" line="47"/>
|
||||
<source>Customize spells</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Zaubersprüche anpassen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/herospellwidget.ui" line="76"/>
|
||||
<source>Level 1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Level 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/herospellwidget.ui" line="114"/>
|
||||
<source>Level 2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Level 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/herospellwidget.ui" line="152"/>
|
||||
<source>Level 3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Level 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/herospellwidget.ui" line="190"/>
|
||||
<source>Level 4</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Level 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/herospellwidget.ui" line="228"/>
|
||||
<source>Level 5</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Level 5</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -1738,32 +1738,32 @@
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="164"/>
|
||||
<source>S (36x36)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>S (36x36)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="169"/>
|
||||
<source>M (72x72)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>M (72x72)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="174"/>
|
||||
<source>L (108x108)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>L (108x108)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="184"/>
|
||||
<source>H (180x180)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>H (180x180)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="189"/>
|
||||
<source>XH (216x216)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>XH (216x216)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="194"/>
|
||||
<source>G (252x252)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>G (252x252)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="248"/>
|
||||
|
@ -108,7 +108,7 @@ bool WindowNewMap::loadUserSettings()
|
||||
|
||||
ui->widthTxt->setText(QString::number(mapGenOptions.getWidth()));
|
||||
ui->heightTxt->setText(QString::number(mapGenOptions.getHeight()));
|
||||
for(auto & sz : mapSizes)
|
||||
for(const auto & sz : mapSizes)
|
||||
{
|
||||
if(sz.second.first == mapGenOptions.getWidth() &&
|
||||
sz.second.second == mapGenOptions.getHeight())
|
||||
|
@ -11,6 +11,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "../lib/mapping/CMapHeader.h"
|
||||
#include "../lib/rmg/CMapGenOptions.h"
|
||||
|
||||
namespace Ui
|
||||
@ -62,7 +64,7 @@ class WindowNewMap : public QDialog
|
||||
{7, 6},
|
||||
{8, 7}
|
||||
};
|
||||
|
||||
|
||||
const std::map<int, std::pair<int, int>> mapSizes
|
||||
{
|
||||
{0, {CMapHeader::MAP_SIZE_SMALL, CMapHeader::MAP_SIZE_SMALL}},
|
||||
|
@ -662,6 +662,10 @@ void CVCMIServer::updateAndPropagateLobbyState()
|
||||
{
|
||||
si->mapGenOptions->setPlayerTypeForStandardPlayer(pset.color, EPlayerType::HUMAN);
|
||||
}
|
||||
else
|
||||
{
|
||||
si->mapGenOptions->setPlayerTypeForStandardPlayer(pset.color, EPlayerType::AI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,10 +313,8 @@ void TurnTimerHandler::onBattleLoop(const BattleID & battleID, int waitTime)
|
||||
}
|
||||
else
|
||||
{
|
||||
BattleAction retreat;
|
||||
retreat.side = side;
|
||||
retreat.actionType = EActionType::RETREAT; //harsh punishment
|
||||
gameHandler.battles->makePlayerBattleAction(battleID, player, retreat);
|
||||
// battle vs neutrals - no-op, let battle run till the end
|
||||
// once battle is over player turn will be over due to running out of timer on adventure map
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user