mirror of
https://github.com/kichikuou/xsystem35-sdl2.git
synced 2026-09-25 07:58:04 +03:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64edcfda29 |
@@ -2,7 +2,7 @@ name: Emscripten Build
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
EM_VERSION: 3.1.34
|
||||
EM_VERSION: 3.1.27
|
||||
EM_CACHE_FOLDER: 'emsdk-cache'
|
||||
|
||||
jobs:
|
||||
|
||||
+5
-1
@@ -123,10 +123,14 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
||||
list(APPEND SRC_CDROM cdrom.emscripten.c)
|
||||
list(APPEND SUMMARY_CDROM "Emscripten")
|
||||
set(ENABLE_CDROM_EMSCRIPTEN 1)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
list(APPEND SRC_CDROM cdrom.android.c)
|
||||
list(APPEND SUMMARY_CDROM "Android")
|
||||
set(ENABLE_CDROM_ANDROID 1)
|
||||
else()
|
||||
list(APPEND SRC_CDROM cdrom.empty.c)
|
||||
endif()
|
||||
if (SDL2MIXER_FOUND)
|
||||
if (SDL2MIXER_FOUND AND NOT ANDROID)
|
||||
list(APPEND SRC_CDROM cdrom.mp3.c)
|
||||
list(APPEND SUMMARY_CDROM "SDL_mixer (wav|mp3|ogg...)")
|
||||
set(ENABLE_CDROM_MP3 1)
|
||||
|
||||
@@ -16,8 +16,8 @@ android {
|
||||
}
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 31
|
||||
versionCode 14
|
||||
versionName "2.9.0" + gitRevision()
|
||||
versionCode 13
|
||||
versionName "2.8.0" + gitRevision()
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments "-DANDROID_APP_PLATFORM=android-16", "-DANDROID_STL=c++_static"
|
||||
@@ -82,7 +82,6 @@ android {
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
|
||||
}
|
||||
|
||||
static String gitRevision() {
|
||||
|
||||
@@ -37,20 +37,24 @@ class GameActivity : SDLActivity() {
|
||||
}
|
||||
|
||||
private lateinit var gameRoot: File
|
||||
private lateinit var cdda: CddaPlayer
|
||||
private val midi = MidiPlayer()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
gameRoot = File(intent.getStringExtra(EXTRA_GAME_ROOT)!!)
|
||||
cdda = CddaPlayer(File(gameRoot, Launcher.PLAYLIST_FILE))
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
cdda.onActivityStop()
|
||||
midi.onActivityStop()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
cdda.onActivityResume()
|
||||
midi.onActivityResume()
|
||||
}
|
||||
|
||||
@@ -59,9 +63,7 @@ class GameActivity : SDLActivity() {
|
||||
}
|
||||
|
||||
override fun getArguments(): Array<String> {
|
||||
return arrayOf(
|
||||
"-gamedir", intent.getStringExtra(EXTRA_GAME_ROOT)!!,
|
||||
"-devcd", Launcher.PLAYLIST_FILE)
|
||||
return arrayOf("-gamedir", intent.getStringExtra(EXTRA_GAME_ROOT)!!)
|
||||
}
|
||||
|
||||
override fun setTitle(title: CharSequence?) {
|
||||
@@ -118,6 +120,9 @@ class GameActivity : SDLActivity() {
|
||||
}
|
||||
|
||||
// The functions below are called in the SDL thread by JNI.
|
||||
@Suppress("unused") fun cddaStart(track: Int, loop: Boolean) = cdda.start(track, loop)
|
||||
@Suppress("unused") fun cddaStop() = cdda.stop()
|
||||
@Suppress("unused") fun cddaCurrentPosition() = cdda.currentPosition()
|
||||
@Suppress("unused") fun midiStart(path: String, loop: Boolean) = midi.start(path, loop)
|
||||
@Suppress("unused") fun midiStop() = midi.stop()
|
||||
@Suppress("unused") fun midiCurrentPosition() = midi.currentPosition()
|
||||
@@ -151,6 +156,69 @@ class GameActivity : SDLActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private class CddaPlayer(private val playlistPath: File) {
|
||||
private val playlist =
|
||||
try {
|
||||
playlistPath.readLines()
|
||||
} catch (e: IOException) {
|
||||
Log.e("loadPlaylist", "Cannot load $playlistPath", e)
|
||||
emptyList()
|
||||
}
|
||||
private var currentTrack = 0
|
||||
private val player = MediaPlayer()
|
||||
private var playerPaused = false
|
||||
|
||||
fun start(track: Int, loop: Boolean) {
|
||||
val f = playlist.elementAtOrNull(track - 1)
|
||||
if (f.isNullOrEmpty()) {
|
||||
Log.w("cddaStart", "No playlist entry for track $track")
|
||||
return
|
||||
}
|
||||
Log.v("cddaStart", "$f Loop:$loop")
|
||||
try {
|
||||
player.apply {
|
||||
reset()
|
||||
setDataSource(File(playlistPath.parent, f).path)
|
||||
isLooping = loop
|
||||
prepare()
|
||||
start()
|
||||
}
|
||||
currentTrack = track
|
||||
} catch (e: IOException) {
|
||||
Log.e("cddaStart", "Cannot play $f", e)
|
||||
player.reset()
|
||||
}
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
if (currentTrack > 0 && player.isPlaying) {
|
||||
player.stop()
|
||||
currentTrack = 0
|
||||
}
|
||||
}
|
||||
|
||||
fun currentPosition(): Int {
|
||||
if (currentTrack == 0)
|
||||
return 0
|
||||
val frames = player.currentPosition * 75 / 1000
|
||||
return currentTrack or (frames shl 8)
|
||||
}
|
||||
|
||||
fun onActivityStop() {
|
||||
if (currentTrack > 0 && player.isPlaying) {
|
||||
player.pause()
|
||||
playerPaused = true
|
||||
}
|
||||
}
|
||||
|
||||
fun onActivityResume() {
|
||||
if (playerPaused) {
|
||||
player.start()
|
||||
playerPaused = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MidiPlayer {
|
||||
private val player = MediaPlayer()
|
||||
private var playing = false
|
||||
|
||||
@@ -17,13 +17,11 @@
|
||||
*/
|
||||
package io.github.kichikuou.xsystem35
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Message
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.*
|
||||
import java.lang.StringBuilder
|
||||
import java.nio.charset.Charset
|
||||
@@ -42,6 +40,9 @@ interface LauncherObserver {
|
||||
}
|
||||
|
||||
private const val SAVE_DIR = "save"
|
||||
private const val PROGRESS = 0
|
||||
private const val SUCCESS = 1
|
||||
private const val FAILURE = 2
|
||||
|
||||
class Launcher private constructor(private val rootDir: File) {
|
||||
companion object {
|
||||
@@ -73,28 +74,31 @@ class Launcher private constructor(private val rootDir: File) {
|
||||
updateGameList()
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun install(input: InputStream, archiveName: String?) {
|
||||
val dir = createDirForGame()
|
||||
isInstalling = true
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
try {
|
||||
withContext(Dispatchers.IO) {
|
||||
extractFiles(input, dir) { msg ->
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
observer?.onInstallProgress(msg)
|
||||
}
|
||||
@SuppressLint("HandlerLeak")
|
||||
val handler = object : Handler() {
|
||||
override fun handleMessage(msg: Message) {
|
||||
when (msg.what) {
|
||||
PROGRESS -> {
|
||||
observer?.onInstallProgress(msg.obj as String)
|
||||
}
|
||||
SUCCESS -> {
|
||||
isInstalling = false
|
||||
observer?.onInstallSuccess(msg.obj as File, archiveName)
|
||||
}
|
||||
FAILURE -> {
|
||||
isInstalling = false
|
||||
observer?.onInstallFailure(msg.obj as Int)
|
||||
}
|
||||
}
|
||||
observer?.onInstallSuccess(dir, archiveName)
|
||||
} catch (e: InstallFailureException) {
|
||||
observer?.onInstallFailure(e.msgId)
|
||||
} catch (e: Exception) {
|
||||
Log.e("launcher", "Failed to extract ZIP", e)
|
||||
observer?.onInstallFailure(R.string.zip_extraction_error)
|
||||
}
|
||||
isInstalling = false
|
||||
}
|
||||
val t = Thread {
|
||||
extractFiles(input, dir, handler)
|
||||
}
|
||||
t.start()
|
||||
isInstalling = true
|
||||
}
|
||||
|
||||
fun uninstall(id: Int) {
|
||||
@@ -179,26 +183,32 @@ class Launcher private constructor(private val rootDir: File) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractFiles(input: InputStream, outDir: File, progressCallback: (String) -> Unit) {
|
||||
val configWriter = GameConfigWriter()
|
||||
val hadDecodeError = forEachZipEntry(input) { zipEntry, zip ->
|
||||
Log.i("extractFiles", zipEntry.name)
|
||||
val path = File(outDir, zipEntry.name)
|
||||
if (zipEntry.isDirectory)
|
||||
return@forEachZipEntry
|
||||
path.parentFile?.mkdirs()
|
||||
progressCallback(zipEntry.name)
|
||||
FileOutputStream(path).buffered().use {
|
||||
zip.copyTo(it)
|
||||
private fun extractFiles(input: InputStream, outDir: File, handler: Handler) {
|
||||
try {
|
||||
val configWriter = GameConfigWriter()
|
||||
val hadDecodeError = forEachZipEntry(input) { zipEntry, zip ->
|
||||
Log.i("extractFiles", zipEntry.name)
|
||||
val path = File(outDir, zipEntry.name)
|
||||
if (zipEntry.isDirectory)
|
||||
return@forEachZipEntry
|
||||
path.parentFile?.mkdirs()
|
||||
handler.sendMessage(handler.obtainMessage(PROGRESS, zipEntry.name))
|
||||
FileOutputStream(path).buffered().use {
|
||||
zip.copyTo(it)
|
||||
}
|
||||
configWriter.maybeAdd(zipEntry.name)
|
||||
}
|
||||
configWriter.maybeAdd(zipEntry.name)
|
||||
if (!configWriter.readyToWrite()) {
|
||||
val msgId = if (hadDecodeError) R.string.unsupported_zip else R.string.cannot_find_ald
|
||||
handler.sendMessage(handler.obtainMessage(FAILURE, msgId))
|
||||
return
|
||||
}
|
||||
configWriter.write(outDir)
|
||||
handler.sendMessage(handler.obtainMessage(SUCCESS, outDir))
|
||||
} catch (e: IOException) {
|
||||
Log.e("launcher", "Failed to extract ZIP", e)
|
||||
handler.sendMessage(handler.obtainMessage(FAILURE, R.string.zip_extraction_error))
|
||||
}
|
||||
if (!configWriter.readyToWrite()) {
|
||||
if (hadDecodeError)
|
||||
throw InstallFailureException(R.string.unsupported_zip)
|
||||
throw InstallFailureException(R.string.cannot_find_ald)
|
||||
}
|
||||
configWriter.write(outDir)
|
||||
}
|
||||
|
||||
// Xsystem35-sdl2 <=2.2.0 had a bug where playlist had an extra empty line at
|
||||
@@ -209,14 +219,12 @@ class Launcher private constructor(private val rootDir: File) {
|
||||
if (!oldPlaylist.exists())
|
||||
return
|
||||
var tracks = oldPlaylist.readLines()
|
||||
if (tracks.isNotEmpty())
|
||||
if (!tracks.isEmpty())
|
||||
tracks = tracks.subList(1, tracks.size)
|
||||
File(dir, PLAYLIST_FILE).writeText(tracks.joinToString("\n"))
|
||||
oldPlaylist.delete()
|
||||
}
|
||||
|
||||
class InstallFailureException(val msgId: Int) : Exception()
|
||||
|
||||
// A helper class which generates xsystem35.gr and playlist.txt in the game root directory.
|
||||
private class GameConfigWriter {
|
||||
private val grb = StringBuilder()
|
||||
|
||||
@@ -27,7 +27,6 @@ import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.ListView
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import java.io.*
|
||||
|
||||
@@ -35,11 +34,10 @@ private const val CONTENT_TYPE_ZIP = "application/zip"
|
||||
private const val INSTALL_REQUEST = 1
|
||||
private const val SAVEDATA_EXPORT_REQUEST = 2
|
||||
private const val SAVEDATA_IMPORT_REQUEST = 3
|
||||
private const val STATE_PROGRESS_TEXT = "progressText"
|
||||
|
||||
class LauncherActivity : Activity(), LauncherObserver {
|
||||
private lateinit var launcher: Launcher
|
||||
private var progressDialog: Dialog? = null
|
||||
private var progressDialog: ProgressDialogFragment? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -48,7 +46,7 @@ class LauncherActivity : Activity(), LauncherObserver {
|
||||
launcher = Launcher.getInstance(filesDir)
|
||||
launcher.observer = this
|
||||
if (launcher.isInstalling) {
|
||||
showProgressDialog(savedInstanceState)
|
||||
showProgressDialog()
|
||||
}
|
||||
|
||||
onGameListChange()
|
||||
@@ -63,17 +61,9 @@ class LauncherActivity : Activity(), LauncherObserver {
|
||||
|
||||
override fun onDestroy() {
|
||||
launcher.observer = null
|
||||
dismissProgressDialog()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
progressDialog?.let {
|
||||
outState.putCharSequence(STATE_PROGRESS_TEXT, it.findViewById<TextView>(R.id.text).text)
|
||||
}
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
private fun onListItemClick(position: Int) {
|
||||
if (position < launcher.games.size) {
|
||||
startGame(launcher.games[position].path, null)
|
||||
@@ -163,7 +153,7 @@ class LauncherActivity : Activity(), LauncherObserver {
|
||||
}
|
||||
|
||||
override fun onInstallProgress(path: String) {
|
||||
progressDialog?.findViewById<TextView>(R.id.text)?.text = getString(R.string.install_progress, path)
|
||||
progressDialog?.setProgress(getString(R.string.install_progress, path))
|
||||
}
|
||||
|
||||
override fun onInstallSuccess(path: File, archiveName: String?) {
|
||||
@@ -188,17 +178,9 @@ class LauncherActivity : Activity(), LauncherObserver {
|
||||
launcher.uninstall(id)
|
||||
}
|
||||
|
||||
private fun showProgressDialog(savedInstanceState: Bundle? = null) {
|
||||
progressDialog = Dialog(this)
|
||||
progressDialog!!.apply {
|
||||
setTitle(R.string.install_dialog_title)
|
||||
setCancelable(false)
|
||||
setContentView(R.layout.progress_dialog)
|
||||
savedInstanceState?.let {
|
||||
findViewById<TextView>(R.id.text)?.text = it.getCharSequence(STATE_PROGRESS_TEXT)
|
||||
}
|
||||
show()
|
||||
}
|
||||
private fun showProgressDialog() {
|
||||
progressDialog = ProgressDialogFragment()
|
||||
progressDialog!!.show(fragmentManager, "progress_dialog")
|
||||
}
|
||||
|
||||
private fun dismissProgressDialog() {
|
||||
@@ -227,3 +209,18 @@ class LauncherActivity : Activity(), LauncherObserver {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION") // for ProgressDialog
|
||||
class ProgressDialogFragment : DialogFragment() {
|
||||
private lateinit var dialog: ProgressDialog
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
dialog = ProgressDialog(activity)
|
||||
return dialog.apply {
|
||||
setTitle(R.string.install_dialog_title)
|
||||
setCancelable(true)
|
||||
}
|
||||
}
|
||||
fun setProgress(msg: String) {
|
||||
dialog.setMessage(msg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ProgressBar
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textSize="16sp"/>
|
||||
</LinearLayout>
|
||||
@@ -1,7 +1,7 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.7.21'
|
||||
ext.kotlin_version = '1.6.20'
|
||||
repositories {
|
||||
mavenCentral()
|
||||
google()
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#cmakedefine PACKAGE "@PACKAGE@"
|
||||
#define VERSION "2.9.0"
|
||||
#define VERSION "2.8.0"
|
||||
|
||||
#cmakedefine CMAKE_SYSTEM_NAME "@CMAKE_SYSTEM_NAME@"
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ static void cb_waitkey_simple(agsevent_t *e) {
|
||||
switch (e->type) {
|
||||
case AGSEVENT_BUTTON_RELEASE:
|
||||
case AGSEVENT_KEY_RELEASE:
|
||||
night.waitkey = e->code;
|
||||
night.waitkey = e->d3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -59,15 +59,15 @@ void ntev_callback(agsevent_t *e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->type == AGSEVENT_KEY_PRESS && e->code == KEY_CTRL) {
|
||||
if (e->type == AGSEVENT_KEY_PRESS && e->d3 == KEY_CTRL) {
|
||||
night.waitskiplv = 2;
|
||||
night.waitkey = e->code;
|
||||
night.waitkey = e->d3;
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->type == AGSEVENT_KEY_RELEASE && e->code == KEY_CTRL) {
|
||||
if (e->type == AGSEVENT_KEY_RELEASE && e->d3 == KEY_CTRL) {
|
||||
night.waitskiplv = 0;
|
||||
night.waitkey = e->code;
|
||||
night.waitkey = e->d3;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -392,11 +392,13 @@ static void is_in_icon() {
|
||||
|
||||
|
||||
static void cb_keyrelease(agsevent_t *e) {
|
||||
switch (e->code) {
|
||||
int x = e->d1, y = e->d2;
|
||||
|
||||
switch (e->d3) {
|
||||
case AGSEVENT_BUTTON_LEFT:
|
||||
#if 0
|
||||
if (is_in_icon()) {
|
||||
do_icon(e->mousex, e->mousey);
|
||||
do_icon(x, y);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -406,15 +408,19 @@ static void cb_keyrelease(agsevent_t *e) {
|
||||
// unhide();
|
||||
break;
|
||||
}
|
||||
night.waitkey = e->code;
|
||||
night.waitkey = e->d3;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void cb_mousemove(agsevent_t *e) {
|
||||
int x = e->d1, y = e->d2;
|
||||
|
||||
// 音声mute/メッセージスキップ/メッセージ枠消去の領域に
|
||||
// マウスが移動したら、その部分のアイコンを変化させる
|
||||
|
||||
|
||||
}
|
||||
|
||||
// メッセージ表示時に、キー入力を促すアニメーションの設定
|
||||
|
||||
+12
-12
@@ -213,7 +213,7 @@ static void cb_waitkey_simple(agsevent_t *e) {
|
||||
|
||||
switch (e->type) {
|
||||
case AGSEVENT_KEY_PRESS:
|
||||
if (e->code == KEY_Z) {
|
||||
if (e->d3 == KEY_Z) {
|
||||
cur = sdl_getTicks();
|
||||
if (!sact.zhiding) {
|
||||
slist_foreach(sact.sp_zhide, cb_defocused_zkey, &update);
|
||||
@@ -242,7 +242,7 @@ static void cb_waitkey_simple(agsevent_t *e) {
|
||||
// fall through
|
||||
|
||||
case AGSEVENT_KEY_RELEASE:
|
||||
switch(e->code) {
|
||||
switch(e->d3) {
|
||||
case KEY_Z:
|
||||
cur = sdl_getTicks();
|
||||
if (500 < (cur - sact.zofftime) || !sact.zdooff) {
|
||||
@@ -258,7 +258,7 @@ static void cb_waitkey_simple(agsevent_t *e) {
|
||||
sact.waittype = KEYWAIT_BACKLOG;
|
||||
break;
|
||||
default:
|
||||
sact.waitkey = e->code;
|
||||
sact.waitkey = e->d3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -292,7 +292,7 @@ void cb_waitkey_sprite(agsevent_t *e) {
|
||||
// 右クリックキャンセル
|
||||
// drag中でない時のみ、キャンセルを受け付ける
|
||||
if (e->type == AGSEVENT_BUTTON_RELEASE &&
|
||||
e->code == AGSEVENT_BUTTON_RIGHT) {
|
||||
e->d3 == AGSEVENT_BUTTON_RIGHT) {
|
||||
sact.waitkey = 0;
|
||||
return;
|
||||
}
|
||||
@@ -311,7 +311,7 @@ void cb_waitkey_sprite(agsevent_t *e) {
|
||||
// dragg中の sprite は無視する
|
||||
if (sp == sact.draggedsp) continue;
|
||||
|
||||
if (focused_sp == NULL && sp_is_insprite(sp, e->mousex, e->mousey)) {
|
||||
if (focused_sp == NULL && sp_is_insprite(sp, e->d1, e->d2)) {
|
||||
/*
|
||||
focusを得ている sprite
|
||||
*/
|
||||
@@ -388,7 +388,7 @@ static void cb_waitkey_selection(agsevent_t *e) {
|
||||
static void cb_waitkey_backlog(agsevent_t *e) {
|
||||
switch (e->type) {
|
||||
case AGSEVENT_KEY_RELEASE:
|
||||
switch (e->code) {
|
||||
switch (e->d3) {
|
||||
case KEY_ESC:
|
||||
sblog_end();
|
||||
sact.waittype = KEYWAIT_MESSAGE;
|
||||
@@ -409,14 +409,14 @@ static void cb_waitkey_backlog(agsevent_t *e) {
|
||||
break;
|
||||
|
||||
case AGSEVENT_BUTTON_RELEASE:
|
||||
if (e->code == AGSEVENT_BUTTON_RIGHT) {
|
||||
if (e->d3 == AGSEVENT_BUTTON_RIGHT) {
|
||||
sblog_end();
|
||||
sact.waittype = KEYWAIT_MESSAGE;
|
||||
}
|
||||
break;
|
||||
|
||||
case AGSEVENT_MOUSE_WHEEL:
|
||||
if (e->code > 0)
|
||||
if (e->d3 > 0)
|
||||
sblog_pagenext();
|
||||
else
|
||||
sblog_pagepre();
|
||||
@@ -434,15 +434,15 @@ void spev_callback(agsevent_t *e) {
|
||||
}
|
||||
|
||||
if (sact.waittype != KEYWAIT_BACKLOG) {
|
||||
if (e->type == AGSEVENT_KEY_PRESS && e->code == KEY_CTRL) {
|
||||
if (e->type == AGSEVENT_KEY_PRESS && e->d3 == KEY_CTRL) {
|
||||
sact.waitskiplv = 2;
|
||||
sact.waitkey = e->code;
|
||||
sact.waitkey = e->d3;
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->type == AGSEVENT_KEY_RELEASE && e->code == KEY_CTRL) {
|
||||
if (e->type == AGSEVENT_KEY_RELEASE && e->d3 == KEY_CTRL) {
|
||||
sact.waitskiplv = 0;
|
||||
sact.waitkey = e->code;
|
||||
sact.waitkey = e->d3;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,12 +58,12 @@ static int eventCB_GET(sprite_t *sp, agsevent_t *e) {
|
||||
|
||||
switch(e->type) {
|
||||
case AGSEVENT_BUTTON_PRESS:
|
||||
if (e->code != AGSEVENT_BUTTON_LEFT) break;
|
||||
if (e->d3 != AGSEVENT_BUTTON_LEFT) break;
|
||||
|
||||
// drag開始時のマウスの位置記録
|
||||
sp->u.get.dragging = TRUE;
|
||||
sp->u.get.dragstart.x = e->mousex;
|
||||
sp->u.get.dragstart.y = e->mousey;
|
||||
sp->u.get.dragstart.x = e->d1;
|
||||
sp->u.get.dragstart.y = e->d2;
|
||||
|
||||
if (sp->cg3) {
|
||||
sp->curcg = sp->cg3;
|
||||
@@ -104,8 +104,8 @@ static int eventCB_GET(sprite_t *sp, agsevent_t *e) {
|
||||
// if (!sp->u.get.dragging) break;
|
||||
|
||||
// マウスの現在位置により新しい場所を計算
|
||||
newx = sp->loc.x + (e->mousex - sp->u.get.dragstart.x);
|
||||
newy = sp->loc.y + (e->mousey - sp->u.get.dragstart.y);
|
||||
newx = sp->loc.x + (e->d1 - sp->u.get.dragstart.x);
|
||||
newy = sp->loc.y + (e->d2 - sp->u.get.dragstart.y);
|
||||
if (newx != sp->cur.x || newy != sp->cur.y) {
|
||||
sp_updateme(sp);
|
||||
sp->cur.x = newx;
|
||||
|
||||
@@ -135,13 +135,13 @@ int sp_keywait(int *vOK, int *vRND, int *vD01, int *vD02, int *vD03, int timeout
|
||||
{
|
||||
// とりあえず、現在のマウス位置を送って、switch sprite の
|
||||
// 状態を更新しておく
|
||||
agsevent_t agse;
|
||||
MyPoint p;
|
||||
sys_getMouseInfo(&p, FALSE);
|
||||
agsevent_t agse = {
|
||||
.type = AGSEVENT_MOUSE_MOTION,
|
||||
.mousex = p.x,
|
||||
.mousey = p.y
|
||||
};
|
||||
agse.type = AGSEVENT_MOUSE_MOTION;
|
||||
agse.d1 = p.x;
|
||||
agse.d2 = p.y;
|
||||
agse.d3 = 0;
|
||||
spev_callback(&agse);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ static int eventCB_PUT(sprite_t *sp, agsevent_t *e) {
|
||||
|
||||
switch(e->type) {
|
||||
case AGSEVENT_BUTTON_PRESS:
|
||||
if (e->code != AGSEVENT_BUTTON_LEFT) return 0;
|
||||
if (e->d3 != AGSEVENT_BUTTON_LEFT) return 0;
|
||||
|
||||
// ボタン押下時のスプライトがあれば、それを表示
|
||||
if (sp->cg3) {
|
||||
|
||||
@@ -77,7 +77,7 @@ static boolean sp_is_insprite2(sprite_t *sp, int x, int y, int margin) {
|
||||
|
||||
// マウスが移動したときの callback
|
||||
static void cb_select_move(agsevent_t *e) {
|
||||
int x = e->mousex, y = e->mousey;
|
||||
int x = e->d1, y = e->d2;
|
||||
sprite_t *sp = sact.sp[sact.sel.spno];
|
||||
boolean newstate;
|
||||
int newindex;
|
||||
@@ -115,12 +115,12 @@ static void cb_select_move(agsevent_t *e) {
|
||||
|
||||
// ボタンがリリースされたときの callback
|
||||
static void cb_select_release(agsevent_t *e) {
|
||||
int x = e->mousex, y = e->mousey;
|
||||
int x = e->d1, y = e->d2;
|
||||
sprite_t *sp = sact.sp[sact.sel.spno];
|
||||
boolean st;
|
||||
int iy;
|
||||
|
||||
switch (e->code) {
|
||||
switch (e->d3) {
|
||||
case AGSEVENT_BUTTON_LEFT:
|
||||
st = sp_is_insprite2(sp, x, y, sact.sel.frame_dot);
|
||||
iy = (y - (sp->cur.y + sact.sel.frame_dot)) / (sact.sel.font_size + sact.sel.linespace);
|
||||
|
||||
@@ -41,7 +41,7 @@ static int eventCB_switch(sprite_t *sp, agsevent_t *e) {
|
||||
|
||||
switch(e->type) {
|
||||
case AGSEVENT_BUTTON_PRESS:
|
||||
if (e->code != AGSEVENT_BUTTON_LEFT) return 0;
|
||||
if (e->d3 != AGSEVENT_BUTTON_LEFT) return 0;
|
||||
|
||||
// ボタン押下時のスプライトがあれば、それを表示
|
||||
if (sp->cg3) {
|
||||
@@ -53,7 +53,7 @@ static int eventCB_switch(sprite_t *sp, agsevent_t *e) {
|
||||
break;
|
||||
|
||||
case AGSEVENT_BUTTON_RELEASE:
|
||||
if (e->code != AGSEVENT_BUTTON_LEFT) return 0;
|
||||
if (e->d3 != AGSEVENT_BUTTON_LEFT) return 0;
|
||||
|
||||
// ここにくるときは forcusが当たっているときしかこないので、
|
||||
// curcg は cg2 に戻せばよい
|
||||
|
||||
@@ -84,7 +84,6 @@ if (EMSCRIPTEN)
|
||||
"SHELL:-s USE_ZLIB=1"
|
||||
"SHELL:-s USE_SDL=2"
|
||||
"SHELL:-s USE_SDL_TTF=2")
|
||||
target_compile_options(src_lib PRIVATE ${LIBS})
|
||||
target_compile_options(xsystem35 PRIVATE ${LIBS})
|
||||
target_link_options(xsystem35 PRIVATE ${LIBS})
|
||||
target_link_libraries(xsystem35 PRIVATE idbfs.js)
|
||||
@@ -100,7 +99,6 @@ if (EMSCRIPTEN)
|
||||
"SHELL:-s ASYNCIFY_ADD=commands2F60,nact_main,send_agsevent,cb_waitkey_sprite"
|
||||
"SHELL:-s ALLOW_MEMORY_GROWTH=1"
|
||||
"SHELL:-s NO_EXIT_RUNTIME=1"
|
||||
"SHELL:-s EXPORTED_FUNCTIONS=_main,_malloc"
|
||||
"SHELL:-s EXPORTED_RUNTIME_METHODS=getValue,addRunDependency,removeRunDependency")
|
||||
|
||||
elseif (ANDROID)
|
||||
|
||||
@@ -78,27 +78,24 @@ typedef struct agsurface agsurface_t;
|
||||
// for SDL_surface
|
||||
#define PIXEL_AT(suf, x, y) ((suf)->pixels + (y) * (suf)->pitch + (x) * (suf)->format->BytesPerPixel)
|
||||
|
||||
typedef struct {
|
||||
struct _agsevent {
|
||||
int type;
|
||||
int code;
|
||||
int mousex, mousey;
|
||||
} agsevent_t;
|
||||
|
||||
enum agsevent_type {
|
||||
AGSEVENT_MOUSE_MOTION,
|
||||
AGSEVENT_BUTTON_PRESS,
|
||||
AGSEVENT_BUTTON_RELEASE,
|
||||
AGSEVENT_KEY_PRESS,
|
||||
AGSEVENT_KEY_RELEASE,
|
||||
AGSEVENT_TIMER,
|
||||
AGSEVENT_MOUSE_WHEEL,
|
||||
int d1, d2, d3;
|
||||
};
|
||||
typedef struct _agsevent agsevent_t;
|
||||
|
||||
enum agsevent_button {
|
||||
AGSEVENT_BUTTON_LEFT,
|
||||
AGSEVENT_BUTTON_MID,
|
||||
AGSEVENT_BUTTON_RIGHT,
|
||||
};
|
||||
|
||||
#define AGSEVENT_MOUSE_MOTION 1
|
||||
#define AGSEVENT_BUTTON_PRESS 2
|
||||
#define AGSEVENT_BUTTON_RELEASE 3
|
||||
#define AGSEVENT_KEY_PRESS 4
|
||||
#define AGSEVENT_KEY_RELEASE 5
|
||||
#define AGSEVENT_TIMER 6
|
||||
#define AGSEVENT_MOUSE_WHEEL 7
|
||||
|
||||
#define AGSEVENT_BUTTON_LEFT 1
|
||||
#define AGSEVENT_BUTTON_MID 2
|
||||
#define AGSEVENT_BUTTON_RIGHT 3
|
||||
|
||||
enum mouse_warp_mode {
|
||||
MOUSE_WARP_DISABLED,
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2020 <KichikuouChrome@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <SDL.h>
|
||||
#include <jni.h>
|
||||
#include "system.h"
|
||||
#include "portab.h"
|
||||
#include "cdrom.h"
|
||||
|
||||
static int cdrom_init(char *);
|
||||
static int cdrom_exit(void);
|
||||
static int cdrom_reset(void);
|
||||
static int cdrom_start(int, int);
|
||||
static int cdrom_stop();
|
||||
static int cdrom_getPlayingInfo(cd_time *);
|
||||
|
||||
#define cdrom cdrom_android
|
||||
cdromdevice_t cdrom = {
|
||||
cdrom_init,
|
||||
cdrom_exit,
|
||||
cdrom_reset,
|
||||
cdrom_start,
|
||||
cdrom_stop,
|
||||
cdrom_getPlayingInfo,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
int cdrom_init(char *name) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_reset(void) {
|
||||
cdrom_stop();
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_exit(void) {
|
||||
cdrom_stop();
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_start(int trk, int loop) {
|
||||
JNIEnv *env = SDL_AndroidGetJNIEnv();
|
||||
if ((*env)->PushLocalFrame(env, 16) < 0) {
|
||||
WARNING("Failed to allocate JVM local references");
|
||||
return NG;
|
||||
}
|
||||
jobject context = SDL_AndroidGetActivity();
|
||||
jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, context),
|
||||
"cddaStart", "(IZ)V");
|
||||
(*env)->CallVoidMethod(env, context, mid, trk, loop == 0);
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_stop() {
|
||||
JNIEnv *env = SDL_AndroidGetJNIEnv();
|
||||
if ((*env)->PushLocalFrame(env, 16) < 0) {
|
||||
WARNING("Failed to allocate JVM local references");
|
||||
return NG;
|
||||
}
|
||||
jobject context = SDL_AndroidGetActivity();
|
||||
jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, context),
|
||||
"cddaStop", "()V");
|
||||
(*env)->CallVoidMethod(env, context, mid);
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_getPlayingInfo (cd_time *info) {
|
||||
JNIEnv *env = SDL_AndroidGetJNIEnv();
|
||||
if ((*env)->PushLocalFrame(env, 16) < 0) {
|
||||
WARNING("Failed to allocate JVM local references");
|
||||
return NG;
|
||||
}
|
||||
jobject context = SDL_AndroidGetActivity();
|
||||
jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, context),
|
||||
"cddaCurrentPosition", "()I");
|
||||
int t = (*env)->CallIntMethod(env, context, mid);
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
|
||||
info->t = t & 0xff;
|
||||
FRAMES_TO_MSF(t >> 8, &info->m, &info->s, &info->f);
|
||||
return OK;
|
||||
}
|
||||
+6
-2
@@ -43,6 +43,10 @@ extern cdromdevice_t cdrom_bsd;
|
||||
extern cdromdevice_t cdrom_emscripten;
|
||||
#define NATIVE_CD_DEVICE &cdrom_emscripten
|
||||
|
||||
#elif defined(ENABLE_CDROM_ANDROID)
|
||||
extern cdromdevice_t cdrom_android;
|
||||
#define NATIVE_CD_DEVICE &cdrom_android
|
||||
|
||||
#else
|
||||
|
||||
extern cdromdevice_t cdrom_empty;
|
||||
@@ -54,7 +58,7 @@ extern cdromdevice_t cdrom_mp3;
|
||||
#endif
|
||||
|
||||
cdromdevice_t *cd_init(const char *dev) {
|
||||
#if defined(ENABLE_CDROM_EMSCRIPTEN)
|
||||
#if defined(ENABLE_CDROM_EMSCRIPTEN) || defined(ENABLE_CDROM_ANDROID)
|
||||
return NATIVE_CD_DEVICE;
|
||||
#else
|
||||
struct stat st;
|
||||
@@ -67,5 +71,5 @@ cdromdevice_t *cd_init(const char *dev) {
|
||||
WARNING("no cdrom device available");
|
||||
return NULL;
|
||||
#endif
|
||||
#endif // ENABLE_CDROM_EMSCRIPTEN
|
||||
#endif // ENABLE_CDROM_EMSCRIPTEN || ENABLE_CDROM_ANDROID
|
||||
}
|
||||
|
||||
+29
-21
@@ -27,10 +27,39 @@
|
||||
|
||||
static int frame_of_getpos = -1;
|
||||
|
||||
static int cdrom_init(char *);
|
||||
static int cdrom_exit(void);
|
||||
static int cdrom_reset(void);
|
||||
extern int cdrom_start(int, int);
|
||||
extern int cdrom_stop();
|
||||
static int cdrom_getPlayingInfo(cd_time *);
|
||||
|
||||
#define cdrom cdrom_emscripten
|
||||
cdromdevice_t cdrom = {
|
||||
cdrom_init,
|
||||
cdrom_exit,
|
||||
cdrom_reset,
|
||||
cdrom_start,
|
||||
cdrom_stop,
|
||||
cdrom_getPlayingInfo,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
int cdrom_init(char *name) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_exit(void) {
|
||||
cdrom_stop();
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_reset(void) {
|
||||
cdrom_stop();
|
||||
return OK;
|
||||
}
|
||||
|
||||
EM_JS(int, cdrom_start, (int trk, int loop), {
|
||||
xsystem35.cdPlayer.play(trk, loop == 0 ? 1 : 0);
|
||||
return xsystem35.Status.OK;
|
||||
@@ -41,16 +70,6 @@ EM_JS(int, cdrom_stop, (), {
|
||||
return xsystem35.Status.OK;
|
||||
});
|
||||
|
||||
int cdrom_exit(void) {
|
||||
cdrom_stop();
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_reset(void) {
|
||||
cdrom_stop();
|
||||
return OK;
|
||||
}
|
||||
|
||||
int cdrom_getPlayingInfo(cd_time *info) {
|
||||
if (nact->frame_count == frame_of_getpos)
|
||||
nact->wait_vsync = TRUE;
|
||||
@@ -63,14 +82,3 @@ int cdrom_getPlayingInfo(cd_time *info) {
|
||||
FRAMES_TO_MSF(t >> 8, &info->m, &info->s, &info->f);
|
||||
return OK;
|
||||
}
|
||||
|
||||
cdromdevice_t cdrom_emscripten = {
|
||||
cdrom_init,
|
||||
cdrom_exit,
|
||||
cdrom_reset,
|
||||
cdrom_start,
|
||||
cdrom_stop,
|
||||
cdrom_getPlayingInfo,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
+4
-2
@@ -345,8 +345,10 @@ void commandZZ0() {
|
||||
sys_exit(sysVar[0]);
|
||||
#endif
|
||||
} else if (sw == 1) {
|
||||
while (!nact->is_quit)
|
||||
sys_keywait(1000, 0);
|
||||
while (TRUE) {
|
||||
usleep(1000*1000);
|
||||
sys_getInputInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -72,7 +72,7 @@ static void send_json(cJSON *json) {
|
||||
printf("Content-Length: %zu\r\n\r\n%s", strlen(str), str);
|
||||
fflush(stdout);
|
||||
free(str);
|
||||
cJSON_Delete(json);
|
||||
cJSON_free(json);
|
||||
}
|
||||
|
||||
static void emit_initialized_event(void) {
|
||||
@@ -494,7 +494,7 @@ static boolean handle_request(cJSON *request) {
|
||||
if (!cJSON_IsString(command)) {
|
||||
fprintf(stderr, "protocol error: command is not a string\n");
|
||||
// FIXME: return an error response
|
||||
cJSON_Delete(resp);
|
||||
cJSON_free(resp);
|
||||
return continue_repl;
|
||||
}
|
||||
|
||||
@@ -549,7 +549,7 @@ static boolean handle_message(char *msg) {
|
||||
boolean continue_repl = true;
|
||||
if (cJSON_IsString(type) && !strcmp(type->valuestring, "request"))
|
||||
continue_repl = handle_request(json);
|
||||
cJSON_Delete(json);
|
||||
cJSON_free(json);
|
||||
free(msg);
|
||||
return continue_repl;
|
||||
}
|
||||
|
||||
+38
-22
@@ -24,15 +24,43 @@
|
||||
#include "portab.h"
|
||||
#include "midi.h"
|
||||
|
||||
static int midi_initilize(char *pname, int subdev);
|
||||
static int midi_exit(void);
|
||||
static int midi_reset(void);
|
||||
static int midi_start(int no, int loop, char *data, int datalen);
|
||||
static int midi_stop();
|
||||
extern int midi_pause(void);
|
||||
extern int midi_unpause(void);
|
||||
static int midi_get_playing_info(midiplaystate *st);
|
||||
static int midi_getflag(int mode, int index);
|
||||
static int midi_setflag(int mode, int index, int val);
|
||||
extern int midi_setvol(int vol);
|
||||
extern int midi_getvol();
|
||||
extern int midi_fadestart(int time, int volume, int stop);
|
||||
extern boolean midi_fading();
|
||||
|
||||
#define midi midi_emscripten
|
||||
mididevice_t midi = {
|
||||
midi_initilize,
|
||||
midi_exit,
|
||||
midi_reset,
|
||||
midi_start,
|
||||
midi_stop,
|
||||
midi_pause,
|
||||
midi_unpause,
|
||||
midi_get_playing_info,
|
||||
midi_getflag,
|
||||
midi_setflag,
|
||||
midi_setvol,
|
||||
midi_getvol,
|
||||
midi_fadestart,
|
||||
midi_fading
|
||||
};
|
||||
|
||||
static int midi_initilize(char *pname, int subdev) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
EM_JS(int, midi_stop, (void), {
|
||||
xsystem35.midiPlayer.stop();
|
||||
return xsystem35.Status.OK;
|
||||
});
|
||||
|
||||
static int midi_exit(void) {
|
||||
midi_stop();
|
||||
return OK;
|
||||
@@ -48,6 +76,11 @@ static int midi_start(int no, int loop, char *data, int datalen) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int midi_stop() {
|
||||
EM_ASM( xsystem35.midiPlayer.stop(); );
|
||||
return OK;
|
||||
}
|
||||
|
||||
EM_JS(int, midi_pause, (void), {
|
||||
xsystem35.midiPlayer.pause();
|
||||
return xsystem35.Status.OK;
|
||||
@@ -94,20 +127,3 @@ EM_JS(int, midi_fadestart, (int time, int volume, int stop), {
|
||||
EM_JS(boolean, midi_fading, (), {
|
||||
return xsystem35.midiPlayer.isFading();
|
||||
});
|
||||
|
||||
mididevice_t midi_emscripten = {
|
||||
midi_initilize,
|
||||
midi_exit,
|
||||
midi_reset,
|
||||
midi_start,
|
||||
midi_stop,
|
||||
midi_pause,
|
||||
midi_unpause,
|
||||
midi_get_playing_info,
|
||||
midi_getflag,
|
||||
midi_setflag,
|
||||
midi_setvol,
|
||||
midi_getvol,
|
||||
midi_fadestart,
|
||||
midi_fading
|
||||
};
|
||||
|
||||
+212
-18
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -44,6 +45,7 @@ typedef int emscripten_align1_int;
|
||||
#include "message.h"
|
||||
|
||||
const char *save_signature[] = {
|
||||
[SAVEFMT_SYS35] = "This is save data for System3.5 Win95 For NACT/ADV system (C) 1996 ALICE-SOFT",
|
||||
[SAVEFMT_XSYS35] = "System3.5 SavaData(c)ALICE-SOFT",
|
||||
[SAVEFMT_SYS36] = "System3.5 SaveData(c)ALICE-SOFT",
|
||||
[SAVEFMT_SYS38] = "System3.8 SaveData(c)ALICE-SOFT",
|
||||
@@ -113,11 +115,7 @@ typedef struct {
|
||||
emscripten_align1_int rsv2;
|
||||
} asd_varPageHdr;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
static enum save_format save_format = SAVEFMT_XSYS35;
|
||||
#else
|
||||
static enum save_format save_format = SAVEFMT_SYS38;
|
||||
#endif
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EM_JS(void, scheduleSync, (), {
|
||||
@@ -477,19 +475,83 @@ int save_copyAll(int dstno, int srcno) {
|
||||
return status;
|
||||
}
|
||||
|
||||
static int loadpartial_sys35(char *saveTop, int filesize, struct VarRef *vref, int cnt) {
|
||||
if (filesize < 0xb0)
|
||||
return SAVE_LOADERR;
|
||||
cnt = min(cnt, v_sliceSize(vref));
|
||||
int *var = v_resolveRef(vref);
|
||||
|
||||
if (vref->page == 0) {
|
||||
// SysVar section
|
||||
int section_offset = LittleEndian_getDW(saveTop, 0x90);
|
||||
int section_length = LittleEndian_getDW(saveTop, 0x94);
|
||||
if (section_offset + 16 + section_length > filesize)
|
||||
return SAVE_LOADERR;
|
||||
|
||||
int sysvar_count = LittleEndian_getDW(saveTop, section_offset);
|
||||
if (sysvar_count > varPage[0].size)
|
||||
return SAVE_LOADERR; // resizing system page is not supported in sys3.5
|
||||
int offset = section_offset + 16 + vref->index * 2;
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
var[i] = LittleEndian_getW(saveTop, offset);
|
||||
offset += 2;
|
||||
}
|
||||
return SAVE_LOADOK;
|
||||
}
|
||||
// Arrays section
|
||||
int section_offset = LittleEndian_getDW(saveTop, 0xa0);
|
||||
int section_length = LittleEndian_getDW(saveTop, 0xa4);
|
||||
if (section_offset + 16 + section_length > filesize)
|
||||
return SAVE_LOADERR;
|
||||
int page_count = LittleEndian_getDW(saveTop, section_offset + 4);
|
||||
int offset = section_offset + 16;
|
||||
// TODO: section size check
|
||||
for (int i = 0; i < page_count; i++) {
|
||||
int page = LittleEndian_getDW(saveTop, offset); offset += 4;
|
||||
int count = LittleEndian_getDW(saveTop, offset); offset += 4;
|
||||
int content_offset = LittleEndian_getDW(saveTop, offset); offset += 4;
|
||||
offset += 4;
|
||||
if (page != vref->page)
|
||||
continue;
|
||||
// TODO page resize
|
||||
// TODO: section size check
|
||||
content_offset += vref->index * 2;
|
||||
for (int j = 0; j < cnt; j++) {
|
||||
var[j] = LittleEndian_getW(saveTop, content_offset + j * 2);
|
||||
}
|
||||
return SAVE_LOADOK;
|
||||
}
|
||||
return SAVE_LOADERR;
|
||||
}
|
||||
|
||||
/* データの一部ロード */
|
||||
int save_loadPartial(int no, struct VarRef *vref, int cnt) {
|
||||
if (no >= SAVE_MAXNUMBER)
|
||||
return SAVE_SAVEERR;
|
||||
|
||||
cnt = min(cnt, v_sliceSize(vref));
|
||||
int *var = v_resolveRef(vref);
|
||||
|
||||
int status, filesize;
|
||||
char *saveTop = loadGameData(no, &status, &filesize);
|
||||
if (!saveTop)
|
||||
return status;
|
||||
|
||||
if (filesize < 0x60)
|
||||
goto errexit;
|
||||
enum save_format format = (enum save_format)-1;
|
||||
for (int i = 0; i < sizeof(save_signature) / sizeof(save_signature[0]); i++) {
|
||||
if (!strcmp(save_signature[i], saveTop)) {
|
||||
format = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (format < 0) {
|
||||
WARNING("unrecognized save format");
|
||||
goto errexit;
|
||||
}
|
||||
|
||||
if (format == SAVEFMT_SYS35) {
|
||||
int result = loadpartial_sys35(saveTop, filesize, vref, cnt);
|
||||
free(saveTop);
|
||||
return result;
|
||||
}
|
||||
if (filesize <= sizeof(asd_baseHdr))
|
||||
goto errexit;
|
||||
|
||||
@@ -499,6 +561,8 @@ int save_loadPartial(int no, struct VarRef *vref, int cnt) {
|
||||
goto errexit;
|
||||
}
|
||||
|
||||
cnt = min(cnt, v_sliceSize(vref));
|
||||
int *var = v_resolveRef(vref);
|
||||
if (save_base->varSys[vref->page] == 0)
|
||||
goto errexit;
|
||||
|
||||
@@ -519,9 +583,11 @@ int save_loadPartial(int no, struct VarRef *vref, int cnt) {
|
||||
|
||||
/* データの一部セーブ */
|
||||
int save_savePartial(int no, struct VarRef *vref, int cnt) {
|
||||
if (no >= SAVE_MAXNUMBER || !varPage[vref->page].saveflag)
|
||||
if (no >= SAVE_MAXNUMBER) {
|
||||
return SAVE_SAVEERR;
|
||||
|
||||
}
|
||||
if (!varPage[vref->page].saveflag)
|
||||
goto errexit;
|
||||
cnt = min(cnt, v_sliceSize(vref));
|
||||
int *var = v_resolveRef(vref);
|
||||
|
||||
@@ -553,6 +619,125 @@ int save_savePartial(int no, struct VarRef *vref, int cnt) {
|
||||
return SAVE_SAVEERR;
|
||||
}
|
||||
|
||||
static int loadall_sys35(char *saveTop, int filesize) {
|
||||
if (filesize < 0xb0)
|
||||
return SAVE_LOADERR;
|
||||
|
||||
int page = LittleEndian_getDW(saveTop, 0x80);
|
||||
int addr = LittleEndian_getDW(saveTop, 0x84);
|
||||
sl_jmpFar2(page - 1, addr);
|
||||
|
||||
// SysVar section
|
||||
int section_offset = LittleEndian_getDW(saveTop, 0x90);
|
||||
int section_length = LittleEndian_getDW(saveTop, 0x94);
|
||||
if (section_offset + 16 + section_length > filesize)
|
||||
return SAVE_LOADERR;
|
||||
|
||||
int sysvar_count = LittleEndian_getDW(saveTop, section_offset);
|
||||
if (sysvar_count > varPage[0].size)
|
||||
return SAVE_LOADERR; // resizing system page is not supported in sys3.5
|
||||
int offset = section_offset + 16;
|
||||
for (int i = 0; i < sysvar_count; i++) {
|
||||
varPage[0].value[i] = LittleEndian_getW(saveTop, offset);
|
||||
offset += 2;
|
||||
}
|
||||
nact->sel.MsgFontSize = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->msg.MsgFontSize = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
cg_vspPB = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->msg.MsgFontColor = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->sel.MsgFontColor = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->sel.WinFrameColor = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->sel.WinBackgroundColor = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->msg.WinFrameColor = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->msg.WinBackgroundColor = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
int left = section_offset + 16 + section_length - offset;
|
||||
WARNING("0x%x bytes for window info", left);
|
||||
if (left < 0)
|
||||
return SAVE_LOADERR;
|
||||
int win_info_count = left / 32;
|
||||
if (win_info_count >= SELWINMAX)
|
||||
return SAVE_LOADERR;
|
||||
for (int i = 1; i <= win_info_count; i++) {
|
||||
offset += 2;
|
||||
nact->sel.wininfo[i].x = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->sel.wininfo[i].y = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
int ex = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
int ey = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->sel.wininfo[i].width = ex + 1 - nact->sel.wininfo[i].x;
|
||||
nact->sel.wininfo[i].height = ey + 1 - nact->sel.wininfo[i].y;
|
||||
offset += 6;
|
||||
}
|
||||
for (int i = 1; i <= win_info_count; i++) {
|
||||
offset += 2;
|
||||
nact->msg.wininfo[i].x = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->msg.wininfo[i].y = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
int ex = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
int ey = LittleEndian_getW(saveTop, offset); offset += 2;
|
||||
nact->msg.wininfo[i].width = ex + 1 - nact->msg.wininfo[i].x;
|
||||
nact->msg.wininfo[i].height = ey + 1 - nact->msg.wininfo[i].y;
|
||||
offset += 6;
|
||||
}
|
||||
//assert(offset == section_offset + 16 + section_length);
|
||||
|
||||
// Strings section
|
||||
section_offset = LittleEndian_getDW(saveTop, 0x98);
|
||||
section_length = LittleEndian_getDW(saveTop, 0x9c);
|
||||
if (section_offset + 16 + section_length > filesize)
|
||||
return SAVE_LOADERR;
|
||||
|
||||
int strvar_count = LittleEndian_getDW(saveTop, section_offset);
|
||||
int strvar_length = LittleEndian_getDW(saveTop, section_offset + 4);
|
||||
offset = section_offset + 16;
|
||||
if (section_length != strvar_count * strvar_length)
|
||||
return SAVE_LOADERR;
|
||||
if (strvar_count > svar_maxindex())
|
||||
strvar_count = svar_maxindex();
|
||||
char *buf = malloc(strvar_length + 1);
|
||||
buf[strvar_length] = '\0';
|
||||
for (int i = 1; i <= strvar_count; i++) {
|
||||
memcpy(buf, saveTop + offset, strvar_length);
|
||||
svar_set(i, buf);
|
||||
offset += strvar_length;
|
||||
}
|
||||
|
||||
// Arrays section
|
||||
section_offset = LittleEndian_getDW(saveTop, 0xa0);
|
||||
section_length = LittleEndian_getDW(saveTop, 0xa4);
|
||||
if (section_offset + 16 + section_length > filesize)
|
||||
return SAVE_LOADERR;
|
||||
|
||||
int array_total_size = LittleEndian_getDW(saveTop, section_offset);
|
||||
int page_count = LittleEndian_getDW(saveTop, section_offset + 4);
|
||||
offset = section_offset + 16;
|
||||
// TODO: section size check
|
||||
int total = 0;
|
||||
for (int i = 0; i < page_count; i++) {
|
||||
int page = LittleEndian_getDW(saveTop, offset); offset += 4;
|
||||
int count = LittleEndian_getDW(saveTop, offset); offset += 4;
|
||||
int content_offset = LittleEndian_getDW(saveTop, offset); offset += 4;
|
||||
offset += 4;
|
||||
total += count;
|
||||
// TODO page resize
|
||||
// TODO: section size check
|
||||
for (int j = 0; j < count; j++) {
|
||||
varPage[page].value[j] = LittleEndian_getW(saveTop, content_offset + j * 2);
|
||||
}
|
||||
}
|
||||
if (total != array_total_size) {
|
||||
WARNING("wrong array total size");
|
||||
} else {
|
||||
WARNING("correct array total size");
|
||||
}
|
||||
|
||||
// Stack section
|
||||
section_offset = LittleEndian_getDW(saveTop, 0xa8);
|
||||
section_length = LittleEndian_getDW(saveTop, 0xac);
|
||||
if (section_offset + section_length > filesize)
|
||||
return SAVE_LOADERR;
|
||||
|
||||
sl_loadStack(SAVEFMT_SYS35, saveTop + section_offset, section_length);
|
||||
return SAVE_LOADOK;
|
||||
}
|
||||
|
||||
/* データのロード */
|
||||
int save_loadAll(int no) {
|
||||
@@ -563,17 +748,11 @@ int save_loadAll(int no) {
|
||||
char *saveTop = loadGameData(no, &status, &filesize);
|
||||
if (!saveTop)
|
||||
return status;
|
||||
if (filesize <= sizeof(asd_baseHdr))
|
||||
if (filesize < 0x60)
|
||||
goto errexit;
|
||||
/* 各種データの反映 */
|
||||
asd_baseHdr *save_base = (asd_baseHdr *)saveTop;
|
||||
if (save_base->version != SAVE_DATAVERSION) {
|
||||
WARNING("endian mismatch");
|
||||
goto errexit;
|
||||
}
|
||||
enum save_format format = (enum save_format)-1;
|
||||
for (int i = 0; i < sizeof(save_signature) / sizeof(save_signature[0]); i++) {
|
||||
if (!strcmp(save_signature[i], save_base->ID)) {
|
||||
if (!strcmp(save_signature[i], saveTop)) {
|
||||
format = i;
|
||||
break;
|
||||
}
|
||||
@@ -583,6 +762,21 @@ int save_loadAll(int no) {
|
||||
goto errexit;
|
||||
}
|
||||
|
||||
if (format == SAVEFMT_SYS35) {
|
||||
int result = loadall_sys35(saveTop, filesize);
|
||||
free(saveTop);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (filesize <= sizeof(asd_baseHdr))
|
||||
goto errexit;
|
||||
/* 各種データの反映 */
|
||||
asd_baseHdr *save_base = (asd_baseHdr *)saveTop;
|
||||
if (save_base->version != SAVE_DATAVERSION) {
|
||||
WARNING("endian mismatch");
|
||||
goto errexit;
|
||||
}
|
||||
|
||||
nact->sel.MsgFontSize = save_base->selMsgSize;
|
||||
nact->sel.MsgFontColor = save_base->selMsgColor;
|
||||
nact->sel.WinBackgroundColor = save_base->selBackColor;
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
enum save_format {
|
||||
SAVEFMT_XSYS35,
|
||||
SAVEFMT_SYS35, // System3.5 v1.x
|
||||
SAVEFMT_SYS36, // System3.5 v2.x - System3.6
|
||||
SAVEFMT_SYS38, // System3.8 - System3.9
|
||||
};
|
||||
|
||||
+121
-36
@@ -354,7 +354,7 @@ void sl_popVar(struct VarRef *vref, int cnt) {
|
||||
}
|
||||
}
|
||||
|
||||
enum save_stack_frame_type {
|
||||
enum xsys35_stack_frame_type {
|
||||
SAVE_NEARJMP = 1,
|
||||
SAVE_FARJMP = 2,
|
||||
SAVE_VARIABLE = 3,
|
||||
@@ -367,15 +367,15 @@ enum txx_type {
|
||||
TxxTEXTLOC = 3
|
||||
};
|
||||
|
||||
struct save_stack_frame {
|
||||
struct save_stack_frame *next;
|
||||
struct xsys35_stack_frame {
|
||||
struct xsys35_stack_frame *next;
|
||||
int len;
|
||||
int buf[];
|
||||
};
|
||||
|
||||
struct save_stack_frame *push_save_stack_frame(int size, struct save_stack_frame *next) {
|
||||
struct save_stack_frame *f =
|
||||
malloc(sizeof(struct save_stack_frame) + sizeof(int) * size);
|
||||
struct xsys35_stack_frame *push_xsys35_stack_frame(int size, struct xsys35_stack_frame *next) {
|
||||
struct xsys35_stack_frame *f =
|
||||
malloc(sizeof(struct xsys35_stack_frame) + sizeof(int) * size);
|
||||
f->next = next;
|
||||
f->len = size;
|
||||
return f;
|
||||
@@ -391,13 +391,13 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
}
|
||||
|
||||
// Serialize to the stack format used in old versions of xsystem35.
|
||||
struct save_stack_frame *frame = NULL;
|
||||
struct xsys35_stack_frame *frame = NULL;
|
||||
uint8_t *sp = stack_top;
|
||||
while (sp > stack_buf) {
|
||||
switch (sp[-1]) {
|
||||
case STACK_FARCALL:
|
||||
sp -= 7;
|
||||
frame = push_save_stack_frame(4, frame);
|
||||
frame = push_xsys35_stack_frame(4, frame);
|
||||
frame->buf[3] = SAVE_FARJMP;
|
||||
frame->buf[2] = 2;
|
||||
frame->buf[1] = LittleEndian_getW(sp, 0) - 1; // page
|
||||
@@ -405,7 +405,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
break;
|
||||
case STACK_NEARCALL:
|
||||
sp -= 5;
|
||||
frame = push_save_stack_frame(3, frame);
|
||||
frame = push_xsys35_stack_frame(3, frame);
|
||||
frame->buf[2] = SAVE_NEARJMP;
|
||||
frame->buf[1] = 1;
|
||||
frame->buf[0] = LittleEndian_getDW(sp, 0); // addr
|
||||
@@ -422,7 +422,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
int base = frame->buf[frame->len - 4];
|
||||
// Merge into existing SAVE_VARIABLE frame.
|
||||
if (page == fpage && index == base - 1) {
|
||||
frame = realloc(frame, sizeof(struct save_stack_frame) + sizeof(int) * (frame->len + 1));
|
||||
frame = realloc(frame, sizeof(struct xsys35_stack_frame) + sizeof(int) * (frame->len + 1));
|
||||
frame->len++;
|
||||
frame->buf[frame->len - 1] = SAVE_VARIABLE;
|
||||
frame->buf[frame->len - 2] = count + 1;
|
||||
@@ -432,7 +432,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
frame = push_save_stack_frame(5, frame);
|
||||
frame = push_xsys35_stack_frame(5, frame);
|
||||
frame->buf[4] = SAVE_VARIABLE;
|
||||
frame->buf[3] = 3;
|
||||
frame->buf[2] = page;
|
||||
@@ -442,7 +442,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
break;
|
||||
case STACK_TEXTCOLOR:
|
||||
sp -= 3;
|
||||
frame = push_save_stack_frame(5, frame);
|
||||
frame = push_xsys35_stack_frame(5, frame);
|
||||
frame->buf[4] = SAVE_TXXSTATE;
|
||||
frame->buf[3] = 3;
|
||||
frame->buf[2] = TxxTEXTCOLOR;
|
||||
@@ -451,7 +451,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
break;
|
||||
case STACK_TEXTSIZE:
|
||||
sp -= 6;
|
||||
frame = push_save_stack_frame(5, frame);
|
||||
frame = push_xsys35_stack_frame(5, frame);
|
||||
frame->buf[4] = SAVE_TXXSTATE;
|
||||
frame->buf[3] = 3;
|
||||
frame->buf[2] = TxxTEXTSIZE;
|
||||
@@ -460,7 +460,7 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
break;
|
||||
case STACK_TEXTLOC:
|
||||
sp -= 9;
|
||||
frame = push_save_stack_frame(5, frame);
|
||||
frame = push_xsys35_stack_frame(5, frame);
|
||||
frame->buf[4] = SAVE_TXXSTATE;
|
||||
frame->buf[3] = 3;
|
||||
frame->buf[2] = TxxTEXTLOC;
|
||||
@@ -472,15 +472,15 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
}
|
||||
}
|
||||
int total_len = 0;
|
||||
for (struct save_stack_frame *f = frame; f; f = f->next)
|
||||
for (struct xsys35_stack_frame *f = frame; f; f = f->next)
|
||||
total_len += f->len;
|
||||
|
||||
int *buf = malloc(total_len * sizeof(int));
|
||||
int *p = buf;
|
||||
for (struct save_stack_frame *f = frame; f;) {
|
||||
for (struct xsys35_stack_frame *f = frame; f;) {
|
||||
memcpy(p, f->buf, f->len * sizeof(int));
|
||||
p += f->len;
|
||||
struct save_stack_frame *next = f->next;
|
||||
struct xsys35_stack_frame *next = f->next;
|
||||
free(f);
|
||||
f = next;
|
||||
}
|
||||
@@ -510,36 +510,22 @@ uint8_t *sl_saveStack(enum save_format format, int *size_out) {
|
||||
return (uint8_t *)buf;
|
||||
}
|
||||
|
||||
void sl_loadStack(enum save_format format, uint8_t *unaligned_data, int size) {
|
||||
if (format != SAVEFMT_XSYS35) {
|
||||
if (size > stack_size) {
|
||||
while (size > stack_size)
|
||||
stack_size *= 2;
|
||||
free(stack_buf);
|
||||
stack_buf = malloc(stack_size);
|
||||
if (!stack_buf)
|
||||
NOMEMERR();
|
||||
}
|
||||
memcpy(stack_buf, unaligned_data, size);
|
||||
stack_top = stack_buf + size;
|
||||
return;
|
||||
}
|
||||
|
||||
static void load_stack_xsys35(uint8_t *unaligned_data, int size) {
|
||||
// Deserialize from the stack format used in old versions of xsystem35.
|
||||
int *data = malloc(size);
|
||||
memcpy(data, unaligned_data, size);
|
||||
struct save_stack_frame *frame = NULL;
|
||||
struct xsys35_stack_frame *frame = NULL;
|
||||
|
||||
for (int *p = data + size / sizeof(int); p > data;) {
|
||||
int len = p[-2] + 2;
|
||||
p -= len;
|
||||
frame = push_save_stack_frame(len, frame);
|
||||
frame = push_xsys35_stack_frame(len, frame);
|
||||
memcpy(frame->buf, p, len * sizeof(int));
|
||||
}
|
||||
free(data);
|
||||
|
||||
stack_top = stack_buf;
|
||||
for (struct save_stack_frame *f = frame; f;) {
|
||||
for (struct xsys35_stack_frame *f = frame; f;) {
|
||||
switch (f->buf[f->len - 1]) {
|
||||
case SAVE_NEARJMP:
|
||||
if (f->len != 3)
|
||||
@@ -601,12 +587,111 @@ void sl_loadStack(enum save_format format, uint8_t *unaligned_data, int size) {
|
||||
default:
|
||||
SYSERROR("broken stack data");
|
||||
}
|
||||
struct save_stack_frame *next = f->next;
|
||||
struct xsys35_stack_frame *next = f->next;
|
||||
free(f);
|
||||
f = next;
|
||||
}
|
||||
}
|
||||
|
||||
struct asdv1_stack_frame {
|
||||
struct asdv1_stack_frame *next;
|
||||
int len;
|
||||
uint8_t buf[];
|
||||
};
|
||||
|
||||
struct asdv1_stack_frame *push_asdv1_stack_frame(int size, struct asdv1_stack_frame *next) {
|
||||
struct asdv1_stack_frame *f =
|
||||
malloc(sizeof(struct asdv1_stack_frame) + size);
|
||||
f->next = next;
|
||||
f->len = size;
|
||||
return f;
|
||||
}
|
||||
|
||||
static void load_stack_sys35(uint8_t *data, int size) {
|
||||
struct asdv1_stack_frame *frame = NULL;
|
||||
for (uint8_t *p = data + size; p > data;) {
|
||||
int frame_size = 0;
|
||||
switch (p[-1]) {
|
||||
case STACK_FARCALL:
|
||||
frame_size = 13;
|
||||
break;
|
||||
case 0xee:
|
||||
frame_size = 5;
|
||||
break;
|
||||
case 0xdd:
|
||||
frame_size = LittleEndian_getW(p, -3) * 2 + 5;
|
||||
break;
|
||||
}
|
||||
if (!frame_size)
|
||||
break; // System3.5 save files has some junk data at the stack bottom.
|
||||
p -= frame_size;
|
||||
frame = push_asdv1_stack_frame(frame_size, frame);
|
||||
memcpy(frame->buf, p, frame_size);
|
||||
}
|
||||
|
||||
stack_top = stack_buf;
|
||||
for (struct asdv1_stack_frame *f = frame; f;) {
|
||||
switch (f->buf[f->len - 1]) {
|
||||
case STACK_FARCALL:
|
||||
stack_reserve(2 + 4 + 1);
|
||||
if (LittleEndian_getDW(f->buf, 0) != 0)
|
||||
WARNING("unexpected stack structure");
|
||||
stack_push_word(LittleEndian_getDW(f->buf, 4));
|
||||
stack_push_dword(LittleEndian_getDW(f->buf, 8));
|
||||
stack_push_byte(STACK_FARCALL);
|
||||
break;
|
||||
case STACK_NEARCALL:
|
||||
stack_reserve(4 + 1);
|
||||
stack_push_dword(LittleEndian_getDW(f->buf, 0));
|
||||
stack_push_byte(STACK_NEARCALL);
|
||||
break;
|
||||
case STACK_VARIABLE:
|
||||
{
|
||||
int count = LittleEndian_getW(f->buf, f->len - 3);
|
||||
int base = LittleEndian_getW(f->buf, f->len - 5);
|
||||
stack_reserve((2 + 2 + 2 + 1) * count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
stack_push_word(base + 1);
|
||||
stack_push_word(0); // page
|
||||
stack_push_word(LittleEndian_getW(f->buf, i * 2));
|
||||
stack_push_byte(STACK_VARIABLE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
struct asdv1_stack_frame *next = f->next;
|
||||
free(f);
|
||||
f = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void load_stack_sys39(uint8_t *data, int size) {
|
||||
if (size > stack_size) {
|
||||
while (size > stack_size)
|
||||
stack_size *= 2;
|
||||
free(stack_buf);
|
||||
stack_buf = malloc(stack_size);
|
||||
if (!stack_buf)
|
||||
NOMEMERR();
|
||||
}
|
||||
memcpy(stack_buf, data, size);
|
||||
stack_top = stack_buf + size;
|
||||
}
|
||||
|
||||
void sl_loadStack(enum save_format format, uint8_t *unaligned_data, int size) {
|
||||
switch (format) {
|
||||
case SAVEFMT_XSYS35:
|
||||
load_stack_xsys35(unaligned_data, size);
|
||||
break;
|
||||
case SAVEFMT_SYS35:
|
||||
load_stack_sys35(unaligned_data, size);
|
||||
break;
|
||||
default:
|
||||
load_stack_sys39(unaligned_data, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sl_getStackInfo(struct stack_info *info) {
|
||||
memset(info, 0, sizeof(struct stack_info));
|
||||
|
||||
|
||||
+20
-61
@@ -45,12 +45,6 @@
|
||||
static void sdl_getEvent(void);
|
||||
static void keyEventProsess(SDL_KeyboardEvent *e, boolean pressed);
|
||||
|
||||
static uint32_t custom_event_type = (uint32_t)-1;
|
||||
|
||||
enum CustomEventCode {
|
||||
SIMULATE_RIGHT_BUTTON,
|
||||
};
|
||||
|
||||
/* pointer の状態 */
|
||||
static int mousex, mousey, mouseb;
|
||||
static int mouse_wheel_up, mouse_wheel_down;
|
||||
@@ -59,11 +53,6 @@ boolean RawKeyInfo[256];
|
||||
/* SDL Joystick */
|
||||
static int joyinfo=0;
|
||||
|
||||
void sdl_event_init(void) {
|
||||
if (custom_event_type == (uint32_t)-1)
|
||||
custom_event_type = SDL_RegisterEvents(1);
|
||||
}
|
||||
|
||||
static int mouse_to_rawkey(int button) {
|
||||
switch(button) {
|
||||
case SDL_BUTTON_LEFT:
|
||||
@@ -89,16 +78,20 @@ static int mouse_to_agsevent(int button) {
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
void send_agsevent(enum agsevent_type type, int code) {
|
||||
void send_agsevent(int type, int code) {
|
||||
if (!nact->ags.eventcb)
|
||||
return;
|
||||
agsevent_t agse = {
|
||||
.type = type,
|
||||
.code = code,
|
||||
.mousex = mousex,
|
||||
.mousey = mousey
|
||||
};
|
||||
agsevent_t agse;
|
||||
agse.type = type;
|
||||
agse.d1 = mousex;
|
||||
agse.d2 = mousey;
|
||||
agse.d3 = code;
|
||||
nact->ags.eventcb(&agse); // Async in emscripten
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// HACK: this ensures that callers of this function are instrumented.
|
||||
emscripten_sleep(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Improves map navigation of Rance4 v2. See also the function comment of
|
||||
@@ -198,41 +191,34 @@ static void sdl_getEvent(void) {
|
||||
mouseb |= 1 << SDL_BUTTON_RIGHT;
|
||||
RawKeyInfo[mouse_to_rawkey(SDL_BUTTON_LEFT)] = FALSE;
|
||||
RawKeyInfo[mouse_to_rawkey(SDL_BUTTON_RIGHT)] = TRUE;
|
||||
send_agsevent(AGSEVENT_BUTTON_PRESS, AGSEVENT_BUTTON_RIGHT);
|
||||
} else {
|
||||
// SDL_RendererEventWatch clamps touch locations outside of the
|
||||
// viewport to 0.0-1.0. Treat such events as right-clicks.
|
||||
int button;
|
||||
if (e.tfinger.x == 0.0f || e.tfinger.x == 1.0f || e.tfinger.y == 0.0f || e.tfinger.y == 1.0f) {
|
||||
button = SDL_BUTTON_RIGHT;
|
||||
if (e.tfinger.x == 0.0f || e.tfinger.x == 1.0f || e.tfinger.y == 0.0f || e.tfinger.y == 1.0f) {
|
||||
mouseb |= 1 << SDL_BUTTON_RIGHT;
|
||||
RawKeyInfo[mouse_to_rawkey(SDL_BUTTON_RIGHT)] = TRUE;
|
||||
} else {
|
||||
button = SDL_BUTTON_LEFT;
|
||||
mousex = e.tfinger.x * view_w;
|
||||
mousey = e.tfinger.y * view_h;
|
||||
send_agsevent(AGSEVENT_MOUSE_MOTION, 0);
|
||||
mouseb |= 1 << SDL_BUTTON_LEFT;
|
||||
RawKeyInfo[mouse_to_rawkey(SDL_BUTTON_LEFT)] = TRUE;
|
||||
}
|
||||
mouseb |= 1 << button;
|
||||
RawKeyInfo[mouse_to_rawkey(button)] = TRUE;
|
||||
send_agsevent(AGSEVENT_BUTTON_PRESS, mouse_to_agsevent(button));
|
||||
mousex = e.tfinger.x * view_w;
|
||||
mousey = e.tfinger.y * view_h;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_FINGERUP:
|
||||
if (SDL_GetNumTouchFingers(e.tfinger.touchId) == 0) {
|
||||
int ags_button = (mouseb & 1 << SDL_BUTTON_LEFT) ? AGSEVENT_BUTTON_LEFT : AGSEVENT_BUTTON_RIGHT;
|
||||
mouseb &= ~(1 << SDL_BUTTON_LEFT | 1 << SDL_BUTTON_RIGHT);
|
||||
RawKeyInfo[mouse_to_rawkey(SDL_BUTTON_LEFT)] = FALSE;
|
||||
RawKeyInfo[mouse_to_rawkey(SDL_BUTTON_RIGHT)] = FALSE;
|
||||
mousex = e.tfinger.x * view_w;
|
||||
mousey = e.tfinger.y * view_h;
|
||||
send_agsevent(AGSEVENT_BUTTON_RELEASE, ags_button);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_FINGERMOTION:
|
||||
mousex = e.tfinger.x * view_w;
|
||||
mousey = e.tfinger.y * view_h;
|
||||
send_agsevent(AGSEVENT_MOUSE_MOTION, 0);
|
||||
break;
|
||||
|
||||
case SDL_JOYDEVICEADDED:
|
||||
@@ -279,22 +265,9 @@ static void sdl_getEvent(void) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (e.type == custom_event_type) {
|
||||
switch (e.user.code) {
|
||||
case SIMULATE_RIGHT_BUTTON:
|
||||
if ((intptr_t)e.user.data1) {
|
||||
mouseb |= 1 << SDL_BUTTON_RIGHT;
|
||||
RawKeyInfo[KEY_MOUSE_RIGHT] = TRUE;
|
||||
send_agsevent(AGSEVENT_BUTTON_PRESS, AGSEVENT_BUTTON_RIGHT);
|
||||
} else {
|
||||
mouseb &= ~(1 << SDL_BUTTON_RIGHT);
|
||||
RawKeyInfo[KEY_MOUSE_RIGHT] = FALSE;
|
||||
send_agsevent(AGSEVENT_BUTTON_RELEASE, AGSEVENT_BUTTON_RIGHT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
NOTICE("ev %x", e.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -367,17 +340,3 @@ int sdl_getJoyInfo(void) {
|
||||
sdl_getEvent();
|
||||
return joyinfo;
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EMSCRIPTEN_KEEPALIVE
|
||||
void simulate_right_button(int pressed) {
|
||||
SDL_Event event = {
|
||||
.user = {
|
||||
.type = custom_event_type,
|
||||
.code = SIMULATE_RIGHT_BUTTON,
|
||||
.data1 = (void*)pressed
|
||||
}
|
||||
};
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -52,7 +52,6 @@ struct sdl_private_data {
|
||||
boolean (*custom_event_handler)(const SDL_Event *);
|
||||
};
|
||||
|
||||
void sdl_event_init(void);
|
||||
void sdl_cursor_init(void);
|
||||
void sdl_shadow_init(void);
|
||||
int sdl_nearest_color(int r, int g, int b);
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ int sdl_Initialize(const char *render_driver) {
|
||||
/* offscreen Pixmap */
|
||||
makeDIB(SYS35_DEFAULT_WIDTH, SYS35_DEFAULT_HEIGHT, SYS35_DEFAULT_DEPTH);
|
||||
|
||||
sdl_event_init();
|
||||
/* init cursor */
|
||||
sdl_cursor_init();
|
||||
|
||||
sdl_setWindowSize(SYS35_DEFAULT_WIDTH, SYS35_DEFAULT_HEIGHT);
|
||||
|
||||
+1
-1
@@ -111,7 +111,7 @@ static void sys35_usage(boolean verbose) {
|
||||
puts("OPTIONS");
|
||||
puts(" -gamefile file : set game resource file to 'file'");
|
||||
puts(" -game game : enable game-specific hacks");
|
||||
puts(" -saveformat fmt : save file format. 'xsystem35', 'system36' or 'system39' (default)");
|
||||
puts(" -saveformat fmt : save file format. 'xsystem35' (default), 'system36' or 'system39'");
|
||||
puts(" -renderer name : set rendering driver name to 'name'");
|
||||
puts(" -devcd device : set cdrom device name to 'device'");
|
||||
puts(" -devmidi device : set midi device name to 'device'");
|
||||
|
||||
Reference in New Issue
Block a user