mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Merge vcmi/beta into vcmi/develop
This commit is contained in:
		| @@ -1,3 +0,0 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| "$1/ios/zip2ipa.sh" "$2" | ||||
| @@ -729,6 +729,7 @@ elseif(APPLE_MACOS AND NOT ENABLE_MONOLITHIC_INSTALL) | ||||
| 	add_subdirectory(osx) | ||||
| elseif(APPLE_IOS) | ||||
| 	set(CPACK_GENERATOR ZIP) | ||||
| 	set(CPACK_ARCHIVE_FILE_EXTENSION ipa) | ||||
| 	set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF) | ||||
| 	set(CPACK_INSTALL_CMAKE_PROJECTS "${CMAKE_CURRENT_BINARY_DIR};${CMAKE_PROJECT_NAME};app;/") | ||||
| else() | ||||
|   | ||||
| @@ -376,7 +376,8 @@ int main(int argc, char * argv[]) | ||||
| 		SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); | ||||
| 		#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); | ||||
|  | ||||
| @@ -432,11 +433,20 @@ int main(int argc, char * argv[]) | ||||
| 		CCS->musich->setVolume((ui32)settings["general"]["music"].Float()); | ||||
| 		logGlobal->info("Initializing screen and sound handling: %d ms", pomtime.getDiff()); | ||||
| 	} | ||||
|  | ||||
| #ifdef VCMI_MAC | ||||
| 	// Ctrl+click should be treated as a right click on Mac OS X | ||||
| 	SDL_SetHint(SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, "1"); | ||||
| #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 | ||||
| 	//we can properly play intro only in the main thread, so we have to move loading to the separate thread | ||||
| 	boost::thread loading(init); | ||||
|   | ||||
| @@ -263,8 +263,7 @@ elseif(APPLE_IOS) | ||||
| 		set_source_files_properties(${XCODE_RESOURCE_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) | ||||
|  | ||||
| 		# 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") | ||||
| 		if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.22.0" AND CMAKE_VERSION VERSION_LESS "3.25.0") | ||||
| 			set_source_files_properties(${XCODE_RESOURCE_PATH} PROPERTIES LANGUAGE CXX) | ||||
| 		endif() | ||||
| 	endforeach() | ||||
|   | ||||
| @@ -775,14 +775,14 @@ void CClient::removeGUI() | ||||
| } | ||||
|  | ||||
| #ifdef VCMI_ANDROID | ||||
| extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_clientSetupJNI(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, jobject cls) | ||||
| extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerClosed(JNIEnv * env, jclass cls) | ||||
| { | ||||
| 	logNetwork->info("Received server closed signal"); | ||||
| 	if (CSH) { | ||||
| @@ -790,13 +790,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"); | ||||
| 	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"); | ||||
| 	if(!LOCPLINT || !LOCPLINT->cb) | ||||
|   | ||||
| @@ -79,6 +79,13 @@ void CGuiHandler::processLists(const ui16 activityFlag, std::function<void (std: | ||||
| 	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) | ||||
| { | ||||
| 	processLists(activityFlag,[&](std::list<CIntObject*> * lst){ | ||||
| @@ -207,7 +214,79 @@ void CGuiHandler::handleEvents() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGuiHandler::handleCurrentEvent(const SDL_Event & current ) | ||||
| 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->position().x + (int)(GH.pointerSpeedMultiplier * w * dx); | ||||
| 	sme.y = CCS->curh->position().y + (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->position().x; | ||||
| 	sme.y = CCS->curh->position().y; | ||||
|  | ||||
| 	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); | ||||
| 	CSDL_Ext::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( SDL_Event & current ) | ||||
| { | ||||
| 	if(current.type == SDL_KEYDOWN || current.type == SDL_KEYUP) | ||||
| 	{ | ||||
| @@ -344,22 +423,78 @@ void CGuiHandler::handleCurrentEvent(const SDL_Event & current ) | ||||
| 			it->textEdited(current.edit); | ||||
| 		} | ||||
| 	} | ||||
| 	//todo: muiltitouch | ||||
| 	else if(current.type == SDL_MOUSEBUTTONUP) | ||||
| 	{ | ||||
| 		switch(current.button.button) | ||||
| 		if(!multifinger) | ||||
| 		{ | ||||
| 		case SDL_BUTTON_LEFT: | ||||
| 			handleMouseButtonClick(lclickable, EIntObjMouseBtnType::LEFT, false); | ||||
| 			break; | ||||
| 		case SDL_BUTTON_RIGHT: | ||||
| 			handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false); | ||||
| 			break; | ||||
| 		case SDL_BUTTON_MIDDLE: | ||||
| 			handleMouseButtonClick(mclickable, EIntObjMouseBtnType::MIDDLE, false); | ||||
| 			break; | ||||
| 			switch(current.button.button) | ||||
| 			{ | ||||
| 			case SDL_BUTTON_LEFT: | ||||
| 				handleMouseButtonClick(lclickable, EIntObjMouseBtnType::LEFT, false); | ||||
| 				break; | ||||
| 			case SDL_BUTTON_RIGHT: | ||||
| 				handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false); | ||||
| 				break; | ||||
| 			case SDL_BUTTON_MIDDLE: | ||||
| 				handleMouseButtonClick(mclickable, EIntObjMouseBtnType::MIDDLE, false); | ||||
| 				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(¤t); | ||||
| 			handleMouseMotion(current); | ||||
| 			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(¤t); | ||||
| 			handleMouseMotion(current); | ||||
| 			handleMouseButtonClick(rclickable, EIntObjMouseBtnType::RIGHT, false); | ||||
| 			multifinger = fingerCount != 0; | ||||
| 		} | ||||
| #endif //VCMI_IOS | ||||
| 	} | ||||
| } //event end | ||||
|  | ||||
| void CGuiHandler::handleMouseButtonClick(CIntObjectList & interestedObjs, EIntObjMouseBtnType btn, bool isPressed) | ||||
| @@ -431,20 +566,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() | ||||
| { | ||||
|  | ||||
| @@ -486,7 +607,8 @@ void CGuiHandler::renderFrame() | ||||
|  | ||||
|  | ||||
| CGuiHandler::CGuiHandler() | ||||
| 	: lastClick(-500, -500),lastClickTime(0), defActionsDef(0), captureChildren(false) | ||||
| 	: lastClick(-500, -500),lastClickTime(0), defActionsDef(0), captureChildren(false), | ||||
|     multifinger(false) | ||||
| { | ||||
| 	continueEventHandling = true; | ||||
| 	curInt = nullptr; | ||||
|   | ||||
| @@ -92,9 +92,12 @@ private: | ||||
|  | ||||
| 	void handleMouseButtonClick(CIntObjectList & interestedObjs, EIntObjMouseBtnType btn, bool isPressed); | ||||
| 	void processLists(const ui16 activityFlag, std::function<void (std::list<CIntObject*> *)> cb); | ||||
| 	void handleCurrentEvent(const SDL_Event & current); | ||||
| 	void handleCurrentEvent(SDL_Event ¤t); | ||||
| 	void handleMouseMotion(const SDL_Event & current); | ||||
| 	void handleMoveInterested( const SDL_MouseMotionEvent & motion ); | ||||
| 	void convertTouchToMouse(SDL_Event * current); | ||||
| 	void fakeMoveCursor(float dx, float dy); | ||||
| 	void fakeMouseButtonEventRelativeMode(bool down, bool right); | ||||
|  | ||||
| public: | ||||
| 	void handleElementActivate(CIntObject * elem, ui16 activityFlag); | ||||
| @@ -110,6 +113,9 @@ public: | ||||
|  | ||||
| 	Point lastClick; | ||||
| 	unsigned lastClickTime; | ||||
| 	bool multifinger; | ||||
| 	bool isPointerRelativeMode; | ||||
| 	float pointerSpeedMultiplier; | ||||
|  | ||||
| 	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 | ||||
| @@ -118,6 +124,7 @@ public: | ||||
| 	CGuiHandler(); | ||||
| 	~CGuiHandler(); | ||||
|  | ||||
| 	void init(); | ||||
| 	void renderFrame(); | ||||
|  | ||||
| 	void totalRedraw(); //forces total redraw (using showAll), sets a flag, method gets called at the end of the rendering | ||||
|   | ||||
| @@ -889,22 +889,10 @@ SDL_Color CSDL_Ext::makeColor(ui8 r, ui8 g, ui8 b, ui8 a) | ||||
|  | ||||
| void CSDL_Ext::startTextInput(const Rect & whereInput) | ||||
| { | ||||
| 	const SDL_Rect where = CSDL_Ext::toSDL(whereInput); | ||||
|  | ||||
| 	auto impl = [](SDL_Rect where) | ||||
| 	{ | ||||
| 		if (SDL_IsTextInputActive() == SDL_FALSE) | ||||
| 		{ | ||||
| 			SDL_StartTextInput(); | ||||
| 		} | ||||
| 		SDL_SetTextInputRect(&where); | ||||
| 	}; | ||||
|  | ||||
| #ifdef VCMI_APPLE | ||||
| 	dispatch_async(dispatch_get_main_queue(), ^{ | ||||
| #endif | ||||
|  | ||||
| #ifdef VCMI_IOS | ||||
| 	// TODO ios: looks like SDL bug actually, try fixing there | ||||
| 	auto renderer = SDL_GetRenderer(mainWindow); | ||||
| 	float scaleX, scaleY; | ||||
| @@ -912,17 +900,25 @@ void CSDL_Ext::startTextInput(const Rect & whereInput) | ||||
| 	SDL_RenderGetScale(renderer, &scaleX, &scaleY); | ||||
| 	SDL_RenderGetViewport(renderer, &viewport); | ||||
|  | ||||
| #ifdef VCMI_IOS | ||||
| 	const auto nativeScale = iOS_utils::screenScale(); | ||||
| 	auto rectInScreenCoordinates = where; | ||||
| 	rectInScreenCoordinates.x = (viewport.x + rectInScreenCoordinates.x) * scaleX / nativeScale; | ||||
| 	rectInScreenCoordinates.y = (viewport.y + rectInScreenCoordinates.y) * scaleY / nativeScale; | ||||
| 	rectInScreenCoordinates.w = rectInScreenCoordinates.w * scaleX / nativeScale; | ||||
| 	rectInScreenCoordinates.h = rectInScreenCoordinates.h * scaleY / nativeScale; | ||||
| 	impl(rectInScreenCoordinates); | ||||
| #else | ||||
| 	impl(where); | ||||
| 	scaleX /= nativeScale; | ||||
| 	scaleY /= nativeScale; | ||||
| #endif | ||||
|  | ||||
| 	SDL_Rect rectInScreenCoordinates; | ||||
| 	rectInScreenCoordinates.x = (viewport.x + whereInput.x) * scaleX; | ||||
| 	rectInScreenCoordinates.y = (viewport.y + whereInput.y) * scaleY; | ||||
| 	rectInScreenCoordinates.w = whereInput.w * scaleX; | ||||
| 	rectInScreenCoordinates.h = whereInput.h * scaleY; | ||||
|  | ||||
| 	SDL_SetTextInputRect(&rectInScreenCoordinates); | ||||
|  | ||||
| 	if (SDL_IsTextInputActive() == SDL_FALSE) | ||||
| 	{ | ||||
| 		SDL_StartTextInput(); | ||||
| 	} | ||||
|  | ||||
| #ifdef VCMI_APPLE | ||||
| 	}); | ||||
| #endif | ||||
|   | ||||
| @@ -10,11 +10,13 @@ | ||||
|  | ||||
| #import <UIKit/UIKit.h> | ||||
|  | ||||
| #include <SDL_events.h> | ||||
|  | ||||
| NS_ASSUME_NONNULL_BEGIN | ||||
|  | ||||
| @interface GameChatKeyboardHandler : NSObject | ||||
|  | ||||
| - (void)triggerInput; | ||||
| + (void)sendKeyEventWithKeyCode:(SDL_KeyCode)keyCode; | ||||
|  | ||||
| @end | ||||
|  | ||||
|   | ||||
| @@ -10,20 +10,8 @@ | ||||
|  | ||||
| #import "GameChatKeyboardHandler.h" | ||||
|  | ||||
| #include <SDL_events.h> | ||||
|  | ||||
| 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 () | ||||
| @property (nonatomic) BOOL wasChatMessageSent; | ||||
| @@ -31,28 +19,40 @@ static void sendKeyEvent(SDL_KeyCode keyCode) | ||||
|  | ||||
| @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; | ||||
| 	[notificationCenter addObserver:self selector:@selector(textDidBeginEditing:) name:UITextFieldTextDidBeginEditingNotification object:nil]; | ||||
| 	[notificationCenter addObserver:self selector:@selector(textDidEndEditing:) name:UITextFieldTextDidEndEditingNotification object:nil]; | ||||
|  | ||||
| 	self.wasChatMessageSent = NO; | ||||
| 	sendKeyEvent(SDLK_TAB); | ||||
| 	return self; | ||||
| } | ||||
|  | ||||
| #pragma mark - Notifications | ||||
|  | ||||
| - (void)textDidBeginEditing:(NSNotification *)n { | ||||
| 	self.wasChatMessageSent = NO; | ||||
|  | ||||
| 	// watch for pressing Return to ignore sending Escape key after keyboard is closed | ||||
| 	SDL_AddEventWatch(watchReturnKey, (__bridge void *)self); | ||||
| } | ||||
|  | ||||
| - (void)textDidEndEditing:(NSNotification *)n { | ||||
| 	[NSNotificationCenter.defaultCenter removeObserver:self]; | ||||
|  | ||||
| 	// discard chat message | ||||
| 	if(!self.wasChatMessageSent) | ||||
| 		sendKeyEvent(SDLK_ESCAPE); | ||||
| 		[[self class] sendKeyEventWithKeyCode:SDLK_ESCAPE]; | ||||
| } | ||||
|  | ||||
| @end | ||||
|   | ||||
| @@ -95,7 +95,7 @@ | ||||
| - (void)handlePinch:(UIGestureRecognizer *)gesture { | ||||
|     if(gesture.state != UIGestureRecognizerStateBegan || CSH->state != EClientState::GAMEPLAY) | ||||
|         return; | ||||
| 	[self.gameChatHandler triggerInput]; | ||||
| 	[GameChatKeyboardHandler sendKeyEventWithKeyCode:SDLK_SPACE]; | ||||
| } | ||||
|  | ||||
| #pragma mark - UIGestureRecognizerDelegate | ||||
|   | ||||
| @@ -177,7 +177,7 @@ void CTerrainRect::mouseMoved(const SDL_MouseMotionEvent & sEvent) | ||||
| void CTerrainRect::handleSwipeMove(const SDL_MouseMotionEvent & sEvent) | ||||
| { | ||||
| #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 | ||||
| 	if((sEvent.state & SDL_BUTTON_MMASK) == 0) // swipe only works with middle mouse on other platforms | ||||
| #endif | ||||
|   | ||||
| @@ -101,7 +101,7 @@ void QuickRecruitmentWindow::maxAllCards(std::vector<std::shared_ptr<CreaturePur | ||||
|  | ||||
| void QuickRecruitmentWindow::purchaseUnits() | ||||
| { | ||||
| 	for(auto selected : cards) | ||||
| 	for(auto selected : boost::adaptors::reverse(cards)) | ||||
| 	{ | ||||
| 		if(selected->slider->getValue()) | ||||
| 		{ | ||||
|   | ||||
| @@ -17,7 +17,21 @@ | ||||
| 			"type" : "object", | ||||
| 			"default": {}, | ||||
| 			"additionalProperties" : false, | ||||
| 			"required" : [ "playerName", "showfps", "music", "sound", "encoding", "language", "swipe", "saveRandomMaps", "saveFrequency", "notifications", "extraDump" ], | ||||
| 			"required" : [ | ||||
| 				"playerName", | ||||
| 				"showfps", | ||||
| 				"music", | ||||
| 				"sound", | ||||
| 				"encoding", | ||||
| 				"language", | ||||
| 				"swipe", | ||||
| 				"saveRandomMaps", | ||||
| 				"saveFrequency", | ||||
| 				"notifications", | ||||
| 				"extraDump", | ||||
| 				"userRelativePointer", | ||||
| 				"relativePointerSpeedMultiplier" | ||||
| 			], | ||||
| 			"properties" : { | ||||
| 				"playerName" : { | ||||
| 					"type":"string", | ||||
| @@ -75,6 +89,14 @@ | ||||
| 				"extraDump" : { | ||||
| 					"type" : "boolean", | ||||
| 					"default" : false | ||||
| 				}, | ||||
| 				"userRelativePointer" : { | ||||
| 					"type" : "boolean", | ||||
| 					"default" : false | ||||
| 				}, | ||||
| 				"relativePointerSpeedMultiplier" : { | ||||
| 					"type" : "number", | ||||
| 					"default" : 1 | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
|   | ||||
| @@ -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" | ||||
| @@ -96,7 +96,7 @@ jclass CAndroidVMHelper::findClass(const std::string & name, bool classloaded) | ||||
| 	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 envHelper; | ||||
|   | ||||
| @@ -1583,7 +1583,7 @@ bool NBonus::hasOfType(const CBonusSystemNode *obj, Bonus::BonusType type, int s | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| std::string Bonus::Description() const | ||||
| std::string Bonus::Description(boost::optional<si32> customValue) const | ||||
| { | ||||
| 	std::ostringstream str; | ||||
|  | ||||
| @@ -1622,8 +1622,8 @@ std::string Bonus::Description() const | ||||
| 		str << description; | ||||
| 	} | ||||
|  | ||||
| 	if(val != 0) | ||||
| 		str << " " << std::showpos << val; | ||||
| 	if(auto value = customValue.value_or(val)) | ||||
| 		str << " " << std::showpos << value; | ||||
|  | ||||
| 	return str.str(); | ||||
| } | ||||
|   | ||||
| @@ -510,7 +510,7 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus> | ||||
| 		return (high << 16) + low; | ||||
| 	} | ||||
|  | ||||
| 	std::string Description() const; | ||||
| 	std::string Description(boost::optional<si32> customValue = {}) const; | ||||
| 	JsonNode toJsonNode() const; | ||||
| 	std::string nameForBonus() const; // generate suitable name for bonus - e.g. for storing in json struct | ||||
|  | ||||
|   | ||||
| @@ -554,24 +554,26 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const | ||||
| 		if(hasBuilt(BuildingID::HORDE_2)) | ||||
| 			ret.entries.push_back(GrowthInfo::Entry(subID, BuildingID::HORDE_2, creature->hordeGrowth)); | ||||
|  | ||||
| 	int dwellingBonus = 0; | ||||
| 	if(const PlayerState *p = cb->getPlayerState(tempOwner, false)) | ||||
| 	//statue-of-legion-like bonus: % to base+castle | ||||
| 	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) | ||||
| 	TConstBonusListPtr bonuses = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH).And(Selector::subtype()(level))); | ||||
| 	for(const auto & b : *bonuses) | ||||
| 		ret.entries.push_back(GrowthInfo::Entry(b->val, b->Description())); | ||||
|  | ||||
| 	//statue-of-legion-like bonus: % to base+castle | ||||
| 	TConstBonusListPtr bonuses2 = getBonuses(Selector::type()(Bonus::CREATURE_GROWTH_PERCENT)); | ||||
| 	for(const auto & b : *bonuses2) | ||||
| 		ret.entries.push_back(GrowthInfo::Entry(b->val * (base + castleBonus) / 100, b->Description())); | ||||
| 	int dwellingBonus = 0; | ||||
| 	if(const PlayerState *p = cb->getPlayerState(tempOwner, false)) | ||||
| 	{ | ||||
| 		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 | ||||
| 		ret.entries.push_back(GrowthInfo::Entry(subID, BuildingID::GRAIL, ret.totalGrowth() / 2)); | ||||
|   | ||||
| @@ -1326,10 +1326,10 @@ std::string CMapSaverJson::writeTerrainTile(const TerrainTile & tile) | ||||
| 	out << tile.terType->shortIdentifier << (int)tile.terView << flipCodes[tile.extTileFlags % 4]; | ||||
|  | ||||
| 	if(tile.roadType->getId() != Road::NO_ROAD) | ||||
| 		out << tile.roadType << (int)tile.roadDir << flipCodes[(tile.extTileFlags >> 4) % 4]; | ||||
| 		out << tile.roadType->shortIdentifier << (int)tile.roadDir << flipCodes[(tile.extTileFlags >> 4) % 4]; | ||||
|  | ||||
| 	if(tile.riverType->getId() != River::NO_RIVER) | ||||
| 		out << tile.riverType << (int)tile.riverDir << flipCodes[(tile.extTileFlags >> 2) % 4]; | ||||
| 		out << tile.riverType->shortIdentifier << (int)tile.riverDir << flipCodes[(tile.extTileFlags >> 2) % 4]; | ||||
|  | ||||
| 	return out.str(); | ||||
| } | ||||
|   | ||||
| @@ -28,6 +28,8 @@ | ||||
| #include "../lib/mapping/CMap.h" | ||||
| #include "../lib/rmg/CMapGenOptions.h" | ||||
| #ifdef VCMI_ANDROID | ||||
| #include <jni.h> | ||||
| #include <android/log.h> | ||||
| #include "lib/CAndroidVMHelper.h" | ||||
| #elif !defined(VCMI_IOS) | ||||
| #include "../lib/Interprocess.h" | ||||
| @@ -1122,12 +1124,21 @@ int main(int argc, char * argv[]) | ||||
| } | ||||
|  | ||||
| #ifdef VCMI_ANDROID | ||||
|  | ||||
| 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"; | ||||
| 	std::vector<const void *> argv = {foo}; | ||||
| 	main(argv.size(), reinterpret_cast<char **>(const_cast<void **>(&*argv.begin()))); | ||||
| } | ||||
|  | ||||
| #elif defined(SINGLE_PROCESS_APP) | ||||
| void CVCMIServer::create(boost::condition_variable * cond, const std::vector<std::string> & args) | ||||
| { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user