Add Android controls (#101)

This commit is contained in:
Alexander Batalov 2022-07-29 20:04:37 +03:00 committed by GitHub
parent e41a4b8e16
commit 6064a4bc79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 260 additions and 3 deletions

11
.gitattributes vendored
View File

@ -2,14 +2,23 @@
*.c text eol=lf *.c text eol=lf
*.cc text eol=lf *.cc text eol=lf
*.cmake text eol=lf *.cmake text eol=lf
*.gradle text eol=lf
*.h text eol=lf *.h text eol=lf
*.md text eol=lf *.java text eol=lf
*.json text eol=lf *.json text eol=lf
*.md text eol=lf
*.plist text eol=lf *.plist text eol=lf
*.pro text eol=lf
*.properties text eol=lf
*.xml text eol=lf
*.yml text eol=lf *.yml text eol=lf
.clang-format text eol=lf .clang-format text eol=lf
.editorconfig text eol=lf .editorconfig text eol=lf
.gitattributes text eol=lf .gitattributes text eol=lf
.gitignore text eol=lf .gitignore text eol=lf
gradlew text eol=lf
CMakeLists.txt text eol=lf CMakeLists.txt text eol=lf
LICENSE text eol=lf LICENSE text eol=lf
# Force CRLF
*.bat text eol=crlf

View File

@ -38,6 +38,49 @@ jobs:
- name: cppcheck - name: cppcheck
run: cppcheck --std=c++17 src/ run: cppcheck --std=c++17 src/
android:
name: Android
runs-on: ubuntu-latest
steps:
- name: Clone
uses: actions/checkout@v3
- name: Setup Java
uses: actions/setup-java@v2
with:
distribution: temurin
java-version: 11
cache: gradle
- name: Cache cmake build
uses: actions/cache@v3
with:
path: os/android/app/.cxx
key: android-cmake-v1
- name: Setup signing config
run: |
cd os/android
echo "$KEYSTORE_FILE_BASE64" | base64 --decode > debug.keystore
echo "$KEYSTORE_PROPERTIES_FILE_BASE64" | base64 --decode > debug-keystore.properties
env:
KEYSTORE_FILE_BASE64: ${{ secrets.ANDROID_DEBUG_KEYSTORE_FILE_BASE64 }}
KEYSTORE_PROPERTIES_FILE_BASE64: ${{ secrets.ANDROID_DEBUG_KEYSTORE_PROPERTIES_FILE_BASE64 }}
- name: Build
run: |
cd os/android
./gradlew assembleDebug
- name: Upload
uses: actions/upload-artifact@v3
with:
name: fallout2-ce-debug.apk
path: os/android/app/build/outputs/apk/debug/app-debug.apk
retention-days: 7
linux: linux:
name: Linux (${{ matrix.arch }}) name: Linux (${{ matrix.arch }})

View File

@ -10,6 +10,51 @@ defaults:
shell: bash shell: bash
jobs: jobs:
android:
name: Android
runs-on: ubuntu-latest
steps:
- name: Clone
uses: actions/checkout@v3
- name: Setup Java
uses: actions/setup-java@v2
with:
distribution: temurin
java-version: 11
cache: gradle
- name: Cache cmake build
uses: actions/cache@v3
with:
path: os/android/app/.cxx
key: android-cmake-v1
- name: Setup signing config
run: |
cd os/android
echo "$KEYSTORE_FILE_BASE64" | base64 --decode > release.keystore
echo "$KEYSTORE_PROPERTIES_FILE_BASE64" | base64 --decode > release-keystore.properties
env:
KEYSTORE_FILE_BASE64: ${{ secrets.ANDROID_RELEASE_KEYSTORE_FILE_BASE64 }}
KEYSTORE_PROPERTIES_FILE_BASE64: ${{ secrets.ANDROID_RELEASE_KEYSTORE_PROPERTIES_FILE_BASE64 }}
- name: Build
run: |
cd os/android
./gradlew assembleRelease
- name: Upload
run: |
cd os/android/app/build/outputs/apk/release
cp app-release.apk fallout2-ce-android.apk
gh release upload ${{ github.ref_name }} fallout2-ce-android.apk
rm fallout2-ce-android.apk
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
linux: linux:
name: Linux (${{ matrix.arch }}) name: Linux (${{ matrix.arch }})

View File

@ -34,6 +34,20 @@ $ sudo apt install libsdl2-2.0-0
- Run `fallout2-ce.app`. - Run `fallout2-ce.app`.
### Android
> **NOTE**: Fallout 2 was designed with mouse in mind. There are many controls that require precise cursor positioning, which is not possible with fingers. When playing on Android you'll use fingers to move mouse cursor, not a character, or a map. Double tap to "click" left mouse button in the current cursor position, triple tap to "click" right mouse button. It might feel awkward at first, but it's super handy - you can play with just a thumb. This is not set in stone and might change in the future.
- Download `fallout2-ce.apk` and copy it to your device. Open it with file explorer, follow instructions (install from unknown source).
- Run the game once, it will say `Couldn't find/load text fonts` and create a folder for data assets.
- Open file explorer, navigate to `Android/data/com.alexbatalov.fallout2ce/files`, delete junk folders inside (they will be named as game files, just delete them).
- Copy `master.dat`, `critter.dat`, `patch000.dat` and `data` folder from your Windows/macOS installation to the folder above.
- Run the game again.
## Contributing ## Contributing
Integrating Sfall goodies is the top priority. Quality of life updates are OK too. Please no large scale refactorings at this time as we need to reconcile changes from Reference Edition, which will make this process slow and error-prone. In any case open up an issue with your suggestion or to notify other people that something is being worked on. Integrating Sfall goodies is the top priority. Quality of life updates are OK too. Please no large scale refactorings at this time as we need to reconcile changes from Reference Edition, which will make this process slow and error-prone. In any case open up an issue with your suggestion or to notify other people that something is being worked on.

View File

@ -7,3 +7,7 @@
/.idea/navEditor.xml /.idea/navEditor.xml
/.idea/workspace.xml /.idea/workspace.xml
/local.properties /local.properties
/debug-keystore.properties
/debug.keystore
/release-keystore.properties
/release.keystore

View File

@ -1,2 +1,5 @@
/.cxx /.cxx
/build /build
# TODO: Cleanup root .gitignore
!/src/debug

View File

@ -26,10 +26,49 @@ android {
} }
} }
signingConfigs {
// Override default debug signing config to make sure every CI runner
// uses the same key for painless updates.
def debugKeystorePropertiesFile = rootProject.file('debug-keystore.properties')
if (debugKeystorePropertiesFile.exists()) {
def debugKeystoreProperties = new Properties()
debugKeystoreProperties.load(new FileInputStream(debugKeystorePropertiesFile))
debug {
storeFile rootProject.file(debugKeystoreProperties.getProperty('storeFile'))
storePassword debugKeystoreProperties.getProperty('storePassword')
keyAlias debugKeystoreProperties.getProperty('keyAlias')
keyPassword debugKeystoreProperties.getProperty('keyPassword')
}
}
def releaseKeystoreProperties = new Properties()
def releaseKeystorePropertiesFile = rootProject.file('release-keystore.properties')
if (releaseKeystorePropertiesFile.exists()) {
releaseKeystoreProperties.load(new FileInputStream(releaseKeystorePropertiesFile))
release {
storeFile rootProject.file(releaseKeystoreProperties.getProperty('storeFile'))
storePassword releaseKeystoreProperties.getProperty('storePassword')
keyAlias releaseKeystoreProperties.getProperty('keyAlias')
keyPassword releaseKeystoreProperties.getProperty('keyPassword')
}
}
}
buildTypes { buildTypes {
debug {
// Prevents signing keys clashes between debug and release versions
// for painless development.
applicationIdSuffix '.debug'
}
release { release {
minifyEnabled false minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
// Release signing config is optional and might not be present in CI
// builds, hence `findByName`.
signingConfig signingConfigs.findByName('release')
} }
} }

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">Fallout 2 (Debug)</string>
</resources>

