-
Notifications
You must be signed in to change notification settings - Fork 194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support Maniac Patch (Metabug for all releases) #1818
Comments
New versions 190625 and 190630 released. No new features, just unspecified fixes for the new commands. |
New version 190904. There is now a website for the patch: https://bingshan1024.github.io/steam2003_maniacs/ Just a quick summary of notable changes as my time is limited right now:
|
For later: There is some Command dispatch table in the CHERRY segment (guess this was relocated from the normal Code segment, havn't analyzed RPG_RT that much yet).
|
About the savedata: |
I asked BingShan months ago about a documentation for the "Variable Expression" feature. The expression is compiled to an op code list by the editor and these opcodes are interpreted by the engine:
|
Chunk information: SaveSystem: Set by command "Set Game Option": 88: FrameSkip (kinda useless)
89: Picture limit (useless, ours is dynamic) 8A: Fatal Mix stuff 4 Byte: XX XB XC XD B:
C:
D:
8B: Unknown SaveEventExecFrame: 12: 2x Little Endian Int32 (-_-) Modified by Loop command
|
About the new common event things:
|
This makes sense because I left an area dedicated for patching in the CHERRY segment (with a note embedded in the segment that says patches should go here). :) |
I redid the entire initial post via DeepL (was a Google Translate before) and improved the formating. Also updated to the latest version before the recompile approach (this is 210414). I see no reason in supporting anything post 210414 because this was reverse-compiled allowing huge changes to the engine. Good news: I was able to find an older branch where I worked on Maniacs again. Thought I lost it but was just on a different PC :) https://github.com/Ghabry/easyrpg-player/tree/maniac-events That branch implements:
|
Also interesting are the new loop commands that can do more than just "endless loop". It also adds Count up/down and (do) while. Pretty useful if you ask me. The commands completely replace the old ones, here are the function addresses:
And here what they do (not motivated to code right now, so just documenting it for later) LoopParam 0 is the loop type. 0 (or no argument) is a normal, endless loop. For all other cases when too short it allocates "8 * (depth + 1)" byte for
For "X Times"
Count Up
This is like "X Times" but the Begin value can be set. Count DownLike count up, but the values Current and End receive are swapped WhileAssignment like Count Up When Current == End, Current = End = 0, also Skips shared logic, except for Arg4 Do WhileCurrent = 0, End is kept as is Shared logicWhen Current <= End: Arg 4 is a Variable that receives "Current " Repeat LoopThe arguments from Loop are duplicated in here (makes sense, otherwise it would be necessary to scan for the loop command) When Param 0 is 0 or missing it is the normal endless loop In the other cases: It allocates as above if too short (likely safety reasons to prevent crashes) "X Times" and "Count Up"Increment Current by 1. Count DownDecrements Current "While" and "Do While"(not sure how the operator is encoded, easiest way here is just changing stuff and looking in lcf2xml output) Contrary to the X Times and Count Up/Down where the value is resolved in the Loop command here the values are resolved everytime "Repeat Loop" is reached. When the condition for the two checked values is true (depending on the operator) then "current" is incremented by 1. End is never touched. When the condition is false the loop is aborted. Shared logicWhen the loop is continued then the variable specified by arg4 received "current". Break LoopThis doesn't touch the |
Erase Pictureat 4FD16C Okay, no surprises here but better to take a look ;)
Before 2k3E this only supported "Arg 0 = Picture ID" Cherry added:
BingShan added:
|
New command: Control Var ArrayThe arguments are already documented by BingShan (see top comment) tl;dr: Nothing surprising here (good) This basicly operates on two slices in the variables array. When the resolved value of "slice1" is < 1 or the lengh of the slice is <= 0: Abort the command. Note: CopyWhen target (slice2) < 1: Abort. ExchangeWhen target (slice2) < 1: Abort. Sort (Ascending) & Sort (Descending)Does a numeric sort ShuffleThis loops backwards. For each element pick a random number from the slice and then swap current with the picked one. EnumerateThis loops backwards again (maybe is a compiler optimisation...) E.g. The constant is 2 and len is 3, then the result in the slice is 2, 3, 4. Everything else (Math operations from Add to Shr)This shares code: For Div and Mod: In the 0-case a 1 is assumed. Operation order, relevant for Div, Mod, SHL, SHR: slice1_val OP slice2_val. |
Here a list of stuff that I personally consider worth implementing. Italic = Already implemented or PR open
Maybe, because they are simple but not too useful:
Maybe (very low priority):
Not interested at all: All this battle stuff because it uses hacky things like "parallel processed in battle". 2k3 battle is already terrible, I will not touch this.
|
Example for the expression format:
Unfortunately this is not stored in postfix notation which would make evaluating the expression easy:
|
Unfinished patch for the fixed_angle: This is more tricky than expected because this seems to use 360 degree angles instead of 256 (wtf?), so needs custom code to work properly... I give up on this for now, my progress before reset: diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp
index 95db656b0..6579520d8 100644
--- a/src/game_interpreter.cpp
+++ b/src/game_interpreter.cpp
@@ -2624,6 +2624,11 @@ bool Game_Interpreter::CommandShowPicture(lcf::rpg::EventCommand const& com) { /
}
params.flip_x = (flags & 16) == 16;
params.flip_y = (flags & 32) == 32;
+
+ if (params.effect_mode == lcf::rpg::SavePicture::Effect_maniac_fixed_angle) {
+ params.effect_power = ValueOrVariable(com.parameters[16] & 0xF, params.effect_power);
+ params.effect_power /= ValueOrVariable((com.parameters[16] & 0xF0) >> 4, com.parameters[15]);
+ }
}
}
@@ -2698,6 +2703,11 @@ bool Game_Interpreter::CommandMovePicture(lcf::rpg::EventCommand const& com) { /
}
params.flip_x = (flags & 16) == 16;
params.flip_y = (flags & 32) == 32;
+
+ if (params.effect_mode == lcf::rpg::SavePicture::Effect_maniac_fixed_angle) {
+ params.effect_power = ValueOrVariable(com.parameters[16] & 0xF, params.effect_power);
+ params.effect_power /= ValueOrVariable((com.parameters[16] & 0xF0) >> 4, com.parameters[15]);
+ }
}
} else {
// Corner case when 2k maps are used in 2k3 (pre-1.10) and don't contain this chunk
diff --git a/src/game_pictures.cpp b/src/game_pictures.cpp
index f14be9b01..881eb8e0b 100644
--- a/src/game_pictures.cpp
+++ b/src/game_pictures.cpp
@@ -189,7 +189,11 @@ bool Game_Pictures::Picture::Show(const ShowParams& params) {
SyncCurrentToFinish<true>(data);
data.start_x = data.current_x;
data.start_y = data.current_y;
- data.current_rotation = 0.0;
+ if (data.effect_mode == lcf::rpg::SavePicture::Effect_maniac_fixed_angle) {
+ data.current_rotation = data.finish_effect_power;
+ } else {
+ data.current_rotation = 0.0;
+ }
data.current_waver = 0;
data.time_left = 0;
@@ -423,18 +427,16 @@ void Game_Pictures::Picture::Update(bool is_battle) {
}
}
- if (data.effect_mode != lcf::rpg::SavePicture::Effect_none) {
- data.current_effect_power = interpolate(data.current_effect_power, data.finish_effect_power);
- }
-
// Update rotation
if (data.effect_mode == lcf::rpg::SavePicture::Effect_rotation) {
data.current_rotation += data.current_effect_power;
+ data.current_effect_power = interpolate(data.current_effect_power, data.finish_effect_power);
}
// Update waver phase
if (data.effect_mode == lcf::rpg::SavePicture::Effect_wave) {
data.current_waver += 8;
+ data.current_effect_power = interpolate(data.current_effect_power, data.finish_effect_power);
}
// RPG Maker 2k3 1.12: Animated spritesheets
-- |
The expression format is actually not that hard to parse. Instead of a stack you need recursion (almost ready :)) Also getting close to ShowPicInfo working... |
They also changed how math works. For sqrt they do wtf. |
I ran into some problems with this patch. |
As shown in the opening post, this command is not yet supported. |
A problem with ShowStringPic is the font name: It uses the name of the installed font reported by the Windows Api. Not the filename. Obtaining installed fonts on all platforms is tricky (not portable) and imo not worth it because this gives complaints like "I run this on Android but the text is wrong". There could be some heuristic probing like this (assuming font is e.g. "Noto Sans"):
|
Imo BingShan confused the units in the size calculation of the window (pt vs. px). E.g. when using a Font size of 32 pt (24 px) the Maniac Patch assumes for every line a height of 32 px. Which is a mistake of 8 px per line. By using these incorrect units everywhere the calculation perfectly matches up though. Here an example rendering with a 32 pt (24 px) text and a gap between the lines (can be configured) of 8 px. Maniac version has lots of margin everywhere because of this error. Player Note: This message is not supposed to be offensive (language barrier). It just documents a potential bug. |
New from TPC Display Text Options supporting Display Text Options
|
About Play SE:
In other commands 0 is "direct", "1" is "variable", "2" is "variable indirect". Making it possible to conclude which block is which. So this obviously means:
AAAA is unused or a string variable. The order makes sense because this matches with the TPC parameter order. (Guess the arg order is volume, pitch, pan???) Will likely yield to the same conclusion for BGM. |
Updates to
|
Just some bugs present with the patch that I'm listing here for documentation:
|
With #3051 there is support for String Variables added. Implementation differences:
This shouldn't be a huge problem because unprocessed command codes are likely a game bug.
|
Hm, as many issues in this repo showed, what is "not supposed to" be done is often used in creative ways, especially in Japanese games...... |
I was playing around with pictures, especially the ".scale2" argument. It allows to stretch a picture using width and height parameters. Using TPC, it looks like this:
I made a test project for testing interactions between various settings. Here's my observations:
So here's the kicker:
Bonus: I also managed to crash EasyRPG when moving a picture with Display Position set. |
I managed to implement separate Width/Height values for drawing pictures, it can even Save and Load as required! There's still work to do, for instance saves from ManiacPatch and EasyRPG aren't Byte-identical, when saving/loading between versions, it skips a few unknown chunks:
For everything else, it works as expected. |
Just discovered that using the command ShowPicture with a StringVar crashes the game by showing picture ID -1.
EasyRPG does a ValueOrVariable check on this value, however it does not check if it's equal or higher than 256 (bitfield that Maniac Uses). I've made this quick change in game_interpreter.cpp, for CommandShowPicture:
Now it just works! Edit: Pull request right there #3182 |
We are really close to fully support legacy Maniac Patch :) Only missing are:
|
Strange behaviour with Maniac Patch while in the battle system: Showing a message box (doesn't matter how) freezes the entire battle system: CBA idle animations stop playing and do not even continue when you close the message box. Fixes itself after doing any action. This can also be observed when a message box opens because of a damage callback: The enemy flickers for one frame, then everything hangs until the message box is closed. 🤔 |
Website: https://bingshan1024.github.io/steam2003_maniacs/
Because Maniac Patch is a moving target I decided to close the old issues and just update this one issue here when new features are added, otherwise this slowly becomes messy.
Old issues: #1424, #1557, #1608
Some of these old issues contain more information not moved here yet.
New commands
This command retrieves the same information that is displayed on the default load screen.
It stores the date, time, level and HP in variables and the face graphic in a picture.
Character names are not currently supported.
If the save data does not exist, the date variable will be set to 0.
The face graphic is treated as a 4*4 sprite sheet.
So if you have a file with more than 16 patterns, it will not be displayed correctly.
On the other hand, it doesn't matter if the file is out of the standard as long as it can be divided into 4 parts.
The original picture settings are used, except for the file and sprite sheet related items.
Please use the appropriate picture number to make the picture off-screen or transparent beforehand.
The order of the date (YYMMDD) is the same in the English version.
Numeric Arguments:
This command performs the same operation as the default save function.
It is not possible to use a save number less than 0.
You can optionally store the result of the execution in a variable.
The value is 1 on success and 0 on failure.
Note that the assignment to the variable is done after the save has been executed.
Numeric arguments:
Not implemented: Black screen with fade-in
This command is equivalent to the default load function.
Save numbers less than 0 cannot be used (the operation is ignored).
Optionally, it checks the file before execution and aborts the load if the result is invalid.
The check is equivalent to the "Get Save Information" command.
If you are sure you have the right file, you can disable it, but it is not recommended. -The
Numeric arguments:
Not used anymore
This command cancels the dark state after loading.
It is not available in the new game. The darkness will disappear naturally after 1 frame.
This command gets the relative position of the mouse in the window.
It is based on the resolution of 320*240.
The value will not work correctly if the window is full screen and DirectDraw is specified as the rendering method. (This is probably not a problem, as few machines currently have this setting in effect.
Numeric arguments:
This command sets the relative position of the mouse in the window.
It is based on a resolution of 320*240.
The x-coordinate is rounded to 0-319 and the y-coordinate is rounded to 0-239 to avoid inducing false clicks.
The values are not correctly handled when the machine is in full screen and DirectDraw is specified as the rendering method.
(This is probably not a problem as few machines currently have this setting enabled.
Numeric arguments:
Supported but the implementation is not perfect ;)
Generates a picture from the specified string.
Once generated, it can be treated like a normal picture.
Disabling the background, border, gradient and shadow will reduce the cost of generation.
Control characters:
There are several control characters available in the string.
Some control characters are available in the string, e.g. the value in [] can be referenced by \V
Display position-> coordinates: Specifies the meaning of the position value.
(Traditional pictures are fixed at center coordinates.)
Picture size:
Specify the size of the picture to be generated.
If the value type is set to "Automatic" or the value is set to 0, the picture will be adjusted to the appropriate size.
Font name:
Specify the font to use for drawing.
If this field is left blank, the system settings of the database will be used.
Font size:
The size of the font used for drawing.
Valid values are 1-255, default is 12.
Character spacing:
This specifies the amount of space to be left between each character.
Valid values are 0-255, default is 0.
Line spacing:
The number of spaces per line.
Valid values are 0-255, default is 4.
Bold:
Applies Bold to the font.
System graphics: Specify the graphics to use for drawing.
Specifies the graphics used for drawing.
<Select to refer to the system settings of the database.
Wallpaper:
Specifies the background type for the window.
Draw border: specifies whether the window should have a border or not.
Specifies whether the window should have a frame or not.
If either the height or width is less than 8px, the frame will not be drawn, regardless of the setting.
Enable outside margins:
This specifies whether or not the border area is taken into account when calculating the picture size and text drawing position.
If enabled, the area is 8px on each side and 10px on the top and bottom.
Enabling text gradients:
Enables or disables text gradients, as used in other features such as text display.
If disabled, the text will be drawn from the top left corner (0, 0) of each 16*16px colour.
Enable text shadow:
Enables or disables text shadows, as used in other features such as text display.
Preview restrictions:
Position: Fixed at top left coordinate (0, 0).
Size: - automatically calculated unless specified as a constant.
Magnification: - fixed at 100% (the preview itself can be doubled).
Transparency: Fixed at 0%.
Effects: All effects are disabled.
Font size: 12 unless specified as a constant.
String arguments: (Delimited by 0x01 byte)
Numeric arguments:
This command retrieves the position and size of the picture being displayed.
Special effects such as rotation will not be reflected.
Numeric arguments:
This command allows the user to control some of the defensive battle processes.
This command is only valid for use during the battle, and is deactivated (without all control) at the end of the battle.
It should be used in conjunction with a common event that is conditional on the start of the battle.
Also, weighted commands should not be used within a common event that is being processed.
There are currently five different actions to choose from
ATB Gauge Increase:
This controls the natural increase in the gauge of characters, including enemies, every frame.
The following four variables are used to get or set the value
Damage Pop:
Controls the notation when some damage or recovery occurs.
If you specify a common event for this, the default notation will not be drawn.
There are six variables that can be used to get or set the value
Targeting:
This is called just before a character's action to control the target of the action.
There are six variables that can be used to get or set values
*1:
*2:
*3:
State Granting
This function is called when a character is granted a state.
The following three variables are used to get or set the value. 1.
Value change other than damage
This is called when values other than HP change.
The arguments are aligned so that they can be handled in the same event as the damage pop.
The following 6 variables are used to get or set the value
Numeric arguments:
This command is used to control the gauge of characters, including enemies and allies.
The effective range of the gauge is 0~300000.
Numeric Arguments:
This command is used to enable/disable the change of formation item in the battle command and to edit the party command.
(1) Combat commands
This command can only be used during a battle and will be deactivated after the battle is over.
It should be used in conjunction with the Common Event, which requires the start of combat.
This command can be used to create a situation where there are no combat commands at all. In that case, the game will switch to AI action when you try to choose an action.
Added in 190220: When there are no commands, selecting a transparent item will change the formation
Party Commands:
You can choose any 4 commands from "Fight", "Auto", "Run", "Win" and "Defeat".
Victory" and "Defeat" will literally force you to win or lose the battle.
If you choose all five, the first four will be used, if you choose none, the default three will be used.
If you select only one of them, the screen transition itself will disappear.
Numeric arguments:
Retrieves various values that appear during combat.
It does not do anything when not in combat.
The information is output consecutively, starting with the specified variable number.
Character ID/Member/Enemy Character
Ability Correction Value
Gets the value of the character's ability to move up and down during combat, in order of attack, defense, mental strength, and agility.
State:
The total number of all conditions and the number of turns elapsed since the condition was inflicted.
The number of turns is 1 when the condition is inflicted and 0 when it is not.
For example, if the database contains three conditions (1: death, 2: poison, 3: darkness), and you want to get the character's state immediately after the darkness
v[specified variable] = 3
v[variable+1] = 0
v[variable+2] = 0
v[variable+3] = 1
The result is
Attributes:
Gets the total number of values for the current attribute resistance and the status of each resistance.
The values are 2 for increased resistance, 1 for normal resistance and 0 for decreased resistance.
The value of each resistance may be omitted, in which case it is treated as the default value (1).
For example, if you have three attributes in the database (1: sword, 2: spear, 3: strike) and you want to get the character attributes for reduced sword resistance and increased strike resistance
v[specified variable] = 3
v[variable +1] = 0
v[variable +2] = 1
v[variable+3] = 2
The result will be
Other:
The following information about the specified character is obtained in order.
Image centre coordinates X
Image centre coordinates Y
Actionable state (disabled=0, possible)
Defensive state (None=0, Yes)
charge state (none=0, yes)
Appearance state (none=0, yes)
Numerical arguments:
An array of consecutively numbered variables can be manipulated.
It is also possible to operate on a single variable by setting the length of the array to 1.
Numeric arguments:
The Joypad part is not supported by EasyRPG Player as we provide our own remapping in the configuration scene
This command cannot wait for a key to be pressed.
If you assign keys to the joypad, it will be possible to include the pad when getting the keyboard status.
Get keyboard status list:
Get the status of keys in the keyboard list of the form at once.
Get Keyboard Status List (Disable Assignment):
Get the status of all keys in the keyboard list of the form.
Even if the joypad is assigned, this is ignored.
Get status by key code (allocation disabled):
You can get the status of keys by specifying the key code (0-255) directly.
Use this function when you want to get the status of a key that is not in the list.
Get joypad status list:
Get the status of buttons in the joypad list of the form at once.
Get Joypad Assignment:
Get the current joypad assignment status.
If the button is not assigned, -1 is returned.
Setting joypad assignments:
Assign a joypad button to one of the keys in the key list.
Numeric arguments:
(constant = 0, variable, variable number variable)
Partial: A and B autotiles are unsupported
This command rewrites the tiles on the map where the hero is.
Changes made by this command are not reflected in the save and will disappear when you move the map.
Numeric arguments:
- When single (constant=0, variable, variable number variable)
- For a range (variable=0, variable number)
11: Top of change range (Constant=0, Variable, Variable)15: Width of change range (Constant=0, Variable, Variable)- 12
- 16~19: Changed range height (Constant=0, Variable, Variable)
This command deals with the common save data that can be read and written from each save data.
Currently, only switches and variables are supported.
The file name is fixed to "Save.lgs".
Open:
Loads the shared save data from a file.
This operation is ignored when the file is loaded.
Close:
Release the loaded shared save data.
This operation is ignored if the file is not loaded.
Note that this operation does not save the changes.
Save:
Saves the contents of the loaded shared save data to a file.
This operation will be ignored if the file is not loaded.
Save and close: After "Save", "Close" will be executed.
Copy from shared save:
Loads the specified values from a loaded shared save into your own save.
If you do this when the save is not loaded, it will execute 'Open' before processing.
Copy to shared save:
Writes the specified value from your own save data to the loaded shared save data.
If you do this when the save is not loaded, it will execute "Open" before processing.
Numerical arguments
For copy operations only:
As the name suggests, this command changes the ID of the picture.
If you use the "Ignore out-of-range errors" setting, moving from/to an out-of-range ID will be replaced by a simple delete operation.
Move:
Change the picture ID of (size) from (target1) to (target2).
If (Target2) is in use, it will be erased.
Exchange:
The picture ID of (size) from (target1) is replaced with (target2).
Slide:
Move the picture ID of (size) from (target1) by (distance).
Numeric arguments
This command is used to set the overall behaviour of the game.
Inactivity behaviour:
Whether or not to pause the game when a window becomes inactive.
The default is wait. This setting is reflected in the save data.
Fatal Mix:
This is mainly for debugging purposes.
FPS:
The speed at which the game will run, cannot be less than 1.
This setting is not reflected in the save data.
Test Play:
This is the same as the "TestPlay" start-up option.
This setting will be reflected in the saved data.
Right Shift to skip messages:
While holding down the right shift key, all messages will be displayed momentarily and will close automatically.
This setting is reflected in the save data.
Maximum number of pictures:
This is the maximum number of pictures you can have.
This number has a significant effect on the speed of the game and the load time of saved data.
This setting will be reflected in the saved data.
Frame skipping:
Changes the default drawing process from every frame to once every n frames.
This setting is reflected in the save data.
Numeric arguments:
EasyRPG implementation difference: Instead of invoking the command directly it pushes a new frame with a single new command and invokes it (is like a CallEvent with a single command).
This command is intended for advanced users. Please make sure you fully understand the command specifications before using it.
Invokes any command (with exceptions) with any argument.
If a non-existent code is specified, the behaviour depends on the value.
Unavailable commands:
Commands that do not work:
Commands that do not work properly:
String arguments: Code dependent
Numeric Arguments: Code dependent
Modified commands
Recycles the now unused "bottom transparency" (arg 14) setting as a bit field (seriously...) but the bit field starts at 256 which means it can't be confused with the transparency where the maximum value that makes sense is 255.
The origin uses the upper bits of arg 1 which is the "ValueOrVariable" indicator for X/Y.
Rotation:
see #1818 (comment)
Added support for mouse input (left/right centre click, wheel up/down scroll).
Wheel scroll is only valid under the condition of "wait until pressed" because there is no push down state.
The way how the Key input is encoded is a bit strange because it recycles other parameters but by looking at the ones it uses I see some logic.
When the original checkbox is ticked the value becomes 3 (which means it's a bitfield)
Wheel down: Arg 10 = 2 (check_down)
Wheel up: Arg 13 = 2 (check_up)
Mouse left: Arg 3 = 2 (check_decision)
Mouse right: Arg 4 = 2 (check_cancel)
Mouse middle: Arg 9 = 2 (check_shift)
In the following explanation, argument 1 is a, argument 2 is b, and multiplier is c.
How to get the value of a date
How to get the im/pf value
Add expression format to target and operand
Added method to specify common event by variable number variable.
Added the ability to specify conditions. The switch is treated as a number with 1 for ON and 0 for OFF.
The number of iterations and the index will not be set correctly if a label jump brings you inside the loop.
Infinity: Conventional infinite loop.
Number of times:
While:
Do While:
see #1818 (comment)
Fixes behaviour when running inside a multiple loop.
Added option to disable flashing before battle starts.
Additional features supported from newer releases
The text was updated successfully, but these errors were encountered: