A typical event loop in System4 game looks like this:
while (true) {
SACT2.Mouse_GetPos(x, y);
// Update the screen according to the mouse position (x, y)
...
SACT2.Update();
if (SACT2.Key_IsDown(VK_LBUTTON)) {
// A button was pressed at (x, y)
...
}
}
This works poorly with touch devices. Assume that a touch event occured
during SACT2.Update(). It updates internal mouse position and button
status. After SACT2.Update(), the game calls SACT2.Key_IsDown(VK_LBUTTON).
It returns true, but the game has not yet called SACT2.Mouse_GetPos()
after the touch event, so it assumes that the button was pressed where
the mouse pointer was before the touch.
In order to avoid this situation, this defers mouse button events
synthesized (by SDL) from touch. Such deferred events are processed when
SACT2.Mouse_GetPos() is called or after 50ms.
Writing save files in RSM format is only enabled if `--save-format=rsm`
command line flag is specified, because this implementation does not
create save files that are fully compatible with the AliceSoft's
implementation:
* There is no simple way to determine the RSM format version used by the
game.
* There are several unknown fields in the RSM format.
* Empty arrays are represented as NULL pages in xsystem4, so type
information of such objects cannot be saved.
These limitations are not a problem for the following use cases:
* Use the created save files only in xsystem4
* Load save files created by System40.exe
Also, RSM save files are much smaller and faster to read and write than
JSON.
BanMisc.{Save,Load}Struct now serializes structs in the same format as
AliceSoft's implementation, rather than in JSON format. The old JSON
format can also be loaded for backwards compatibility.
For some reason, this function is renamed from GetHDDVolumeNumber only
in Momoiro Guardian.
This also makes all Confirm3 functions HLL_QUIET_UNIMPLEMENTED.
* The "type" argument of S_MOD is 48 for bool, 56 for long int
* %b, %c, %d can consume any integer types (int, bool, or long int)
* If the value cannot be consumed, S_MOD should return the format
string instead of an empty string
It is implemented as a post-processing effect. The hack for the
projection transform matrix has been removed, because now the image is
flipped upside down in the post-processing stage.
Some games (Ojou-sama o Iinari ni Suru Game and Double Sensei Life, as
far as I know) pass "SaveData\\MsgSkip.asd" to MsgSkip.Init. So this
change:
* uses savedir_path() to resolve the relative path, and
* removes the "SaveData\\" prefix, otherwise "SaveData/" will be
duplicated in the resolved path.
This also rewrites the SetWindowSetting and GetWindowSetting functions
based on the understanding gained from examining games after Haru Urare:
* Setting IDs are consistent across games.
* Settings 5 and 6 are added in Pastel Chime 3, both default true
This ensures that SystemService.hll mixer functions can only access
mixers specified in System40.ini, even if xsystem4 added more mixers.
Beat Blades Haruka checks the number and names of mixers, and refuses to
open the config screen if they are not as expected.
This implementation supports only single-frame sprites with a single
child object. As far as I know, all Flash effects in AliceSoft games
meet this requirement.
The DefineSound tag in SWF has raw PCM data, so we create a WAV file in-
memory and pass it to audio_play_archive_data(). This is not strictly
necessary since libsndfile can handle raw PCM data, but keeps the audio
and mixer interfaces simple.
TapirEngine is the 3D rendering engine used in RanceQuest.
This implements the minimum functionality that is needed to render the
first battle scene. The lighting is still incorrect.
This SWF parser is far from complete, in particular it only supports
simple bitmap-filled rectangular shapes, but it covers all the features
used in Daiteikoku, Rance Quest, Pastel Chime 3 and Dorapeko.
Flash files are stored in archives in AFF format, which is an encrypted
SWF wrapper. The decryption code was adapted from GARbro.
Text sprites hold the height of the text drawn on them, and
sact_SP_TextNewLine increases the Y coordinate by this value if
nTextSize is 0.
The nTextSize argument of sact_SP_TextHome affects this value.
Beat Blades Haruka depends on this behavior.
xsystem4.scene: returns a list of scene entities
* all entities have an entityId that can be used in further requests
* SACT2 sprites have a 'sprite' member with a spriteId that can be
used in further requests
xsystem4.renderEntity: renders a scene entity and returns the texture
xsystem4.spriteTexture: returns the stored SACT2 sprite texture
xsystem4.renderParts: renders a parts object and returns the texture
xsystem4.partsTexture: returns the stored parts object texture
Image data in texture objects is RGB8888 encoded in base 64.
Transparent objects should be drawn in order from furthest to nearest.
In DrawDungeon, the actual viewpoint is slightly behind the camera, but
this was not taken into account when sorting cells by distance.
Fixes#120
And by extension config.save_dir. This fixes an issue where paths
retrieved by system.GetSaveFolderName and then passed to gamedir_path
would become invalid.
Fixes#115
So far only basic debugging functionality is implemented (breakpoints,
stepping, stack traces/variables).
This is not tested against an established DAP client. My intention is to
create a custom GUI frontend and extend the protocol to support
xsystem4-specific features, such as inspecting the scene. (This work is
underway.)
Instruction references are hex-encoded address strings. Clients do not
need to obtain them from DAP requests. This is outside the spec, but it
is needed for a binary-only debugger.
Functions that write directly to stdout (e.g. printf) should generally
not be used any more. Instead, use either sys_message (which respects
sys_silent) or log_message (which will send the message to the debugger
if DAP is enabled). stderr can be used as normal.
Don't allocate massive textures for each text object. Instead, allocate
a texture for each character and then compose them onto an appropriately
sized texture.
Fixes a performance issue in Rance 01.