mirror of
https://github.com/vcmi/vcmi.git
synced 2025-05-13 22:06:58 +02:00
commit
9c13ac8eb0
2
.github/workflows/github.yml
vendored
2
.github/workflows/github.yml
vendored
@ -244,7 +244,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Trigger Android
|
- name: Trigger Android
|
||||||
uses: peter-evans/repository-dispatch@v1
|
uses: peter-evans/repository-dispatch@v1
|
||||||
if: ${{ (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master') && matrix.platform == 'mxe' }}
|
if: ${{ (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/beta' || github.ref == 'refs/heads/master') && matrix.platform == 'mxe' }}
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.VCMI_ANDROID_ACCESS_TOKEN }}
|
token: ${{ secrets.VCMI_ANDROID_ACCESS_TOKEN }}
|
||||||
repository: vcmi/vcmi-android
|
repository: vcmi/vcmi-android
|
||||||
|
@ -202,7 +202,6 @@ void ObjectClusterizer::clusterize()
|
|||||||
Obj::WHIRLPOOL,
|
Obj::WHIRLPOOL,
|
||||||
Obj::BUOY,
|
Obj::BUOY,
|
||||||
Obj::SIGN,
|
Obj::SIGN,
|
||||||
Obj::SIGN,
|
|
||||||
Obj::GARRISON,
|
Obj::GARRISON,
|
||||||
Obj::MONSTER,
|
Obj::MONSTER,
|
||||||
Obj::GARRISON2,
|
Obj::GARRISON2,
|
||||||
|
12
CI/conan/base/apple
Normal file
12
CI/conan/base/apple
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[settings]
|
||||||
|
compiler=apple-clang
|
||||||
|
compiler.version=14
|
||||||
|
compiler.libcxx=libc++
|
||||||
|
build_type=Release
|
||||||
|
|
||||||
|
# required for Boost.Locale in versions >= 1.81
|
||||||
|
compiler.cppstd=11
|
||||||
|
|
||||||
|
[conf]
|
||||||
|
tools.apple:enable_bitcode = False
|
||||||
|
tools.cmake.cmaketoolchain:generator = Ninja
|
5
CI/conan/base/ios
Normal file
5
CI/conan/base/ios
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
include(apple)
|
||||||
|
|
||||||
|
[settings]
|
||||||
|
os=iOS
|
||||||
|
os.sdk=iphoneos
|
4
CI/conan/base/macos
Normal file
4
CI/conan/base/macos
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
include(apple)
|
||||||
|
|
||||||
|
[settings]
|
||||||
|
os=Macos
|
@ -1,14 +1,5 @@
|
|||||||
|
include(base/ios)
|
||||||
|
|
||||||
[settings]
|
[settings]
|
||||||
os=iOS
|
|
||||||
os.version=12.0
|
os.version=12.0
|
||||||
os.sdk=iphoneos
|
|
||||||
arch=armv8
|
arch=armv8
|
||||||
compiler=apple-clang
|
|
||||||
compiler.version=13
|
|
||||||
compiler.libcxx=libc++
|
|
||||||
build_type=Release
|
|
||||||
[options]
|
|
||||||
[build_requires]
|
|
||||||
[env]
|
|
||||||
[conf]
|
|
||||||
tools.cmake.cmaketoolchain:generator = Ninja
|
|
||||||
|
@ -1,14 +1,8 @@
|
|||||||
|
include(base/ios)
|
||||||
|
|
||||||
[settings]
|
[settings]
|
||||||
os=iOS
|
|
||||||
os.version=10.0
|
os.version=10.0
|
||||||
os.sdk=iphoneos
|
|
||||||
arch=armv7
|
arch=armv7
|
||||||
compiler=apple-clang
|
|
||||||
|
# Xcode 13.x is the last version that can build for armv7
|
||||||
compiler.version=13
|
compiler.version=13
|
||||||
compiler.libcxx=libc++
|
|
||||||
build_type=Release
|
|
||||||
[options]
|
|
||||||
[build_requires]
|
|
||||||
[env]
|
|
||||||
[conf]
|
|
||||||
tools.cmake.cmaketoolchain:generator = Ninja
|
|
||||||
|
@ -1,13 +1,5 @@
|
|||||||
|
include(base/macos)
|
||||||
|
|
||||||
[settings]
|
[settings]
|
||||||
os=Macos
|
|
||||||
os.version=11.0
|
os.version=11.0
|
||||||
arch=armv8
|
arch=armv8
|
||||||
compiler=apple-clang
|
|
||||||
compiler.version=13
|
|
||||||
compiler.libcxx=libc++
|
|
||||||
build_type=Release
|
|
||||||
[options]
|
|
||||||
[build_requires]
|
|
||||||
[env]
|
|
||||||
[conf]
|
|
||||||
tools.cmake.cmaketoolchain:generator = Ninja
|
|
||||||
|
@ -1,13 +1,5 @@
|
|||||||
|
include(base/macos)
|
||||||
|
|
||||||
[settings]
|
[settings]
|
||||||
os=Macos
|
|
||||||
os.version=10.13
|
os.version=10.13
|
||||||
arch=x86_64
|
arch=x86_64
|
||||||
compiler=apple-clang
|
|
||||||
compiler.version=13
|
|
||||||
compiler.libcxx=libc++
|
|
||||||
build_type=Release
|
|
||||||
[options]
|
|
||||||
[build_requires]
|
|
||||||
[env]
|
|
||||||
[conf]
|
|
||||||
tools.cmake.cmaketoolchain:generator = Ninja
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
echo DEVELOPER_DIR=/Applications/Xcode_13.4.1.app >> $GITHUB_ENV
|
echo DEVELOPER_DIR=/Applications/Xcode_14.2.app >> $GITHUB_ENV
|
||||||
|
|
||||||
mkdir ~/.conan ; cd ~/.conan
|
mkdir ~/.conan ; cd ~/.conan
|
||||||
curl -L 'https://github.com/vcmi/vcmi-ios-deps/releases/download/1.1/ios-arm64.xz' \
|
curl -L 'https://github.com/vcmi/vcmi-ios-deps/releases/download/1.2/ios-arm64.txz' \
|
||||||
| tar -xf -
|
| tar -xf -
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
"$1/ios/zip2ipa.sh" "$2"
|
|
@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
echo DEVELOPER_DIR=/Applications/Xcode_13.4.1.app >> $GITHUB_ENV
|
echo DEVELOPER_DIR=/Applications/Xcode_14.2.app >> $GITHUB_ENV
|
||||||
|
|
||||||
brew install ninja
|
brew install ninja
|
||||||
|
|
||||||
mkdir ~/.conan ; cd ~/.conan
|
mkdir ~/.conan ; cd ~/.conan
|
||||||
curl -L "https://github.com/vcmi/vcmi-deps-macos/releases/download/1.1/$DEPS_FILENAME.txz" \
|
curl -L "https://github.com/vcmi/vcmi-deps-macos/releases/download/1.2/$DEPS_FILENAME.txz" \
|
||||||
| tar -xf -
|
| tar -xf -
|
||||||
|
@ -506,6 +506,9 @@ if(WIN32)
|
|||||||
FILES ${integration_loc}
|
FILES ${integration_loc}
|
||||||
DESTINATION ${BIN_DIR}/platforms
|
DESTINATION ${BIN_DIR}/platforms
|
||||||
)
|
)
|
||||||
|
install(
|
||||||
|
FILES "$<TARGET_FILE:Qt${QT_VERSION_MAJOR}::QWindowsVistaStylePlugin>"
|
||||||
|
DESTINATION ${BIN_DIR}/styles)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -618,6 +621,7 @@ elseif(APPLE_MACOS AND NOT ENABLE_MONOLITHIC_INSTALL)
|
|||||||
add_subdirectory(osx)
|
add_subdirectory(osx)
|
||||||
elseif(APPLE_IOS)
|
elseif(APPLE_IOS)
|
||||||
set(CPACK_GENERATOR ZIP)
|
set(CPACK_GENERATOR ZIP)
|
||||||
|
set(CPACK_ARCHIVE_FILE_EXTENSION ipa)
|
||||||
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
|
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
|
||||||
set(CPACK_INSTALL_CMAKE_PROJECTS "${CMAKE_CURRENT_BINARY_DIR};${CMAKE_PROJECT_NAME};app;/")
|
set(CPACK_INSTALL_CMAKE_PROJECTS "${CMAKE_CURRENT_BINARY_DIR};${CMAKE_PROJECT_NAME};app;/")
|
||||||
else()
|
else()
|
||||||
|
31
ChangeLog
31
ChangeLog
@ -1,3 +1,34 @@
|
|||||||
|
# 1.1.0 -> 1.1.1
|
||||||
|
|
||||||
|
### GENERAL:
|
||||||
|
* Fixed missing sound in Polish version from gog.com
|
||||||
|
* Fixed positioning of main menu buttons in localized versions of H3
|
||||||
|
* Fixed crash on transferring artifact to commander
|
||||||
|
* Fixed game freeze on receiving multiple artifact assembly dialogs after combat
|
||||||
|
* Fixed potential game freeze on end of music playback
|
||||||
|
* macOS/iOS: fixed sound glitches
|
||||||
|
* Android: upgraded version of SDL library
|
||||||
|
* Android: reworked right click gesture and relative pointer mode
|
||||||
|
* Improved map loading speed
|
||||||
|
|
||||||
|
### ADVENTURE MAP:
|
||||||
|
* Fixed hero movement lag in single-player games
|
||||||
|
* Fixed number of drowned troops on visiting Sirens to match H3
|
||||||
|
* iOS: pinch gesture visits current object (Spacebar behavior) instead of activating in-game console
|
||||||
|
|
||||||
|
### TOWNS:
|
||||||
|
* Fixed displaying growth bonus from Statue of Legion
|
||||||
|
* Growth bonus tooltip ordering now matches H3
|
||||||
|
* Buy All Units dialog will now buy units starting from the highest level
|
||||||
|
|
||||||
|
### LAUNCHER:
|
||||||
|
* Local mods can be disabled or uninstalled
|
||||||
|
* Fixed styling of Launcher interface
|
||||||
|
|
||||||
|
### MAP EDITOR:
|
||||||
|
* Fixed saving of roads and rivers
|
||||||
|
* Fixed placement of heroes on map
|
||||||
|
|
||||||
1.0.0 -> 1.1.0
|
1.0.0 -> 1.1.0
|
||||||
|
|
||||||
GENERAL:
|
GENERAL:
|
||||||
|
@ -374,7 +374,8 @@ int main(int argc, char * argv[])
|
|||||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
|
||||||
#endif // VCMI_ANDROID
|
#endif // VCMI_ANDROID
|
||||||
|
|
||||||
GH.mainFPSmng->init(); //(!)init here AFTER SDL_Init() while using SDL for FPS management
|
//(!)init here AFTER SDL_Init() while using SDL for FPS management
|
||||||
|
GH.init();
|
||||||
|
|
||||||
SDL_LogSetOutputFunction(&SDLLogCallback, nullptr);
|
SDL_LogSetOutputFunction(&SDLLogCallback, nullptr);
|
||||||
|
|
||||||
@ -430,11 +431,20 @@ int main(int argc, char * argv[])
|
|||||||
CCS->musich->setVolume((ui32)settings["general"]["music"].Float());
|
CCS->musich->setVolume((ui32)settings["general"]["music"].Float());
|
||||||
logGlobal->info("Initializing screen and sound handling: %d ms", pomtime.getDiff());
|
logGlobal->info("Initializing screen and sound handling: %d ms", pomtime.getDiff());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VCMI_MAC
|
#ifdef VCMI_MAC
|
||||||
// Ctrl+click should be treated as a right click on Mac OS X
|
// Ctrl+click should be treated as a right click on Mac OS X
|
||||||
SDL_SetHint(SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, "1");
|
SDL_SetHint(SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, "1");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SDL_HINT_MOUSE_TOUCH_EVENTS
|
||||||
|
if(GH.isPointerRelativeMode)
|
||||||
|
{
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
|
||||||
|
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef VCMI_NO_THREADED_LOAD
|
#ifndef VCMI_NO_THREADED_LOAD
|
||||||
//we can properly play intro only in the main thread, so we have to move loading to the separate thread
|
//we can properly play intro only in the main thread, so we have to move loading to the separate thread
|
||||||
boost::thread loading(init);
|
boost::thread loading(init);
|
||||||
@ -1079,7 +1089,8 @@ static bool recreateWindow(int w, int h, int bpp, bool fullscreen, int displayIn
|
|||||||
if (displayIndex < 0)
|
if (displayIndex < 0)
|
||||||
displayIndex = 0;
|
displayIndex = 0;
|
||||||
}
|
}
|
||||||
#ifdef VCMI_IOS
|
|
||||||
|
#if defined(VCMI_ANDROID) || defined(VCMI_IOS)
|
||||||
SDL_GetWindowSize(mainWindow, &w, &h);
|
SDL_GetWindowSize(mainWindow, &w, &h);
|
||||||
#else
|
#else
|
||||||
if(!checkVideoMode(displayIndex, w, h))
|
if(!checkVideoMode(displayIndex, w, h))
|
||||||
|
@ -234,8 +234,7 @@ elseif(APPLE_IOS)
|
|||||||
set_source_files_properties(${XCODE_RESOURCE_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
set_source_files_properties(${XCODE_RESOURCE_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||||
|
|
||||||
# workaround to prevent CMAKE_SKIP_PRECOMPILE_HEADERS being added as compile flag
|
# workaround to prevent CMAKE_SKIP_PRECOMPILE_HEADERS being added as compile flag
|
||||||
# add max version condition when https://gitlab.kitware.com/cmake/cmake/-/merge_requests/7562 is merged
|
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22.0" AND CMAKE_VERSION VERSION_LESS "3.25.0")
|
||||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22.0")
|
|
||||||
set_source_files_properties(${XCODE_RESOURCE_PATH} PROPERTIES LANGUAGE CXX)
|
set_source_files_properties(${XCODE_RESOURCE_PATH} PROPERTIES LANGUAGE CXX)
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
@ -409,6 +409,8 @@ void CMusicHandler::release()
|
|||||||
|
|
||||||
void CMusicHandler::playMusic(const std::string & musicURI, bool loop, bool fromStart)
|
void CMusicHandler::playMusic(const std::string & musicURI, bool loop, bool fromStart)
|
||||||
{
|
{
|
||||||
|
boost::mutex::scoped_lock guard(mutex);
|
||||||
|
|
||||||
if (current && current->isPlaying() && current->isTrack(musicURI))
|
if (current && current->isPlaying() && current->isTrack(musicURI))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -422,6 +424,8 @@ void CMusicHandler::playMusicFromSet(const std::string & musicSet, const std::st
|
|||||||
|
|
||||||
void CMusicHandler::playMusicFromSet(const std::string & whichSet, bool loop, bool fromStart)
|
void CMusicHandler::playMusicFromSet(const std::string & whichSet, bool loop, bool fromStart)
|
||||||
{
|
{
|
||||||
|
boost::mutex::scoped_lock guard(mutex);
|
||||||
|
|
||||||
auto selectedSet = musicsSet.find(whichSet);
|
auto selectedSet = musicsSet.find(whichSet);
|
||||||
if (selectedSet == musicsSet.end())
|
if (selectedSet == musicsSet.end())
|
||||||
{
|
{
|
||||||
@ -441,8 +445,6 @@ void CMusicHandler::queueNext(std::unique_ptr<MusicEntry> queued)
|
|||||||
if (!initialized)
|
if (!initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
boost::mutex::scoped_lock guard(mutex);
|
|
||||||
|
|
||||||
next = std::move(queued);
|
next = std::move(queued);
|
||||||
|
|
||||||
if (current.get() == nullptr || !current->stop(1000))
|
if (current.get() == nullptr || !current->stop(1000))
|
||||||
@ -487,13 +489,32 @@ void CMusicHandler::setVolume(ui32 percent)
|
|||||||
|
|
||||||
void CMusicHandler::musicFinishedCallback()
|
void CMusicHandler::musicFinishedCallback()
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock guard(mutex);
|
// boost::mutex::scoped_lock guard(mutex);
|
||||||
|
// FIXME: WORKAROUND FOR A POTENTIAL DEADLOCK
|
||||||
|
// It is possible for:
|
||||||
|
// 1) SDL thread to call this method on end of playback
|
||||||
|
// 2) VCMI code to call queueNext() method to queue new file
|
||||||
|
// this leads to:
|
||||||
|
// 1) SDL thread waiting to acquire music lock in this method (while keeping internal SDL mutex locked)
|
||||||
|
// 2) VCMI thread waiting to acquire internal SDL mutex (while keeping music mutex locked)
|
||||||
|
// Because of that (and lack of clear way to fix that)
|
||||||
|
// We will try to acquire lock here and if failed - do nothing
|
||||||
|
// This may break music playback till next song is enqued but won't deadlock the game
|
||||||
|
|
||||||
|
if (!mutex.try_lock())
|
||||||
|
{
|
||||||
|
logGlobal->error("Failed to acquire mutex! Unable to restart music!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (current.get() != nullptr)
|
if (current.get() != nullptr)
|
||||||
{
|
{
|
||||||
// if music is looped, play it again
|
// if music is looped, play it again
|
||||||
if (current->play())
|
if (current->play())
|
||||||
|
{
|
||||||
|
mutex.unlock();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
current.reset();
|
current.reset();
|
||||||
}
|
}
|
||||||
@ -503,6 +524,7 @@ void CMusicHandler::musicFinishedCallback()
|
|||||||
current.reset(next.release());
|
current.reset(next.release());
|
||||||
current->play();
|
current->play();
|
||||||
}
|
}
|
||||||
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
MusicEntry::MusicEntry(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped, bool fromStart):
|
MusicEntry::MusicEntry(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped, bool fromStart):
|
||||||
@ -520,6 +542,20 @@ MusicEntry::MusicEntry(CMusicHandler *owner, std::string setName, std::string mu
|
|||||||
}
|
}
|
||||||
MusicEntry::~MusicEntry()
|
MusicEntry::~MusicEntry()
|
||||||
{
|
{
|
||||||
|
if (playing)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
logGlobal->error("Attempt to delete music while playing!");
|
||||||
|
Mix_HaltMusic();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loop == 0 && Mix_FadingMusic() != MIX_NO_FADING)
|
||||||
|
{
|
||||||
|
assert(0);
|
||||||
|
logGlobal->error("Attempt to delete music while fading out!");
|
||||||
|
Mix_HaltMusic();
|
||||||
|
}
|
||||||
|
|
||||||
logGlobal->trace("Del-ing music file %s", currentName);
|
logGlobal->trace("Del-ing music file %s", currentName);
|
||||||
if (music)
|
if (music)
|
||||||
Mix_FreeMusic(music);
|
Mix_FreeMusic(music);
|
||||||
|
@ -1702,7 +1702,7 @@ int CPlayerInterface::getLastIndex( std::string namePrefix)
|
|||||||
else
|
else
|
||||||
for (directory_iterator dir(gamesDir); dir != enddir; ++dir)
|
for (directory_iterator dir(gamesDir); dir != enddir; ++dir)
|
||||||
{
|
{
|
||||||
if (is_regular(dir->status()))
|
if (is_regular_file(dir->status()))
|
||||||
{
|
{
|
||||||
std::string name = dir->path().filename().string();
|
std::string name = dir->path().filename().string();
|
||||||
if (starts_with(name, namePrefix) && ends_with(name, ".vcgm1"))
|
if (starts_with(name, namePrefix) && ends_with(name, ".vcgm1"))
|
||||||
@ -2273,6 +2273,8 @@ void CPlayerInterface::artifactRemoved(const ArtifactLocation &al)
|
|||||||
if (artWin)
|
if (artWin)
|
||||||
artWin->artifactRemoved(al);
|
artWin->artifactRemoved(al);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
waitWhileDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst)
|
void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst)
|
||||||
@ -2287,6 +2289,8 @@ void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const Artifact
|
|||||||
}
|
}
|
||||||
if(!GH.objsToBlit.empty())
|
if(!GH.objsToBlit.empty())
|
||||||
GH.objsToBlit.back()->redraw();
|
GH.objsToBlit.back()->redraw();
|
||||||
|
|
||||||
|
waitWhileDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayerInterface::artifactPossibleAssembling(const ArtifactLocation & dst)
|
void CPlayerInterface::artifactPossibleAssembling(const ArtifactLocation & dst)
|
||||||
@ -2546,6 +2550,9 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
|
|||||||
// (i == 0) means hero went through all the path
|
// (i == 0) means hero went through all the path
|
||||||
adventureInt->updateMoveHero(h, (i != 0));
|
adventureInt->updateMoveHero(h, (i != 0));
|
||||||
adventureInt->updateNextHero(h);
|
adventureInt->updateNextHero(h);
|
||||||
|
|
||||||
|
// ugly workaround to force instant update of adventure map
|
||||||
|
adventureInt->animValHitCount = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
setMovementStatus(false);
|
setMovementStatus(false);
|
||||||
|
@ -770,9 +770,15 @@ void CClient::reinitScripting()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef VCMI_ANDROID
|
#ifdef VCMI_ANDROID
|
||||||
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerClosed(JNIEnv * env, jobject cls)
|
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_clientSetupJNI(JNIEnv * env, jclass cls)
|
||||||
|
{
|
||||||
|
logNetwork->info("Received clientSetupJNI");
|
||||||
|
|
||||||
|
CAndroidVMHelper::cacheVM(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerClosed(JNIEnv * env, jclass cls)
|
||||||
{
|
{
|
||||||
logNetwork->info("Received server closed signal");
|
logNetwork->info("Received server closed signal");
|
||||||
if (CSH) {
|
if (CSH) {
|
||||||
@ -780,13 +786,13 @@ extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerCl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerReady(JNIEnv * env, jobject cls)
|
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerReady(JNIEnv * env, jclass cls)
|
||||||
{
|
{
|
||||||
logNetwork->info("Received server ready signal");
|
logNetwork->info("Received server ready signal");
|
||||||
androidTestServerReadyFlag.store(true);
|
androidTestServerReadyFlag.store(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT bool JNICALL Java_eu_vcmi_vcmi_NativeMethods_tryToSaveTheGame(JNIEnv * env, jobject cls)
|
extern "C" JNIEXPORT jboolean JNICALL Java_eu_vcmi_vcmi_NativeMethods_tryToSaveTheGame(JNIEnv * env, jclass cls)
|
||||||
{
|
{
|
||||||
logGlobal->info("Received emergency save game request");
|
logGlobal->info("Received emergency save game request");
|
||||||
if(!LOCPLINT || !LOCPLINT->cb)
|
if(!LOCPLINT || !LOCPLINT->cb)
|
||||||
|
@ -1275,6 +1275,7 @@ void CBattleInterface::battleFinished(const BattleResult& br)
|
|||||||
void CBattleInterface::displayBattleFinished()
|
void CBattleInterface::displayBattleFinished()
|
||||||
{
|
{
|
||||||
CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
|
CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
|
||||||
|
curInt->waitWhileDialog();
|
||||||
if(settings["session"]["spectate"].Bool() && settings["session"]["spectate-skip-battle-result"].Bool())
|
if(settings["session"]["spectate"].Bool() && settings["session"]["spectate-skip-battle-result"].Bool())
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
|
@ -78,6 +78,13 @@ void CGuiHandler::processLists(const ui16 activityFlag, std::function<void (std:
|
|||||||
processList(CIntObject::TEXTINPUT,activityFlag,&textInterested,cb);
|
processList(CIntObject::TEXTINPUT,activityFlag,&textInterested,cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGuiHandler::init()
|
||||||
|
{
|
||||||
|
mainFPSmng->init();
|
||||||
|
isPointerRelativeMode = settings["general"]["userRelativePointer"].Bool();
|
||||||
|
pointerSpeedMultiplier = settings["general"]["relativePointerSpeedMultiplier"].Float();
|
||||||
|
}
|
||||||
|
|
||||||
void CGuiHandler::handleElementActivate(CIntObject * elem, ui16 activityFlag)
|
void CGuiHandler::handleElementActivate(CIntObject * elem, ui16 activityFlag)
|
||||||
{
|
{
|
||||||
processLists(activityFlag,[&](std::list<CIntObject*> * lst){
|
processLists(activityFlag,[&](std::list<CIntObject*> * lst){
|
||||||
@ -206,6 +213,78 @@ void CGuiHandler::handleEvents()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGuiHandler::convertTouchToMouse(SDL_Event * current)
|
||||||
|
{
|
||||||
|
int rLogicalWidth, rLogicalHeight;
|
||||||
|
|
||||||
|
SDL_RenderGetLogicalSize(mainRenderer, &rLogicalWidth, &rLogicalHeight);
|
||||||
|
|
||||||
|
int adjustedMouseY = (int)(current->tfinger.y * rLogicalHeight);
|
||||||
|
int adjustedMouseX = (int)(current->tfinger.x * rLogicalWidth);
|
||||||
|
|
||||||
|
current->button.x = adjustedMouseX;
|
||||||
|
current->motion.x = adjustedMouseX;
|
||||||
|
current->button.y = adjustedMouseY;
|
||||||
|
current->motion.y = adjustedMouseY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGuiHandler::fakeMoveCursor(float dx, float dy)
|
||||||
|
{
|
||||||
|
int x, y, w, h;
|
||||||
|
|
||||||
|
SDL_Event event;
|
||||||
|
SDL_MouseMotionEvent sme = {SDL_MOUSEMOTION, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
|
sme.state = SDL_GetMouseState(&x, &y);
|
||||||
|
SDL_GetWindowSize(mainWindow, &w, &h);
|
||||||
|
|
||||||
|
sme.x = CCS->curh->xpos + (int)(GH.pointerSpeedMultiplier * w * dx);
|
||||||
|
sme.y = CCS->curh->ypos + (int)(GH.pointerSpeedMultiplier * h * dy);
|
||||||
|
|
||||||
|
vstd::abetween(sme.x, 0, w);
|
||||||
|
vstd::abetween(sme.y, 0, h);
|
||||||
|
|
||||||
|
event.motion = sme;
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGuiHandler::fakeMouseMove()
|
||||||
|
{
|
||||||
|
fakeMoveCursor(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGuiHandler::fakeMouseButtonEventRelativeMode(bool down, bool right)
|
||||||
|
{
|
||||||
|
SDL_Event event;
|
||||||
|
SDL_MouseButtonEvent sme = {SDL_MOUSEBUTTONDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
|
if(!down)
|
||||||
|
{
|
||||||
|
sme.type = SDL_MOUSEBUTTONUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
sme.button = right ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT;
|
||||||
|
|
||||||
|
sme.x = CCS->curh->xpos;
|
||||||
|
sme.y = CCS->curh->ypos;
|
||||||
|
|
||||||
|
float xScale, yScale;
|
||||||
|
int w, h, rLogicalWidth, rLogicalHeight;
|
||||||
|
|
||||||
|
SDL_GetWindowSize(mainWindow, &w, &h);
|
||||||
|
SDL_RenderGetLogicalSize(mainRenderer, &rLogicalWidth, &rLogicalHeight);
|
||||||
|
SDL_RenderGetScale(mainRenderer, &xScale, &yScale);
|
||||||
|
|
||||||
|
SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
|
||||||
|
SDL_WarpMouse(
|
||||||
|
(int)(sme.x * xScale) + (w - rLogicalWidth * xScale) / 2,
|
||||||
|
(int)(sme.y * yScale + (h - rLogicalHeight * yScale) / 2));
|
||||||
|
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
|
||||||
|
|
||||||
|
event.button = sme;
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
}
|
||||||
|
|
||||||
void CGuiHandler::handleCurrentEvent()
|
void CGuiHandler::handleCurrentEvent()
|
||||||
{
|
{
|
||||||
if(current->type == SDL_KEYDOWN || current->type == SDL_KEYUP)
|
if(current->type == SDL_KEYDOWN || current->type == SDL_KEYUP)
|
||||||
@ -338,8 +417,9 @@ void CGuiHandler::handleCurrentEvent()
|
|||||||
it->textEdited(current->edit);
|
it->textEdited(current->edit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//todo: muiltitouch
|
|
||||||
else if(current->type == SDL_MOUSEBUTTONUP)
|
else if(current->type == SDL_MOUSEBUTTONUP)
|
||||||
|
{
|
||||||
|
if(!multifinger)
|
||||||
{
|
{
|
||||||
switch(current->button.button)
|
switch(current->button.button)
|
||||||
{
|
{
|
||||||
@ -354,6 +434,62 @@ void CGuiHandler::handleCurrentEvent()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if(current->type == SDL_FINGERMOTION)
|
||||||
|
{
|
||||||
|
if(isPointerRelativeMode)
|
||||||
|
{
|
||||||
|
fakeMoveCursor(current->tfinger.dx, current->tfinger.dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(current->type == SDL_FINGERDOWN)
|
||||||
|
{
|
||||||
|
auto fingerCount = SDL_GetNumTouchFingers(current->tfinger.touchId);
|
||||||
|
|
||||||
|
multifinger = fingerCount > 1;
|
||||||
|
|
||||||
|
if(isPointerRelativeMode)
|
||||||
|
{
|
||||||
|
if(current->tfinger.x > 0.5)
|
||||||
|
{
|
||||||
|
bool isRightClick = current->tfinger.y < 0.5;
|
||||||
|
|
||||||
|
fakeMouseButtonEventRelativeMode(true, isRightClick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifndef VCMI_IOS
|
||||||
|
else if(fingerCount == 2)
|
||||||
|
{
|
||||||
|
convertTouchToMouse(current);
|
||||||
|
handleMouseMotion();
|
||||||
|
handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, true);
|
||||||
|
}
|
||||||
|
#endif //VCMI_IOS
|
||||||
|
}
|
||||||
|
else if(current->type == SDL_FINGERUP)
|
||||||
|
{
|
||||||
|
auto fingerCount = SDL_GetNumTouchFingers(current->tfinger.touchId);
|
||||||
|
|
||||||
|
if(isPointerRelativeMode)
|
||||||
|
{
|
||||||
|
if(current->tfinger.x > 0.5)
|
||||||
|
{
|
||||||
|
bool isRightClick = current->tfinger.y < 0.5;
|
||||||
|
|
||||||
|
fakeMouseButtonEventRelativeMode(false, isRightClick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifndef VCMI_IOS
|
||||||
|
else if(multifinger)
|
||||||
|
{
|
||||||
|
convertTouchToMouse(current);
|
||||||
|
handleMouseMotion();
|
||||||
|
handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false);
|
||||||
|
multifinger = fingerCount != 0;
|
||||||
|
}
|
||||||
|
#endif //VCMI_IOS
|
||||||
|
}
|
||||||
|
|
||||||
current = nullptr;
|
current = nullptr;
|
||||||
} //event end
|
} //event end
|
||||||
|
|
||||||
@ -426,20 +562,6 @@ void CGuiHandler::handleMoveInterested(const SDL_MouseMotionEvent & motion)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGuiHandler::fakeMouseMove()
|
|
||||||
{
|
|
||||||
SDL_Event event;
|
|
||||||
SDL_MouseMotionEvent sme = {SDL_MOUSEMOTION, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
||||||
int x, y;
|
|
||||||
|
|
||||||
sme.state = SDL_GetMouseState(&x, &y);
|
|
||||||
sme.x = x;
|
|
||||||
sme.y = y;
|
|
||||||
|
|
||||||
event.motion = sme;
|
|
||||||
SDL_PushEvent(&event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CGuiHandler::renderFrame()
|
void CGuiHandler::renderFrame()
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -481,7 +603,8 @@ void CGuiHandler::renderFrame()
|
|||||||
|
|
||||||
|
|
||||||
CGuiHandler::CGuiHandler()
|
CGuiHandler::CGuiHandler()
|
||||||
: lastClick(-500, -500),lastClickTime(0), defActionsDef(0), captureChildren(false)
|
: lastClick(-500, -500),lastClickTime(0), defActionsDef(0), captureChildren(false),
|
||||||
|
multifinger(false)
|
||||||
{
|
{
|
||||||
continueEventHandling = true;
|
continueEventHandling = true;
|
||||||
curInt = nullptr;
|
curInt = nullptr;
|
||||||
|
@ -88,6 +88,10 @@ private:
|
|||||||
|
|
||||||
void handleMouseButtonClick(CIntObjectList & interestedObjs, EIntObjMouseBtnType btn, bool isPressed);
|
void handleMouseButtonClick(CIntObjectList & interestedObjs, EIntObjMouseBtnType btn, bool isPressed);
|
||||||
void processLists(const ui16 activityFlag, std::function<void (std::list<CIntObject*> *)> cb);
|
void processLists(const ui16 activityFlag, std::function<void (std::list<CIntObject*> *)> cb);
|
||||||
|
void convertTouchToMouse(SDL_Event * current);
|
||||||
|
void fakeMoveCursor(float dx, float dy);
|
||||||
|
void fakeMouseButtonEventRelativeMode(bool down, bool right);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void handleElementActivate(CIntObject * elem, ui16 activityFlag);
|
void handleElementActivate(CIntObject * elem, ui16 activityFlag);
|
||||||
void handleElementDeActivate(CIntObject * elem, ui16 activityFlag);
|
void handleElementDeActivate(CIntObject * elem, ui16 activityFlag);
|
||||||
@ -101,6 +105,9 @@ public:
|
|||||||
|
|
||||||
Point lastClick;
|
Point lastClick;
|
||||||
unsigned lastClickTime;
|
unsigned lastClickTime;
|
||||||
|
bool multifinger;
|
||||||
|
bool isPointerRelativeMode;
|
||||||
|
float pointerSpeedMultiplier;
|
||||||
|
|
||||||
ui8 defActionsDef; //default auto actions
|
ui8 defActionsDef; //default auto actions
|
||||||
bool captureChildren; //all newly created objects will get their parents from stack and will be added to parents children list
|
bool captureChildren; //all newly created objects will get their parents from stack and will be added to parents children list
|
||||||
@ -109,6 +116,7 @@ public:
|
|||||||
CGuiHandler();
|
CGuiHandler();
|
||||||
~CGuiHandler();
|
~CGuiHandler();
|
||||||
|
|
||||||
|
void init();
|
||||||
void renderFrame();
|
void renderFrame();
|
||||||
|
|
||||||
void totalRedraw(); //forces total redraw (using showAll), sets a flag, method gets called at the end of the rendering
|
void totalRedraw(); //forces total redraw (using showAll), sets a flag, method gets called at the end of the rendering
|
||||||
|
@ -863,20 +863,10 @@ SDL_Color CSDL_Ext::makeColor(ui8 r, ui8 g, ui8 b, ui8 a)
|
|||||||
|
|
||||||
void CSDL_Ext::startTextInput(SDL_Rect * where)
|
void CSDL_Ext::startTextInput(SDL_Rect * where)
|
||||||
{
|
{
|
||||||
auto impl = [](SDL_Rect * where)
|
|
||||||
{
|
|
||||||
if (SDL_IsTextInputActive() == SDL_FALSE)
|
|
||||||
{
|
|
||||||
SDL_StartTextInput();
|
|
||||||
}
|
|
||||||
SDL_SetTextInputRect(where);
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef VCMI_APPLE
|
#ifdef VCMI_APPLE
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef VCMI_IOS
|
|
||||||
// TODO ios: looks like SDL bug actually, try fixing there
|
// TODO ios: looks like SDL bug actually, try fixing there
|
||||||
auto renderer = SDL_GetRenderer(mainWindow);
|
auto renderer = SDL_GetRenderer(mainWindow);
|
||||||
float scaleX, scaleY;
|
float scaleX, scaleY;
|
||||||
@ -884,17 +874,26 @@ void CSDL_Ext::startTextInput(SDL_Rect * where)
|
|||||||
SDL_RenderGetScale(renderer, &scaleX, &scaleY);
|
SDL_RenderGetScale(renderer, &scaleX, &scaleY);
|
||||||
SDL_RenderGetViewport(renderer, &viewport);
|
SDL_RenderGetViewport(renderer, &viewport);
|
||||||
|
|
||||||
|
#ifdef VCMI_IOS
|
||||||
const auto nativeScale = iOS_utils::screenScale();
|
const auto nativeScale = iOS_utils::screenScale();
|
||||||
auto rectInScreenCoordinates = *where;
|
|
||||||
rectInScreenCoordinates.x = (viewport.x + rectInScreenCoordinates.x) * scaleX / nativeScale;
|
scaleX /= nativeScale;
|
||||||
rectInScreenCoordinates.y = (viewport.y + rectInScreenCoordinates.y) * scaleY / nativeScale;
|
scaleY /= nativeScale;
|
||||||
rectInScreenCoordinates.w = rectInScreenCoordinates.w * scaleX / nativeScale;
|
|
||||||
rectInScreenCoordinates.h = rectInScreenCoordinates.h * scaleY / nativeScale;
|
|
||||||
impl(&rectInScreenCoordinates);
|
|
||||||
#else
|
|
||||||
impl(where);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
auto rectInScreenCoordinates = *where;
|
||||||
|
rectInScreenCoordinates.x = (viewport.x + rectInScreenCoordinates.x) * scaleX;
|
||||||
|
rectInScreenCoordinates.y = (viewport.y + rectInScreenCoordinates.y) * scaleY;
|
||||||
|
rectInScreenCoordinates.w = rectInScreenCoordinates.w * scaleX;
|
||||||
|
rectInScreenCoordinates.h = rectInScreenCoordinates.h * scaleY;
|
||||||
|
|
||||||
|
SDL_SetTextInputRect(&rectInScreenCoordinates);
|
||||||
|
|
||||||
|
if (SDL_IsTextInputActive() == SDL_FALSE)
|
||||||
|
{
|
||||||
|
SDL_StartTextInput();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef VCMI_APPLE
|
#ifdef VCMI_APPLE
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
@ -10,11 +10,13 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
#include <SDL_events.h>
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@interface GameChatKeyboardHandler : NSObject
|
@interface GameChatKeyboardHandler : NSObject
|
||||||
|
|
||||||
- (void)triggerInput;
|
+ (void)sendKeyEventWithKeyCode:(SDL_KeyCode)keyCode;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -10,20 +10,8 @@
|
|||||||
|
|
||||||
#import "GameChatKeyboardHandler.h"
|
#import "GameChatKeyboardHandler.h"
|
||||||
|
|
||||||
#include <SDL_events.h>
|
|
||||||
|
|
||||||
static int watchReturnKey(void * userdata, SDL_Event * event);
|
static int watchReturnKey(void * userdata, SDL_Event * event);
|
||||||
|
|
||||||
static void sendKeyEvent(SDL_KeyCode keyCode)
|
|
||||||
{
|
|
||||||
SDL_Event keyEvent;
|
|
||||||
keyEvent.key = (SDL_KeyboardEvent){
|
|
||||||
.type = SDL_KEYDOWN,
|
|
||||||
.keysym.sym = keyCode,
|
|
||||||
};
|
|
||||||
SDL_PushEvent(&keyEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@interface GameChatKeyboardHandler ()
|
@interface GameChatKeyboardHandler ()
|
||||||
@property (nonatomic) BOOL wasChatMessageSent;
|
@property (nonatomic) BOOL wasChatMessageSent;
|
||||||
@ -31,28 +19,40 @@ static void sendKeyEvent(SDL_KeyCode keyCode)
|
|||||||
|
|
||||||
@implementation GameChatKeyboardHandler
|
@implementation GameChatKeyboardHandler
|
||||||
|
|
||||||
- (void)triggerInput {
|
+ (void)sendKeyEventWithKeyCode:(SDL_KeyCode)keyCode
|
||||||
|
{
|
||||||
|
SDL_Event keyEvent;
|
||||||
|
keyEvent.key = (SDL_KeyboardEvent){
|
||||||
|
.type = SDL_KEYDOWN,
|
||||||
|
.state = SDL_PRESSED,
|
||||||
|
.keysym.sym = keyCode,
|
||||||
|
};
|
||||||
|
SDL_PushEvent(&keyEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)init {
|
||||||
|
self = [super init];
|
||||||
|
|
||||||
__auto_type notificationCenter = NSNotificationCenter.defaultCenter;
|
__auto_type notificationCenter = NSNotificationCenter.defaultCenter;
|
||||||
[notificationCenter addObserver:self selector:@selector(textDidBeginEditing:) name:UITextFieldTextDidBeginEditingNotification object:nil];
|
[notificationCenter addObserver:self selector:@selector(textDidBeginEditing:) name:UITextFieldTextDidBeginEditingNotification object:nil];
|
||||||
[notificationCenter addObserver:self selector:@selector(textDidEndEditing:) name:UITextFieldTextDidEndEditingNotification object:nil];
|
[notificationCenter addObserver:self selector:@selector(textDidEndEditing:) name:UITextFieldTextDidEndEditingNotification object:nil];
|
||||||
|
|
||||||
self.wasChatMessageSent = NO;
|
return self;
|
||||||
sendKeyEvent(SDLK_TAB);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Notifications
|
#pragma mark - Notifications
|
||||||
|
|
||||||
- (void)textDidBeginEditing:(NSNotification *)n {
|
- (void)textDidBeginEditing:(NSNotification *)n {
|
||||||
|
self.wasChatMessageSent = NO;
|
||||||
|
|
||||||
// watch for pressing Return to ignore sending Escape key after keyboard is closed
|
// watch for pressing Return to ignore sending Escape key after keyboard is closed
|
||||||
SDL_AddEventWatch(watchReturnKey, (__bridge void *)self);
|
SDL_AddEventWatch(watchReturnKey, (__bridge void *)self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)textDidEndEditing:(NSNotification *)n {
|
- (void)textDidEndEditing:(NSNotification *)n {
|
||||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
|
||||||
|
|
||||||
// discard chat message
|
// discard chat message
|
||||||
if(!self.wasChatMessageSent)
|
if(!self.wasChatMessageSent)
|
||||||
sendKeyEvent(SDLK_ESCAPE);
|
[[self class] sendKeyEventWithKeyCode:SDLK_ESCAPE];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -95,7 +95,7 @@
|
|||||||
- (void)handlePinch:(UIGestureRecognizer *)gesture {
|
- (void)handlePinch:(UIGestureRecognizer *)gesture {
|
||||||
if(gesture.state != UIGestureRecognizerStateBegan || CSH->state != EClientState::GAMEPLAY)
|
if(gesture.state != UIGestureRecognizerStateBegan || CSH->state != EClientState::GAMEPLAY)
|
||||||
return;
|
return;
|
||||||
[self.gameChatHandler triggerInput];
|
[GameChatKeyboardHandler sendKeyEventWithKeyCode:SDLK_SPACE];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - UIGestureRecognizerDelegate
|
#pragma mark - UIGestureRecognizerDelegate
|
||||||
|
@ -236,7 +236,11 @@ std::shared_ptr<CButton> CMenuEntry::createButton(CMenuScreen * parent, const Js
|
|||||||
if(posy < 0)
|
if(posy < 0)
|
||||||
posy = pos.h + posy;
|
posy = pos.h + posy;
|
||||||
|
|
||||||
return std::make_shared<CButton>(Point(posx, posy), button["name"].String(), help, command, (int)button["hotkey"].Float());
|
auto result = std::make_shared<CButton>(Point(posx, posy), button["name"].String(), help, command, (int)button["hotkey"].Float());
|
||||||
|
|
||||||
|
if (button["center"].Bool())
|
||||||
|
result->moveBy(Point(-result->pos.w/2, -result->pos.h/2));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
CMenuEntry::CMenuEntry(CMenuScreen * parent, const JsonNode & config)
|
CMenuEntry::CMenuEntry(CMenuScreen * parent, const JsonNode & config)
|
||||||
|
@ -488,9 +488,6 @@ CKeyboardFocusListener::CKeyboardFocusListener(CTextInput * textInput)
|
|||||||
void CKeyboardFocusListener::focusGot()
|
void CKeyboardFocusListener::focusGot()
|
||||||
{
|
{
|
||||||
CSDL_Ext::startTextInput(&textInput->pos);
|
CSDL_Ext::startTextInput(&textInput->pos);
|
||||||
#ifdef VCMI_ANDROID
|
|
||||||
textInput->notifyAndroidTextInputChanged(textInput->text);
|
|
||||||
#endif
|
|
||||||
usageIndex++;
|
usageIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,9 +549,6 @@ void CTextInput::keyPressed(const SDL_KeyboardEvent & key)
|
|||||||
{
|
{
|
||||||
redraw();
|
redraw();
|
||||||
cb(text);
|
cb(text);
|
||||||
#ifdef VCMI_ANDROID
|
|
||||||
notifyAndroidTextInputChanged(text);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -563,10 +557,6 @@ void CTextInput::setText(const std::string & nText, bool callCb)
|
|||||||
CLabel::setText(nText);
|
CLabel::setText(nText);
|
||||||
if(callCb)
|
if(callCb)
|
||||||
cb(text);
|
cb(text);
|
||||||
|
|
||||||
#ifdef VCMI_ANDROID
|
|
||||||
notifyAndroidTextInputChanged(text);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CTextInput::captureThisEvent(const SDL_KeyboardEvent & key)
|
bool CTextInput::captureThisEvent(const SDL_KeyboardEvent & key)
|
||||||
@ -592,10 +582,6 @@ void CTextInput::textInputed(const SDL_TextInputEvent & event)
|
|||||||
cb(text);
|
cb(text);
|
||||||
}
|
}
|
||||||
newText.clear();
|
newText.clear();
|
||||||
|
|
||||||
#ifdef VCMI_ANDROID
|
|
||||||
notifyAndroidTextInputChanged(text);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTextInput::textEdited(const SDL_TextEditingEvent & event)
|
void CTextInput::textEdited(const SDL_TextEditingEvent & event)
|
||||||
@ -606,11 +592,6 @@ void CTextInput::textEdited(const SDL_TextEditingEvent & event)
|
|||||||
newText = event.text;
|
newText = event.text;
|
||||||
redraw();
|
redraw();
|
||||||
cb(text + newText);
|
cb(text + newText);
|
||||||
|
|
||||||
#ifdef VCMI_ANDROID
|
|
||||||
auto editedText = text + newText;
|
|
||||||
notifyAndroidTextInputChanged(editedText);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTextInput::filenameFilter(std::string & text, const std::string &)
|
void CTextInput::filenameFilter(std::string & text, const std::string &)
|
||||||
@ -657,24 +638,6 @@ void CTextInput::numberFilter(std::string & text, const std::string & oldText, i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VCMI_ANDROID
|
|
||||||
void CTextInput::notifyAndroidTextInputChanged(std::string & text)
|
|
||||||
{
|
|
||||||
if(!focus)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto fun = [&text](JNIEnv * env, jclass cls, jmethodID method)
|
|
||||||
{
|
|
||||||
auto jtext = env->NewStringUTF(text.c_str());
|
|
||||||
env->CallStaticVoidMethod(cls, method, jtext);
|
|
||||||
env->DeleteLocalRef(jtext);
|
|
||||||
};
|
|
||||||
CAndroidVMHelper vmHelper;
|
|
||||||
vmHelper.callCustomMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "notifyTextInputChanged",
|
|
||||||
"(Ljava/lang/String;)V", fun, true);
|
|
||||||
}
|
|
||||||
#endif //VCMI_ANDROID
|
|
||||||
|
|
||||||
CFocusable::CFocusable()
|
CFocusable::CFocusable()
|
||||||
:CFocusable(std::make_shared<IFocusListener>())
|
:CFocusable(std::make_shared<IFocusListener>())
|
||||||
{
|
{
|
||||||
|
@ -198,9 +198,6 @@ class CTextInput : public CLabel, public CFocusable
|
|||||||
protected:
|
protected:
|
||||||
std::string visibleText() override;
|
std::string visibleText() override;
|
||||||
|
|
||||||
#ifdef VCMI_ANDROID
|
|
||||||
void notifyAndroidTextInputChanged(std::string & text);
|
|
||||||
#endif
|
|
||||||
public:
|
public:
|
||||||
CFunctionList<void(const std::string &)> cb;
|
CFunctionList<void(const std::string &)> cb;
|
||||||
CFunctionList<void(std::string &, const std::string &)> filters;
|
CFunctionList<void(std::string &, const std::string &)> filters;
|
||||||
|
@ -180,7 +180,7 @@ void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent)
|
|||||||
void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent)
|
void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent)
|
||||||
{
|
{
|
||||||
#if defined(VCMI_ANDROID) || defined(VCMI_IOS)
|
#if defined(VCMI_ANDROID) || defined(VCMI_IOS)
|
||||||
if(sEvent.state == 0) // any "button" is enough on mobile
|
if(sEvent.state == 0 || GH.multifinger) // any "button" is enough on mobile
|
||||||
#else
|
#else
|
||||||
if((sEvent.state & SDL_BUTTON_MMASK) == 0) // swipe only works with middle mouse on other platforms
|
if((sEvent.state & SDL_BUTTON_MMASK) == 0) // swipe only works with middle mouse on other platforms
|
||||||
#endif
|
#endif
|
||||||
@ -1044,7 +1044,7 @@ void CAdvMapInt::show(SDL_Surface * to)
|
|||||||
{
|
{
|
||||||
++heroAnim;
|
++heroAnim;
|
||||||
}
|
}
|
||||||
if(animValHitCount == 8)
|
if(animValHitCount >= 8)
|
||||||
{
|
{
|
||||||
CGI->mh->updateWater();
|
CGI->mh->updateWater();
|
||||||
animValHitCount = 0;
|
animValHitCount = 0;
|
||||||
|
@ -101,7 +101,7 @@ void QuickRecruitmentWindow::maxAllCards(std::vector<std::shared_ptr<CreaturePur
|
|||||||
|
|
||||||
void QuickRecruitmentWindow::purchaseUnits()
|
void QuickRecruitmentWindow::purchaseUnits()
|
||||||
{
|
{
|
||||||
for(auto selected : cards)
|
for(auto selected : boost::adaptors::reverse(cards))
|
||||||
{
|
{
|
||||||
if(selected->slider->getValue())
|
if(selected->slider->getValue())
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ class VCMI(ConanFile):
|
|||||||
"minizip/[~1.2.12]",
|
"minizip/[~1.2.12]",
|
||||||
"onetbb/[^2021.3]", # Nullkiller AI
|
"onetbb/[^2021.3]", # Nullkiller AI
|
||||||
"qt/[~5.15.2]", # launcher
|
"qt/[~5.15.2]", # launcher
|
||||||
"sdl/[~2.24.0]",
|
"sdl/[~2.26.1 || >=2.0.20 <=2.22.0]", # versions in between have broken sound
|
||||||
"sdl_image/[~2.0.5]",
|
"sdl_image/[~2.0.5]",
|
||||||
"sdl_mixer/[~2.0.4]",
|
"sdl_mixer/[~2.0.4]",
|
||||||
"sdl_ttf/[~2.0.18]",
|
"sdl_ttf/[~2.0.18]",
|
||||||
|
@ -11,12 +11,16 @@
|
|||||||
[
|
[
|
||||||
{"type" : "lod", "path" : "Data/H3ab_bmp.lod"},
|
{"type" : "lod", "path" : "Data/H3ab_bmp.lod"},
|
||||||
{"type" : "lod", "path" : "Data/H3bitmap.lod"},
|
{"type" : "lod", "path" : "Data/H3bitmap.lod"},
|
||||||
|
{"type" : "lod", "path" : "Data/h3abp_bm.lod"}, // Polish version of H3 only
|
||||||
|
{"type" : "lod", "path" : "Data/H3pbitma.lod"}, // Polish version of H3 only
|
||||||
{"type" : "dir", "path" : "Data"}
|
{"type" : "dir", "path" : "Data"}
|
||||||
],
|
],
|
||||||
"SPRITES/":
|
"SPRITES/":
|
||||||
[
|
[
|
||||||
{"type" : "lod", "path" : "Data/H3ab_spr.lod"},
|
{"type" : "lod", "path" : "Data/H3ab_spr.lod"},
|
||||||
{"type" : "lod", "path" : "Data/H3sprite.lod"},
|
{"type" : "lod", "path" : "Data/H3sprite.lod"},
|
||||||
|
{"type" : "lod", "path" : "Data/h3abp_sp.lod"}, // Polish version of H3 only
|
||||||
|
{"type" : "lod", "path" : "Data/H3psprit.lod"}, // Polish version of H3 only
|
||||||
{"type" : "dir", "path" : "Sprites"}
|
{"type" : "dir", "path" : "Sprites"}
|
||||||
],
|
],
|
||||||
"SOUNDS/":
|
"SOUNDS/":
|
||||||
|
@ -10,29 +10,29 @@
|
|||||||
"background" : "gamselbk",
|
"background" : "gamselbk",
|
||||||
//"scalable" : true, //background will be scaled to screen size
|
//"scalable" : true, //background will be scaled to screen size
|
||||||
//"video" : {"x": 8, "y": 105, "name":"CREDITS.SMK" },//Floating WoG logo. Disabled due to different position in various versions of H3.
|
//"video" : {"x": 8, "y": 105, "name":"CREDITS.SMK" },//Floating WoG logo. Disabled due to different position in various versions of H3.
|
||||||
//"images" : [],//Optioal, contains any additional images in the same format as video
|
//"images" : [],//Optional, contains any additional images in the same format as video
|
||||||
"items" :
|
"items" :
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name" : "main",
|
"name" : "main",
|
||||||
"buttons":
|
"buttons":
|
||||||
[
|
[
|
||||||
{"x": 540, "y": 10, "name":"MMENUNG", "hotkey" : 110, "help": 3, "command": "to new"},
|
{"x": 644, "y": 70, "center" : true, "name":"MMENUNG", "hotkey" : 110, "help": 3, "command": "to new"},
|
||||||
{"x": 532, "y": 132, "name":"MMENULG", "hotkey" : 108, "help": 4, "command": "to load"},
|
{"x": 645, "y": 192, "center" : true, "name":"MMENULG", "hotkey" : 108, "help": 4, "command": "to load"},
|
||||||
{"x": 524, "y": 251, "name":"MMENUHS", "hotkey" : 104, "help": 5, "command": "highscores"},
|
{"x": 643, "y": 296, "center" : true, "name":"MMENUHS", "hotkey" : 104, "help": 5, "command": "highscores"},
|
||||||
{"x": 557, "y": 359, "name":"MMENUCR", "hotkey" : 99, "help": 6, "command": "to credits"},
|
{"x": 643, "y": 414, "center" : true, "name":"MMENUCR", "hotkey" : 99, "help": 6, "command": "to credits"},
|
||||||
{"x": 586, "y": 468, "name":"MMENUQT", "hotkey" : 27, "help": 7, "command": "exit"}
|
{"x": 643, "y": 520, "center" : true, "name":"MMENUQT", "hotkey" : 27, "help": 7, "command": "exit"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name" : "new",
|
"name" : "new",
|
||||||
"buttons":
|
"buttons":
|
||||||
[
|
[
|
||||||
{"x": 545, "y": 4, "name":"GTSINGL", "hotkey" : 115, "help": 10, "command": "start single"},
|
{"x": 649, "y": 65, "center" : true, "name":"GTSINGL", "hotkey" : 115, "help": 10, "command": "start single"},
|
||||||
{"x": 568, "y": 120, "name":"GTMULTI", "hotkey" : 109, "help": 12, "command": "start multi"},
|
{"x": 649, "y": 180, "center" : true, "name":"GTMULTI", "hotkey" : 109, "help": 12, "command": "start multi"},
|
||||||
{"x": 541, "y": 233, "name":"GTCAMPN", "hotkey" : 99, "help": 11, "command": "to campaign"},
|
{"x": 646, "y": 298, "center" : true, "name":"GTCAMPN", "hotkey" : 99, "help": 11, "command": "to campaign"},
|
||||||
{"x": 545, "y": 358, "name":"GTTUTOR", "hotkey" : 116, "help": 13, "command": "start tutorial"},
|
{"x": 647, "y": 412, "center" : true, "name":"GTTUTOR", "hotkey" : 116, "help": 13, "command": "start tutorial"},
|
||||||
{"x": 582, "y": 464, "name":"GTBACK", "hotkey" : 27, "help": 14, "command": "to main"}
|
{"x": 645, "y": 517, "center" : true, "name":"GTBACK", "hotkey" : 27, "help": 14, "command": "to main"}
|
||||||
],
|
],
|
||||||
"images": [ {"x": 114, "y": 312, "name":"NEWGAME"} ]
|
"images": [ {"x": 114, "y": 312, "name":"NEWGAME"} ]
|
||||||
},
|
},
|
||||||
@ -40,11 +40,11 @@
|
|||||||
"name" : "load",
|
"name" : "load",
|
||||||
"buttons":
|
"buttons":
|
||||||
[
|
[
|
||||||
{"x": 545, "y": 8, "name":"GTSINGL", "hotkey" : 115, "help": 10, "command": "load single"},
|
{"x": 649, "y": 65, "center" : true, "name":"GTSINGL", "hotkey" : 115, "help": 10, "command": "load single"},
|
||||||
{"x": 568, "y": 120, "name":"GTMULTI", "hotkey" : 109, "help": 12, "command": "load multi"},
|
{"x": 649, "y": 180, "center" : true, "name":"GTMULTI", "hotkey" : 109, "help": 12, "command": "load multi"},
|
||||||
{"x": 541, "y": 233, "name":"GTCAMPN", "hotkey" : 99, "help": 11, "command": "load campaign"},
|
{"x": 646, "y": 298, "center" : true, "name":"GTCAMPN", "hotkey" : 99, "help": 11, "command": "load campaign"},
|
||||||
{"x": 545, "y": 358, "name":"GTTUTOR", "hotkey" : 116, "help": 13, "command": "load tutorial"},
|
{"x": 647, "y": 412, "center" : true, "name":"GTTUTOR", "hotkey" : 116, "help": 13, "command": "load tutorial"},
|
||||||
{"x": 582, "y": 464, "name":"GTBACK", "hotkey" : 27, "help": 14, "command": "to main"}
|
{"x": 645, "y": 517, "center" : true, "name":"GTBACK", "hotkey" : 27, "help": 14, "command": "to main"}
|
||||||
],
|
],
|
||||||
"images": [ {"x": 114, "y": 312, "name":"LOADGAME"} ]
|
"images": [ {"x": 114, "y": 312, "name":"LOADGAME"} ]
|
||||||
},
|
},
|
||||||
@ -52,11 +52,11 @@
|
|||||||
"name" : "campaign",
|
"name" : "campaign",
|
||||||
"buttons":
|
"buttons":
|
||||||
[
|
[
|
||||||
{"x": 535, "y": 4, "name":"CSSSOD", "hotkey" : 119, "command": "campaigns sod"},
|
{"x": 634, "y": 67, "center" : true, "name":"CSSSOD", "hotkey" : 119, "command": "campaigns sod"},
|
||||||
{"x": 494, "y": 117, "name":"CSSROE", "hotkey" : 114, "command": "campaigns roe"},
|
{"x": 637, "y": 181, "center" : true, "name":"CSSROE", "hotkey" : 114, "command": "campaigns roe"},
|
||||||
{"x": 486, "y": 241, "name":"CSSARM", "hotkey" : 97, "command": "campaigns ab"},
|
{"x": 638, "y": 301, "center" : true, "name":"CSSARM", "hotkey" : 97, "command": "campaigns ab"},
|
||||||
{"x": 550, "y": 358, "name":"CSSCUS", "hotkey" : 99, "command": "start campaign"},
|
{"x": 638, "y": 413, "center" : true, "name":"CSSCUS", "hotkey" : 99, "command": "start campaign"},
|
||||||
{"x": 582, "y": 464, "name":"GTBACK", "hotkey" : 27, "command": "to new"}
|
{"x": 639, "y": 518, "center" : true, "name":"CSSEXIT", "hotkey" : 27, "command": "to new"}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -17,7 +17,20 @@
|
|||||||
"type" : "object",
|
"type" : "object",
|
||||||
"default": {},
|
"default": {},
|
||||||
"additionalProperties" : false,
|
"additionalProperties" : false,
|
||||||
"required" : [ "playerName", "showfps", "music", "sound", "encoding", "swipe", "saveRandomMaps", "saveFrequency", "notifications", "extraDump" ],
|
"required" : [
|
||||||
|
"playerName",
|
||||||
|
"showfps",
|
||||||
|
"music",
|
||||||
|
"sound",
|
||||||
|
"encoding",
|
||||||
|
"swipe",
|
||||||
|
"saveRandomMaps",
|
||||||
|
"saveFrequency",
|
||||||
|
"notifications",
|
||||||
|
"extraDump",
|
||||||
|
"userRelativePointer",
|
||||||
|
"relativePointerSpeedMultiplier"
|
||||||
|
],
|
||||||
"properties" : {
|
"properties" : {
|
||||||
"playerName" : {
|
"playerName" : {
|
||||||
"type":"string",
|
"type":"string",
|
||||||
@ -70,6 +83,14 @@
|
|||||||
"extraDump" : {
|
"extraDump" : {
|
||||||
"type" : "boolean",
|
"type" : "boolean",
|
||||||
"default" : false
|
"default" : false
|
||||||
|
},
|
||||||
|
"userRelativePointer" : {
|
||||||
|
"type" : "boolean",
|
||||||
|
"default" : false
|
||||||
|
},
|
||||||
|
"relativePointerSpeedMultiplier" : {
|
||||||
|
"type" : "number",
|
||||||
|
"default" : 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
"rockTerrain":
|
"rockTerrain":
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The name of tock type terrain which will be used as borders in the underground"
|
"description": "The name of rock type terrain which will be used as borders in the underground"
|
||||||
},
|
},
|
||||||
"river":
|
"river":
|
||||||
{
|
{
|
||||||
|
6
debian/changelog
vendored
6
debian/changelog
vendored
@ -1,3 +1,9 @@
|
|||||||
|
vcmi (1.1.1) jammy; urgency=medium
|
||||||
|
|
||||||
|
* New upstream release
|
||||||
|
|
||||||
|
-- Ivan Savenko <saven.ivan@gmail.com> Fri, 03 Feb 2023 12:00:00 +0200
|
||||||
|
|
||||||
vcmi (1.1.0) jammy; urgency=medium
|
vcmi (1.1.0) jammy; urgency=medium
|
||||||
|
|
||||||
* New upstream release
|
* New upstream release
|
||||||
|
1
debian/rules
vendored
1
debian/rules
vendored
@ -8,6 +8,7 @@ override_dh_auto_configure:
|
|||||||
dh_auto_configure -- \
|
dh_auto_configure -- \
|
||||||
-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON \
|
-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON \
|
||||||
-DCMAKE_INSTALL_RPATH=/usr/lib/$(DEB_HOST_MULTIARCH)/vcmi \
|
-DCMAKE_INSTALL_RPATH=/usr/lib/$(DEB_HOST_MULTIARCH)/vcmi \
|
||||||
|
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||||
-DBIN_DIR=games \
|
-DBIN_DIR=games \
|
||||||
-DFORCE_BUNDLED_FL=OFF \
|
-DFORCE_BUNDLED_FL=OFF \
|
||||||
-DENABLE_TEST=0
|
-DENABLE_TEST=0
|
||||||
|
@ -20,8 +20,8 @@ The following platforms are supported and known to work, others might require ch
|
|||||||
|
|
||||||
1. Check if your build environment can use the prebuilt binaries: basically, that your compiler version (or Xcode major version) matches the information below. If you're unsure, simply advance to the next step.
|
1. Check if your build environment can use the prebuilt binaries: basically, that your compiler version (or Xcode major version) matches the information below. If you're unsure, simply advance to the next step.
|
||||||
|
|
||||||
- macOS: libraries are built with Apple clang 13 (Xcode 13.4.1), should be consumable by Xcode and Xcode CLT 13.x
|
- macOS: libraries are built with Apple clang 14 (Xcode 14.2), should be consumable by Xcode and Xcode CLT 14.x (older library versions are also available for Xcode 13, see Releases in the respective repo)
|
||||||
- iOS: libraries are built with Apple clang 13 (Xcode 13.4.1), should be consumable by Xcode 13.x
|
- iOS: libraries are built with Apple clang 14 (Xcode 14.2), should be consumable by Xcode 14.x (older library versions are also available for Xcode 13, see Releases in the respective repo)
|
||||||
|
|
||||||
2. Download the binaries archive and unpack it to `~/.conan` directory:
|
2. Download the binaries archive and unpack it to `~/.conan` directory:
|
||||||
|
|
||||||
@ -85,7 +85,8 @@ conan install . \
|
|||||||
--no-imports \
|
--no-imports \
|
||||||
--build=never \
|
--build=never \
|
||||||
--profile:build=default \
|
--profile:build=default \
|
||||||
--profile:host=CI/conan/macos-intel
|
--profile:host=CI/conan/macos-intel \
|
||||||
|
-o with_apple_system_libs=True
|
||||||
|
|
||||||
cmake -S . -B build -G Xcode \
|
cmake -S . -B build -G Xcode \
|
||||||
--toolchain conan-generated/conan_toolchain.cmake
|
--toolchain conan-generated/conan_toolchain.cmake
|
||||||
@ -116,7 +117,8 @@ conan install . \
|
|||||||
--no-imports \
|
--no-imports \
|
||||||
--build=never \
|
--build=never \
|
||||||
--profile:build=default \
|
--profile:build=default \
|
||||||
--profile:host=CI/conan/ios-arm64
|
--profile:host=CI/conan/ios-arm64 \
|
||||||
|
-o with_apple_system_libs=True
|
||||||
|
|
||||||
cmake --preset ios-conan
|
cmake --preset ios-conan
|
||||||
```
|
```
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
generatedZip="$1"
|
|
||||||
if [[ -z "$generatedZip" ]]; then
|
|
||||||
echo 'generated zip not provided as param'
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
mv "$generatedZip" "$(basename "$generatedZip" .zip).ipa"
|
|
@ -128,6 +128,11 @@ enable_pch(vcmilauncher)
|
|||||||
if(APPLE_IOS)
|
if(APPLE_IOS)
|
||||||
set(ICONS_DESTINATION ${DATA_DIR})
|
set(ICONS_DESTINATION ${DATA_DIR})
|
||||||
|
|
||||||
|
# TODO: remove after fixing Conan's Qt recipe
|
||||||
|
if(XCODE_VERSION VERSION_GREATER_EQUAL 14.0)
|
||||||
|
target_link_libraries(vcmilauncher "-framework IOKit")
|
||||||
|
endif()
|
||||||
|
|
||||||
# workaround https://github.com/conan-io/conan-center-index/issues/13332
|
# workaround https://github.com/conan-io/conan-center-index/issues/13332
|
||||||
if(USING_CONAN)
|
if(USING_CONAN)
|
||||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/QIOSIntegrationPlugin.h
|
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/QIOSIntegrationPlugin.h
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
<url type="bugtracker">https://github.com/vcmi/vcmi/issues</url>
|
<url type="bugtracker">https://github.com/vcmi/vcmi/issues</url>
|
||||||
<url type="faq">https://vcmi.eu/faq/</url>
|
<url type="faq">https://vcmi.eu/faq/</url>
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="1.1.1" date="2023-02-03" />
|
||||||
<release version="1.1.0" date="2022-12-23" />
|
<release version="1.1.0" date="2022-12-23" />
|
||||||
<release version="1.0.0" date="2022-09-11" />
|
<release version="1.0.0" date="2022-09-11" />
|
||||||
<release version="0.99" date="2016-11-01" />
|
<release version="0.99" date="2016-11-01" />
|
||||||
|
@ -124,7 +124,7 @@ bool CModEntry::isCompatible() const
|
|||||||
|
|
||||||
bool CModEntry::isEssential() const
|
bool CModEntry::isEssential() const
|
||||||
{
|
{
|
||||||
return getValue("storedLocaly").toBool();
|
return getName() == "vcmi";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CModEntry::isInstalled() const
|
bool CModEntry::isInstalled() const
|
||||||
|
@ -21,11 +21,6 @@ void CAndroidVMHelper::cacheVM(JNIEnv * env)
|
|||||||
env->GetJavaVM(&vmCache);
|
env->GetJavaVM(&vmCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAndroidVMHelper::cacheVM(JavaVM * vm)
|
|
||||||
{
|
|
||||||
vmCache = vm;
|
|
||||||
}
|
|
||||||
|
|
||||||
CAndroidVMHelper::CAndroidVMHelper()
|
CAndroidVMHelper::CAndroidVMHelper()
|
||||||
{
|
{
|
||||||
auto res = vmCache->GetEnv((void **) &envPtr, JNI_VERSION_1_1);
|
auto res = vmCache->GetEnv((void **) &envPtr, JNI_VERSION_1_1);
|
||||||
@ -101,7 +96,7 @@ jclass CAndroidVMHelper::findClass(const std::string & name, bool classloaded)
|
|||||||
return get()->FindClass(name.c_str());
|
return get()->FindClass(name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_initClassloader(JNIEnv * baseEnv, jobject * cls)
|
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_initClassloader(JNIEnv * baseEnv, jclass cls)
|
||||||
{
|
{
|
||||||
CAndroidVMHelper::cacheVM(baseEnv);
|
CAndroidVMHelper::cacheVM(baseEnv);
|
||||||
CAndroidVMHelper envHelper;
|
CAndroidVMHelper envHelper;
|
||||||
|
@ -42,8 +42,6 @@ public:
|
|||||||
|
|
||||||
static void cacheVM(JNIEnv * env);
|
static void cacheVM(JNIEnv * env);
|
||||||
|
|
||||||
static void cacheVM(JavaVM * vm);
|
|
||||||
|
|
||||||
static constexpr const char * NATIVE_METHODS_DEFAULT_CLASS = "eu/vcmi/vcmi/NativeMethods";
|
static constexpr const char * NATIVE_METHODS_DEFAULT_CLASS = "eu/vcmi/vcmi/NativeMethods";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1576,7 +1576,7 @@ bool NBonus::hasOfType(const CBonusSystemNode *obj, Bonus::BonusType type, int s
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Bonus::Description() const
|
std::string Bonus::Description(boost::optional<si32> customValue) const
|
||||||
{
|
{
|
||||||
std::ostringstream str;
|
std::ostringstream str;
|
||||||
|
|
||||||
@ -1615,8 +1615,8 @@ std::string Bonus::Description() const
|
|||||||
str << description;
|
str << description;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(val != 0)
|
if(auto value = customValue.value_or(val))
|
||||||
str << " " << std::showpos << val;
|
str << " " << std::showpos << value;
|
||||||
|
|
||||||
return str.str();
|
return str.str();
|
||||||
}
|
}
|
||||||
|
@ -510,7 +510,7 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
|
|||||||
return (high << 16) + low;
|
return (high << 16) + low;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Description() const;
|
std::string Description(boost::optional<si32> customValue = {}) const;
|
||||||
JsonNode toJsonNode() const;
|
JsonNode toJsonNode() const;
|
||||||
std::string nameForBonus() const; // generate suitable name for bonus - e.g. for storing in json struct
|
std::string nameForBonus() const; // generate suitable name for bonus - e.g. for storing in json struct
|
||||||
|
|
||||||
|
@ -153,11 +153,11 @@ void CArchiveLoader::initSNDArchive(const std::string &mountPoint, CFileInputStr
|
|||||||
reader.read(reinterpret_cast<ui8*>(filename), 40);
|
reader.read(reinterpret_cast<ui8*>(filename), 40);
|
||||||
|
|
||||||
// for some reason entries in snd have format NAME\0WAVRUBBISH....
|
// for some reason entries in snd have format NAME\0WAVRUBBISH....
|
||||||
//we need to replace first \0 with dot and take the 3 chars with extension (and drop the rest)
|
// and Polish version does not have extension at all
|
||||||
|
// we need to replace first \0 with dot and add wav extension manuall - we don't expect other types here anyway
|
||||||
ArchiveEntry entry;
|
ArchiveEntry entry;
|
||||||
entry.name = filename; // till 1st \0
|
entry.name = filename; // till 1st \0
|
||||||
entry.name += '.';
|
entry.name += ".wav";
|
||||||
entry.name += std::string(filename + entry.name.size(), 3);
|
|
||||||
|
|
||||||
entry.offset = reader.readInt32();
|
entry.offset = reader.readInt32();
|
||||||
entry.fullSize = reader.readInt32();
|
entry.fullSize = reader.readInt32();
|
||||||
|
@ -112,18 +112,31 @@ std::unordered_map<ResourceID, bfs::path> CFilesystemLoader::listFiles(const std
|
|||||||
std::vector<bfs::path> path; //vector holding relative path to our file
|
std::vector<bfs::path> path; //vector holding relative path to our file
|
||||||
|
|
||||||
bfs::recursive_directory_iterator enddir;
|
bfs::recursive_directory_iterator enddir;
|
||||||
|
#if BOOST_VERSION >= 107200 // 1.72
|
||||||
|
bfs::recursive_directory_iterator it(baseDirectory, bfs::directory_options::follow_directory_symlink);
|
||||||
|
#else
|
||||||
bfs::recursive_directory_iterator it(baseDirectory, bfs::symlink_option::recurse);
|
bfs::recursive_directory_iterator it(baseDirectory, bfs::symlink_option::recurse);
|
||||||
|
#endif
|
||||||
|
|
||||||
for(; it != enddir; ++it)
|
for(; it != enddir; ++it)
|
||||||
{
|
{
|
||||||
EResType::Type type;
|
EResType::Type type;
|
||||||
|
#if BOOST_VERSION >= 107200
|
||||||
|
const auto currentDepth = it.depth();
|
||||||
|
#else
|
||||||
|
const auto currentDepth = it.level();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (bfs::is_directory(it->status()))
|
if (bfs::is_directory(it->status()))
|
||||||
{
|
{
|
||||||
path.resize(it.level() + 1);
|
path.resize(currentDepth + 1);
|
||||||
path.back() = it->path().filename();
|
path.back() = it->path().filename();
|
||||||
// don't iterate into directory if depth limit reached
|
// don't iterate into directory if depth limit reached
|
||||||
it.no_push(depth <= it.level());
|
#if BOOST_VERSION >= 107200
|
||||||
|
it.disable_recursion_pending(depth <= currentDepth);
|
||||||
|
#else
|
||||||
|
it.no_push(depth <= currentDepth);
|
||||||
|
#endif
|
||||||
|
|
||||||
type = EResType::DIRECTORY;
|
type = EResType::DIRECTORY;
|
||||||
}
|
}
|
||||||
@ -134,7 +147,7 @@ std::unordered_map<ResourceID, bfs::path> CFilesystemLoader::listFiles(const std
|
|||||||
{
|
{
|
||||||
//reconstruct relative filename (not possible via boost AFAIK)
|
//reconstruct relative filename (not possible via boost AFAIK)
|
||||||
bfs::path filename;
|
bfs::path filename;
|
||||||
const size_t iterations = std::min((size_t)it.level(), path.size());
|
const size_t iterations = std::min(static_cast<size_t>(currentDepth), path.size());
|
||||||
if (iterations)
|
if (iterations)
|
||||||
{
|
{
|
||||||
filename = path.front();
|
filename = path.front();
|
||||||
|
@ -553,24 +553,26 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
|
|||||||
if(hasBuilt(BuildingID::HORDE_2))
|
if(hasBuilt(BuildingID::HORDE_2))
|
||||||
ret.entries.push_back(GrowthInfo::Entry(subID, BuildingID::HORDE_2, creature->hordeGrowth));
|
ret.entries.push_back(GrowthInfo::Entry(subID, BuildingID::HORDE_2, creature->hordeGrowth));
|
||||||
|
|
||||||
int dwellingBonus = 0;
|
//statue-of-legion-like bonus: % to base+castle
|
||||||
if(const PlayerState *p = cb->getPlayerState(tempOwner, false))
|
TConstBonusListPtr bonuses2 = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH_PERCENT));
|
||||||
|
for(const auto & b : *bonuses2)
|
||||||
{
|
{
|
||||||
dwellingBonus = getDwellingBonus(creatures[level].second, p->dwellings);
|
const auto growth = b->val * (base + castleBonus) / 100;
|
||||||
|
ret.entries.push_back(GrowthInfo::Entry(growth, b->Description(growth)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dwellingBonus)
|
|
||||||
ret.entries.push_back(GrowthInfo::Entry(VLC->generaltexth->allTexts[591], dwellingBonus));// \nExternal dwellings %+d
|
|
||||||
|
|
||||||
//other *-of-legion-like bonuses (%d to growth cumulative with grail)
|
//other *-of-legion-like bonuses (%d to growth cumulative with grail)
|
||||||
TConstBonusListPtr bonuses = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH).And(Selector::subtype()(level)));
|
TConstBonusListPtr bonuses = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH).And(Selector::subtype()(level)));
|
||||||
for(const auto & b : *bonuses)
|
for(const auto & b : *bonuses)
|
||||||
ret.entries.push_back(GrowthInfo::Entry(b->val, b->Description()));
|
ret.entries.push_back(GrowthInfo::Entry(b->val, b->Description()));
|
||||||
|
|
||||||
//statue-of-legion-like bonus: % to base+castle
|
int dwellingBonus = 0;
|
||||||
TConstBonusListPtr bonuses2 = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH_PERCENT));
|
if(const PlayerState *p = cb->getPlayerState(tempOwner, false))
|
||||||
for(const auto & b : *bonuses2)
|
{
|
||||||
ret.entries.push_back(GrowthInfo::Entry(b->val * (base + castleBonus) / 100, b->Description()));
|
dwellingBonus = getDwellingBonus(creatures[level].second, p->dwellings);
|
||||||
|
}
|
||||||
|
if(dwellingBonus)
|
||||||
|
ret.entries.push_back(GrowthInfo::Entry(VLC->generaltexth->allTexts[591], dwellingBonus));// \nExternal dwellings %+d
|
||||||
|
|
||||||
if(hasBuilt(BuildingID::GRAIL)) //grail - +50% to ALL (so far added) growth
|
if(hasBuilt(BuildingID::GRAIL)) //grail - +50% to ALL (so far added) growth
|
||||||
ret.entries.push_back(GrowthInfo::Entry(subID, BuildingID::GRAIL, ret.totalGrowth() / 2));
|
ret.entries.push_back(GrowthInfo::Entry(subID, BuildingID::GRAIL, ret.totalGrowth() / 2));
|
||||||
|
@ -1956,7 +1956,13 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
|
|||||||
|
|
||||||
for (auto i = h->Slots().begin(); i != h->Slots().end(); i++)
|
for (auto i = h->Slots().begin(); i != h->Slots().end(); i++)
|
||||||
{
|
{
|
||||||
TQuantity drown = static_cast<TQuantity>(i->second->count * 0.3);
|
// 1-sized stacks are not affected by sirens
|
||||||
|
if (i->second->count == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// tested H3 behavior: 30% (rounded up) of stack drowns
|
||||||
|
TQuantity drown = std::ceil(i->second->count * 0.3);
|
||||||
|
|
||||||
if(drown)
|
if(drown)
|
||||||
{
|
{
|
||||||
cb->changeStackCount(StackLocation(h, i->first), -drown);
|
cb->changeStackCount(StackLocation(h, i->first), -drown);
|
||||||
|
@ -1292,10 +1292,10 @@ std::string CMapSaverJson::writeTerrainTile(const TerrainTile & tile)
|
|||||||
out << tile.terType->typeCode << (int)tile.terView << flipCodes[tile.extTileFlags % 4];
|
out << tile.terType->typeCode << (int)tile.terView << flipCodes[tile.extTileFlags % 4];
|
||||||
|
|
||||||
if(tile.roadType->id != Road::NO_ROAD)
|
if(tile.roadType->id != Road::NO_ROAD)
|
||||||
out << tile.roadType << (int)tile.roadDir << flipCodes[(tile.extTileFlags >> 4) % 4];
|
out << tile.roadType->code << (int)tile.roadDir << flipCodes[(tile.extTileFlags >> 4) % 4];
|
||||||
|
|
||||||
if(tile.riverType->id != River::NO_RIVER)
|
if(tile.riverType->id != River::NO_RIVER)
|
||||||
out << tile.riverType << (int)tile.riverDir << flipCodes[(tile.extTileFlags >> 2) % 4];
|
out << tile.riverType->code << (int)tile.riverDir << flipCodes[(tile.extTileFlags >> 2) % 4];
|
||||||
|
|
||||||
return out.str();
|
return out.str();
|
||||||
}
|
}
|
||||||
|
@ -31,9 +31,18 @@ using namespace boost::asio::ip;
|
|||||||
#define LIL_ENDIAN
|
#define LIL_ENDIAN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct ConnectionBuffers
|
||||||
|
{
|
||||||
|
boost::asio::streambuf readBuffer;
|
||||||
|
boost::asio::streambuf writeBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
void CConnection::init()
|
void CConnection::init()
|
||||||
{
|
{
|
||||||
|
enableBufferedWrite = false;
|
||||||
|
enableBufferedRead = false;
|
||||||
|
connectionBuffers = std::make_unique<ConnectionBuffers>();
|
||||||
|
|
||||||
socket->set_option(boost::asio::ip::tcp::no_delay(true));
|
socket->set_option(boost::asio::ip::tcp::no_delay(true));
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -72,6 +81,7 @@ CConnection::CConnection(std::string host, ui16 port, std::string Name, std::str
|
|||||||
int i;
|
int i;
|
||||||
boost::system::error_code error = asio::error::host_not_found;
|
boost::system::error_code error = asio::error::host_not_found;
|
||||||
socket = std::make_shared<tcp::socket>(*io_service);
|
socket = std::make_shared<tcp::socket>(*io_service);
|
||||||
|
|
||||||
tcp::resolver resolver(*io_service);
|
tcp::resolver resolver(*io_service);
|
||||||
tcp::resolver::iterator end, pom, endpoint_iterator = resolver.resolve(tcp::resolver::query(host, std::to_string(port)),error);
|
tcp::resolver::iterator end, pom, endpoint_iterator = resolver.resolve(tcp::resolver::query(host, std::to_string(port)),error);
|
||||||
if(error)
|
if(error)
|
||||||
@ -138,10 +148,39 @@ CConnection::CConnection(std::shared_ptr<TAcceptor> acceptor, std::shared_ptr<bo
|
|||||||
}
|
}
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CConnection::flushBuffers()
|
||||||
|
{
|
||||||
|
if(!enableBufferedWrite)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
asio::write(*socket, connectionBuffers->writeBuffer);
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
//connection has been lost
|
||||||
|
connected = false;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
enableBufferedWrite = false;
|
||||||
|
}
|
||||||
|
|
||||||
int CConnection::write(const void * data, unsigned size)
|
int CConnection::write(const void * data, unsigned size)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if(enableBufferedWrite)
|
||||||
|
{
|
||||||
|
std::ostream ostream(&connectionBuffers->writeBuffer);
|
||||||
|
|
||||||
|
ostream.write(static_cast<const char *>(data), size);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
ret = static_cast<int>(asio::write(*socket,asio::const_buffers_1(asio::const_buffer(data,size))));
|
ret = static_cast<int>(asio::write(*socket,asio::const_buffers_1(asio::const_buffer(data,size))));
|
||||||
return ret;
|
return ret;
|
||||||
@ -153,10 +192,29 @@ int CConnection::write(const void * data, unsigned size)
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int CConnection::read(void * data, unsigned size)
|
int CConnection::read(void * data, unsigned size)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if(enableBufferedRead)
|
||||||
|
{
|
||||||
|
auto available = connectionBuffers->readBuffer.size();
|
||||||
|
|
||||||
|
while(available < size)
|
||||||
|
{
|
||||||
|
auto bytesRead = socket->read_some(connectionBuffers->readBuffer.prepare(1024));
|
||||||
|
connectionBuffers->readBuffer.commit(bytesRead);
|
||||||
|
available = connectionBuffers->readBuffer.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream istream(&connectionBuffers->readBuffer);
|
||||||
|
|
||||||
|
istream.read(static_cast<char *>(data), size);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
int ret = static_cast<int>(asio::read(*socket,asio::mutable_buffers_1(asio::mutable_buffer(data,size))));
|
int ret = static_cast<int>(asio::read(*socket,asio::mutable_buffers_1(asio::mutable_buffer(data,size))));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -167,6 +225,7 @@ int CConnection::read(void * data, unsigned size)
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CConnection::~CConnection()
|
CConnection::~CConnection()
|
||||||
{
|
{
|
||||||
if(handler)
|
if(handler)
|
||||||
@ -210,6 +269,8 @@ void CConnection::reportState(vstd::CLoggerBase * out)
|
|||||||
|
|
||||||
CPack * CConnection::retrievePack()
|
CPack * CConnection::retrievePack()
|
||||||
{
|
{
|
||||||
|
enableBufferedRead = true;
|
||||||
|
|
||||||
CPack * pack = nullptr;
|
CPack * pack = nullptr;
|
||||||
boost::unique_lock<boost::mutex> lock(*mutexRead);
|
boost::unique_lock<boost::mutex> lock(*mutexRead);
|
||||||
iser & pack;
|
iser & pack;
|
||||||
@ -222,6 +283,9 @@ CPack * CConnection::retrievePack()
|
|||||||
{
|
{
|
||||||
pack->c = this->shared_from_this();
|
pack->c = this->shared_from_this();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enableBufferedRead = false;
|
||||||
|
|
||||||
return pack;
|
return pack;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +293,12 @@ void CConnection::sendPack(const CPack * pack)
|
|||||||
{
|
{
|
||||||
boost::unique_lock<boost::mutex> lock(*mutexWrite);
|
boost::unique_lock<boost::mutex> lock(*mutexWrite);
|
||||||
logNetwork->trace("Sending a pack of type %s", typeid(*pack).name());
|
logNetwork->trace("Sending a pack of type %s", typeid(*pack).name());
|
||||||
|
|
||||||
|
enableBufferedWrite = true;
|
||||||
|
|
||||||
oser & pack;
|
oser & pack;
|
||||||
|
|
||||||
|
flushBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CConnection::disableStackSendingByID()
|
void CConnection::disableStackSendingByID()
|
||||||
|
@ -52,6 +52,7 @@ typedef boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::so
|
|||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
struct CPack;
|
struct CPack;
|
||||||
|
struct ConnectionBuffers;
|
||||||
|
|
||||||
/// Main class for network communication
|
/// Main class for network communication
|
||||||
/// Allows establishing connection and bidirectional read-write
|
/// Allows establishing connection and bidirectional read-write
|
||||||
@ -63,8 +64,14 @@ class DLL_LINKAGE CConnection
|
|||||||
|
|
||||||
int write(const void * data, unsigned size) override;
|
int write(const void * data, unsigned size) override;
|
||||||
int read(void * data, unsigned size) override;
|
int read(void * data, unsigned size) override;
|
||||||
|
void flushBuffers();
|
||||||
|
|
||||||
std::shared_ptr<boost::asio::io_service> io_service; //can be empty if connection made from socket
|
std::shared_ptr<boost::asio::io_service> io_service; //can be empty if connection made from socket
|
||||||
|
|
||||||
|
bool enableBufferedWrite;
|
||||||
|
bool enableBufferedRead;
|
||||||
|
std::unique_ptr<ConnectionBuffers> connectionBuffers;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BinaryDeserializer iser;
|
BinaryDeserializer iser;
|
||||||
BinarySerializer oser;
|
BinarySerializer oser;
|
||||||
|
@ -109,7 +109,8 @@ void Initializer::initialize(CGLighthouse * o)
|
|||||||
|
|
||||||
void Initializer::initialize(CGHeroInstance * o)
|
void Initializer::initialize(CGHeroInstance * o)
|
||||||
{
|
{
|
||||||
if(!o) return;
|
if(!o)
|
||||||
|
return;
|
||||||
|
|
||||||
o->tempOwner = defaultPlayer;
|
o->tempOwner = defaultPlayer;
|
||||||
if(o->ID == Obj::PRISON)
|
if(o->ID == Obj::PRISON)
|
||||||
@ -119,9 +120,9 @@ void Initializer::initialize(CGHeroInstance * o)
|
|||||||
{
|
{
|
||||||
for(auto t : VLC->heroh->objects)
|
for(auto t : VLC->heroh->objects)
|
||||||
{
|
{
|
||||||
if(t->heroClass == VLC->heroh->classes.objects[o->subID].get())
|
if(t->heroClass->getId() == HeroClassID(o->subID))
|
||||||
{
|
{
|
||||||
o->type = VLC->heroh->objects[o->subID];
|
o->type = t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,36 +33,32 @@ void ResourceConverter::convertExtractedResourceFiles(ConversionOptions conversi
|
|||||||
|
|
||||||
void ResourceConverter::doConvertPcxToPng(bool deleteOriginals)
|
void ResourceConverter::doConvertPcxToPng(bool deleteOriginals)
|
||||||
{
|
{
|
||||||
std::string filename;
|
|
||||||
|
|
||||||
bfs::path imagesPath = VCMIDirs::get().userExtractedPath() / "IMAGES";
|
bfs::path imagesPath = VCMIDirs::get().userExtractedPath() / "IMAGES";
|
||||||
bfs::directory_iterator end_iter;
|
bfs::directory_iterator end_iter;
|
||||||
|
|
||||||
for(bfs::directory_iterator dir_itr(imagesPath); dir_itr != end_iter; ++dir_itr)
|
for(bfs::directory_iterator dir_itr(imagesPath); dir_itr != end_iter; ++dir_itr)
|
||||||
{
|
{
|
||||||
|
const auto filename = dir_itr->path().filename();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!bfs::is_regular_file(dir_itr->status()))
|
if (!bfs::is_regular_file(dir_itr->status()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string filePath = dir_itr->path().string();
|
std::string filenameLowerCase = boost::algorithm::to_lower_copy(filename.string());
|
||||||
std::string fileStem = dir_itr->path().stem().string();
|
|
||||||
filename = dir_itr->path().filename().string();
|
|
||||||
std::string filenameLowerCase = boost::locale::to_lower(filename);
|
|
||||||
|
|
||||||
if(bfs::extension(filenameLowerCase) == ".pcx")
|
if(boost::algorithm::to_lower_copy(filename.extension().string()) == ".pcx")
|
||||||
{
|
{
|
||||||
auto img = BitmapHandler::loadBitmap(filenameLowerCase);
|
auto img = BitmapHandler::loadBitmap(filenameLowerCase);
|
||||||
bfs::path pngFilePath = imagesPath / (fileStem + ".png");
|
bfs::path pngFilePath = imagesPath / (dir_itr->path().stem().string() + ".png");
|
||||||
img.save(pathToQString(pngFilePath), "PNG");
|
img.save(pathToQString(pngFilePath), "PNG");
|
||||||
|
|
||||||
if(deleteOriginals)
|
if(deleteOriginals)
|
||||||
bfs::remove(filePath);
|
bfs::remove(dir_itr->path());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(const std::exception & ex)
|
catch(const std::exception & ex)
|
||||||
{
|
{
|
||||||
logGlobal->info(filename + " " + ex.what() + "\n");
|
logGlobal->info(filename.string() + " " + ex.what() + "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3916,9 +3916,17 @@ bool CGameHandler::moveArtifact(const ArtifactLocation &al1, const ArtifactLocat
|
|||||||
moveArtifact(dst, ArtifactLocation(dst.artHolder, ArtifactPosition(
|
moveArtifact(dst, ArtifactLocation(dst.artHolder, ArtifactPosition(
|
||||||
(si32)dst.getHolderArtSet()->artifactsInBackpack.size() + GameConstants::BACKPACK_START)));
|
(si32)dst.getHolderArtSet()->artifactsInBackpack.size() + GameConstants::BACKPACK_START)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
auto hero = boost::get<ConstTransitivePtr<CGHeroInstance>>(dst.artHolder);
|
auto hero = boost::get<ConstTransitivePtr<CGHeroInstance>>(dst.artHolder);
|
||||||
if(ArtifactUtils::checkSpellbookIsNeeded(hero, srcArtifact->artType->id, dst.slot))
|
if(ArtifactUtils::checkSpellbookIsNeeded(hero, srcArtifact->artType->id, dst.slot))
|
||||||
giveHeroNewArtifact(hero, VLC->arth->objects[ArtifactID::SPELLBOOK], ArtifactPosition::SPELLBOOK);
|
giveHeroNewArtifact(hero, VLC->arth->objects[ArtifactID::SPELLBOOK], ArtifactPosition::SPELLBOOK);
|
||||||
|
}
|
||||||
|
catch (boost::bad_get const &)
|
||||||
|
{
|
||||||
|
// object other than hero received an art - ignore
|
||||||
|
}
|
||||||
|
|
||||||
MoveArtifact ma(&src, &dst);
|
MoveArtifact ma(&src, &dst);
|
||||||
sendAndApply(&ma);
|
sendAndApply(&ma);
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
#include "../lib/mapping/CMap.h"
|
#include "../lib/mapping/CMap.h"
|
||||||
#include "../lib/rmg/CMapGenOptions.h"
|
#include "../lib/rmg/CMapGenOptions.h"
|
||||||
#ifdef VCMI_ANDROID
|
#ifdef VCMI_ANDROID
|
||||||
|
#include <jni.h>
|
||||||
|
#include <android/log.h>
|
||||||
#include "lib/CAndroidVMHelper.h"
|
#include "lib/CAndroidVMHelper.h"
|
||||||
#elif !defined(VCMI_IOS)
|
#elif !defined(VCMI_IOS)
|
||||||
#include "../lib/Interprocess.h"
|
#include "../lib/Interprocess.h"
|
||||||
@ -1118,15 +1120,21 @@ int main(int argc, char * argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VCMI_ANDROID
|
#ifdef VCMI_ANDROID
|
||||||
void CVCMIServer::create(const std::vector<std::string> & args)
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_createServer(JNIEnv * env, jclass cls)
|
||||||
|
{
|
||||||
|
__android_log_write(ANDROID_LOG_INFO, "VCMI", "Got jni call to init server");
|
||||||
|
CAndroidVMHelper::cacheVM(env);
|
||||||
|
CVCMIServer::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CVCMIServer::create()
|
||||||
{
|
{
|
||||||
const char * foo = "android-server";
|
const char * foo = "android-server";
|
||||||
std::vector<const void *> argv = {foo};
|
std::vector<const void *> argv = {foo};
|
||||||
for(auto & a : args)
|
main(argv.size(), reinterpret_cast<char **>(const_cast<void **>(&*argv.begin())));
|
||||||
argv.push_back(a.c_str());
|
|
||||||
|
|
||||||
main(argv.size(), const_cast<char **>(foo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(SINGLE_PROCESS_APP)
|
#elif defined(SINGLE_PROCESS_APP)
|
||||||
void CVCMIServer::create(boost::condition_variable * cond, const std::vector<std::string> & args)
|
void CVCMIServer::create(boost::condition_variable * cond, const std::vector<std::string> & args)
|
||||||
{
|
{
|
||||||
|
@ -114,7 +114,7 @@ public:
|
|||||||
ui8 getIdOfFirstUnallocatedPlayer() const;
|
ui8 getIdOfFirstUnallocatedPlayer() const;
|
||||||
|
|
||||||
#ifdef VCMI_ANDROID
|
#ifdef VCMI_ANDROID
|
||||||
static void create(const std::vector<std::string> & args);
|
static void create();
|
||||||
#elif defined(SINGLE_PROCESS_APP)
|
#elif defined(SINGLE_PROCESS_APP)
|
||||||
static void create(boost::condition_variable * cond, const std::vector<std::string> & args);
|
static void create(boost::condition_variable * cond, const std::vector<std::string> & args);
|
||||||
#endif
|
#endif
|
||||||
|
@ -87,6 +87,11 @@ warning ()
|
|||||||
warn_user=true
|
warn_user=true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#checks whether specified directory exists. Also works with globs
|
||||||
|
dir_exists() {
|
||||||
|
[ -d "$1" ]
|
||||||
|
}
|
||||||
|
|
||||||
# check if selected options are correct.
|
# check if selected options are correct.
|
||||||
|
|
||||||
if [[ -n "$data_dir" ]]
|
if [[ -n "$data_dir" ]]
|
||||||
@ -177,7 +182,7 @@ then
|
|||||||
cd "$data_dir" && innoextract "$gog_file"
|
cd "$data_dir" && innoextract "$gog_file"
|
||||||
|
|
||||||
# some versions of gog.com installer (or innoextract tool?) place game files inside /app directory
|
# some versions of gog.com installer (or innoextract tool?) place game files inside /app directory
|
||||||
if [[ -d "$data_dir"/app ]]
|
if dir_exists "$data_dir"/app/[Dd][Aa][Tt][Aa]
|
||||||
then
|
then
|
||||||
data_dir="$data_dir"/app
|
data_dir="$data_dir"/app
|
||||||
fi
|
fi
|
||||||
|
Loading…
x
Reference in New Issue
Block a user