Texture.dtl contains multiple sets of wall, floor, and ceiling texture
images. dtx_load_from_dtl() randomly selects a texture set using the
floor number as the random seed and returns it as a dtx structure.
In DrawDungeon2, dungeons are generated randomly using a dedicated
random number generator (mtrand43.c), which is a Mersenne Twister with
N=4, M=3.
The entry point for map generation is dgn_generate_drawdungeon2(),
which deterministically generates a floor map using the floor number as
the random seed.
I verified that generated floor layout, player starting position,
exit, and treasure chest locations match the original DrawDungeon2.dll
up to the 1000th floor.
Some classes in Dungeons & Dolls serialize themselves using
`File.Write(this)` in their destructors. Because `File.Write` takes the
argument by value, a copy of `this` is created. If the destructor is
called on the copied `this`, it falls into an an infinite loop.
It provides 64-bit calculation functions with virtual registers.
While the original CalcTable.dll accumulates instructions and executes
them with CalcTable.Run(), this implementation performs calculations on
the fly. This simplification is possible because Run() is only called
with loop=1.
`system.Error()` is used for critical errors, so its message should be
presented to the user.
This makes system.Error() show a message box, allowing users to choose
between stopping execution or continuing.
This fixes https://github.com/kichikuou/xsystem4-android/issues/14.
There appears to be a bug in the OpenGL ES implementation for PowerVR
that prevents row_major mat4x3 uniforms from loading correctly.
This changes bone_matrices from row_major mat4x3 to column_major mat3x4
and transposes them manually in the vertex shaders. (Column major mat4x3
cannot be used due to the UBO size limitation)
The `defines` string in load_shader() is prepended to the glsl file, but
it was not terminated with a newline, so the resulting shader source
looked like this:
#define REIGN_ENGINE 0
#define TAPIR_ENGINE 1
#define ENGINE 1/* Copyright (C) ...
*
* This program is free software; ...
...
This confused some OpenGL ES implementations, causing a syntax error.
https://github.com/kichikuou/xsystem4-android/issues/15
- Only apply percent encoding on non-Windows platforms in OpenPlayingManual
- Windows uses ShellExecuteW which doesn't work with percent-encoded paths
- Unix platforms still use percent encoding for proper URL handling
- Fixes manual opening functionality on Windows systems
- Add percent_encode() function to properly encode URLs for SDL_OpenURL
- Removed not needed null check on filename
- Update SystemService_OpenPlayingManual to use percent encoding on file paths
Marking Rance Quest and Rance Quest Magnum as supported.
I was able to clear Rance Quest Magnum Integrated Edition (TADA patch
v3.86E) without any issues.
I have only played the first few quests of the original Rance Quest, but
I think it is safe to say that it works.
Fixes#209.
Skinned models can have multiple texture images for animation. When a
material colormap in the .pol file is `image.png`, additional images are
stored with names like `image[1].png`, `image[2].png`, etc.
Animation frame information is stored in `<motion_name>.txa` file. This
is a text file containing newline-separated integers, specifying the
texture index for each motion frame.
- 0.1 for ALPHA_MAP_TEST, which fixes a rendering issue of cyouchin.POL
- 0.75 for ALPHA_TEST. Judging from the rendering of mapT_0a.POL, this
seems to be the correct value
The custom characters feature in Rance Quest calls GoatGUIEngine.
SetPartsCG() with a name like "<save>SaveData\\顔CG\\filename.png",
which must be resolved with the save directory.
Since bool functions return a 1-byte value, the value of the upper 24
bits of r.i after ffi_call is undefined.
This actually led to a bug where PassRegister.ExistText returned
incorrect values on Windows x64.
Used in Rance Quest.
Presumably, Inputs() returns true when there is unconverted text in IME,
and Converts() returns whether the user is in the conversion phase of
IME input.
SDL text input API cannot distinguish them, so in this implementation
both return true when there is uncommitted text.
It vibrates the whole screen. To implement this, this introduces a
global motion list and parts_set_global_pos(), which sets the position
of the root of the parts tree.
TapirEngine.FindInstancePath() takes a starting point and an end point
and executes the A* algorithm on the collision mesh. The resulting path
can be obtained with TapirEngine.GetInstancePathLine().