View File

@ -1,3 +1,3 @@
<resources> <resources>
<string name="app_name">Fallout 2 Community Edition</string> <string name="app_name">Fallout 2</string>
</resources> </resources>

View File

@ -1272,6 +1272,11 @@ void _GNW95_process_message()
// The data is accumulated in SDL itself and will be processed // The data is accumulated in SDL itself and will be processed
// in `_mouse_info`. // in `_mouse_info`.
break; break;
case SDL_FINGERDOWN:
case SDL_FINGERMOTION:
case SDL_FINGERUP:
handleTouchFingerEvent(&(e.tfinger));
break;
case SDL_KEYDOWN: case SDL_KEYDOWN:
case SDL_KEYUP: case SDL_KEYUP:
if (!keyboardIsDisabled()) { if (!keyboardIsDisabled()) {

View File

@ -1,6 +1,18 @@
#include "dinput.h" #include "dinput.h"
#include <SDL.h> static int gTouchMouseLastX = 0;
static int gTouchMouseLastY = 0;
static int gTouchMouseDeltaX = 0;
static int gTouchMouseDeltaY = 0;
static int gTouchFingers = 0;
static unsigned int gTouchGestureLastTouchDownTimestamp = 0;
static unsigned int gTouchGestureLastTouchUpTimestamp = 0;
static int gTouchGestureTaps = 0;
static bool gTouchGestureHandled = false;
extern int screenGetWidth();
extern int screenGetHeight();
// 0x4E0400 // 0x4E0400
bool directInputInit() bool directInputInit()
@ -47,9 +59,42 @@ bool mouseDeviceUnacquire()
// 0x4E053C // 0x4E053C
bool mouseDeviceGetData(MouseData* mouseState) bool mouseDeviceGetData(MouseData* mouseState)
{ {
#if __ANDROID__
mouseState->x = gTouchMouseDeltaX;
mouseState->y = gTouchMouseDeltaY;
mouseState->buttons[0] = 0;
mouseState->buttons[1] = 0;
gTouchMouseDeltaX = 0;
gTouchMouseDeltaY = 0;
if (gTouchFingers == 0) {
if (SDL_GetTicks() - gTouchGestureLastTouchUpTimestamp > 150) {
if (!gTouchGestureHandled) {
if (gTouchGestureTaps == 2) {
mouseState->buttons[0] = 1;
gTouchGestureHandled = true;
} else if (gTouchGestureTaps == 3) {
mouseState->buttons[1] = 1;
gTouchGestureHandled = true;
}
}
}
} else if (gTouchFingers == 1) {
if (SDL_GetTicks() - gTouchGestureLastTouchDownTimestamp > 150) {
if (gTouchGestureTaps == 1) {
mouseState->buttons[0] = 1;
gTouchGestureHandled = true;
} else if (gTouchGestureTaps == 2) {
mouseState->buttons[1] = 1;
gTouchGestureHandled = true;
}
}
}
#else
Uint32 buttons = SDL_GetRelativeMouseState(&(mouseState->x), &(mouseState->y)); Uint32 buttons = SDL_GetRelativeMouseState(&(mouseState->x), &(mouseState->y));
mouseState->buttons[0] = (buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; mouseState->buttons[0] = (buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;
mouseState->buttons[1] = (buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; mouseState->buttons[1] = (buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
#endif
return true; return true;
} }
@ -100,3 +145,44 @@ bool keyboardDeviceInit()
void keyboardDeviceFree() void keyboardDeviceFree()
{ {
} }
void handleTouchFingerEvent(SDL_TouchFingerEvent* event)
{
int windowWidth = screenGetWidth();
int windowHeight = screenGetHeight();
if (event->type == SDL_FINGERDOWN) {
gTouchFingers++;
gTouchMouseLastX = (int)(event->x * windowWidth);
gTouchMouseLastY = (int)(event->y * windowHeight);
gTouchMouseDeltaX = 0;
gTouchMouseDeltaY = 0;
if (event->timestamp - gTouchGestureLastTouchDownTimestamp > 250) {
gTouchGestureTaps = 0;
gTouchGestureHandled = false;
}
gTouchGestureLastTouchDownTimestamp = event->timestamp;
} else if (event->type == SDL_FINGERMOTION) {
int prevX = gTouchMouseLastX;
int prevY = gTouchMouseLastY;
gTouchMouseLastX = (int)(event->x * windowWidth);
gTouchMouseLastY = (int)(event->y * windowHeight);
gTouchMouseDeltaX += gTouchMouseLastX - prevX;
gTouchMouseDeltaY += gTouchMouseLastY - prevY;
} else if (event->type == SDL_FINGERUP) {
gTouchFingers--;
int prevX = gTouchMouseLastX;
int prevY = gTouchMouseLastY;
gTouchMouseLastX = (int)(event->x * windowWidth);
gTouchMouseLastY = (int)(event->y * windowHeight);
gTouchMouseDeltaX += gTouchMouseLastX - prevX;
gTouchMouseDeltaY += gTouchMouseLastY - prevY;
gTouchGestureTaps++;
gTouchGestureLastTouchUpTimestamp = event->timestamp;
}
}

View File

@ -1,6 +1,8 @@
#ifndef DINPUT_H #ifndef DINPUT_H
#define DINPUT_H #define DINPUT_H
#include <SDL.h>
typedef struct MouseData { typedef struct MouseData {
int x; int x;
int y; int y;
@ -26,4 +28,6 @@ void mouseDeviceFree();
bool keyboardDeviceInit(); bool keyboardDeviceInit();
void keyboardDeviceFree(); void keyboardDeviceFree();
void handleTouchFingerEvent(SDL_TouchFingerEvent* event);
#endif /* DINPUT_H */ #endif /* DINPUT_H */

View File

@ -40,6 +40,8 @@ int main(int argc, char* argv[])
#endif #endif
#if __ANDROID__ #if __ANDROID__
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
chdir(SDL_AndroidGetExternalStoragePath()); chdir(SDL_AndroidGetExternalStoragePath());
#endif #endif