Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Tirlititi

Pages: 1 ... 13 14 15 16 17 [18] 19 20 21 22 23 ... 35
426
Thanks usb :)
Yeah, I thought that they fixed that bug, but apparently not. It doesn't concern only Italian but also French and Spanish. The bug lies in the CIL method "BattleHUD::SetBattleCommandTitle" but it's a bit tricky to fix it there with HW.

What you can do though is bypass the bug: go to the "Interface" panel, select the "Battle Spell Naming" field and add 13 entries to it (right-click -> Add), then write the proper full names ("Colpo Fire" etc...). Finally, go to the "Party -> Spells" panel and change the casting names of the magic swords spells to the entries that you just added.
It's a bit dirty as a fix, but it works. You should also translate the names in the "Interface" panel if you want it to work for all the languages (I think the game would crash in non-italian language otherwise).

For info, you can have up to 62 custom spell names in that interface field.

427
You're supposed to select the corresponding Texture2D file.
That is, however, very weird that your texture is named "98.fbx"...

428
Huh, I didn't see your post until now Trostboot. That's a shame :/

I updated the tool to v0.39b:
- Fixed a bug in Model Importer when the texture files were auto-detected,
- Allow to use UV, normals and tangents in "ByPolygonVertex" mode for importing models,
- Improved the "Edit Similar Enemies" option: it now applies to the enemies' attacks as well,
- Added a few editable datas to the enemies, related to how they look and sound in-game, as well as which model animations they use,
- Allow to input the model ID of an enemy so you can choose an imported model ID or a model that is normally not used for battles.

This last feature needs a bit of engine modification to work though. When you use an imported model, you need to add it to the engine's database like any other model, but even if you use a standard field model, you'll need to modify 3 CIL methods.
Indeed, there are 2 model databases:
1) "FF9BattleDB::Animation", containing the battle models (enemies, characters and weapons),
2) "FF9DBAll::AnimationDB", containing all the models (including the battle models).
You must make it so the "FF9DBAll::AnimationDB" is used anyway instead of looking in the "FF9BattleDB::Animation" table.
Additionally, you must tell the engine to load all the animations in the RAM for the models used in battles. The policy is indeed that:
1) For Fields, only the animations listed in "Preloading" are initally loaded in the RAM. Other animations are automatically loaded everytime if you use them in the Field script (with a "RunAnimation" call for example). The only exception to this rule is the "Jump" Animation that isn't automatically loaded by the related call so must be loaded another way (either have it in "Preloading", or use a "RunAnimation" or "SetStandAnimation" call on the "Jump" animation beforehand).
2) For World Maps and Battles, all the animations that can be found are loaded in the RAM along with the model.
Whichever option is chosen doesn't depend on the game's state unfortunatly, but on the model's string ID (if it contains something like "_B0_" or "_W0_", it is considered as a Battle/World Map model). So the wrong policy is used if you select a Field model for an enemy.

In practice, do these changes in the CIL Code if you want to use a Field model for an enemy:
- In the method "btl_init::SetMonsterParameter", you should have a line "ldsfld 0x40004B6   // FF9BattleDB::Animation" near the middle of the method. Change it to "ldsfld 0x40012A4   // FF9DBAll::AnimationDB" (the hexadecimal IDs are the ones from the latest Steam release).
- Same in the method "btlseq::SeqExecAnim". Change the "FF9BattleDB::Animation" line to the "FF9DBAll::AnimationDB" line.
- In the method "AnimationFactory::AddAnimToGameObject", search for these lines:
Code: [Select]
ldarg.1
ldstr 0x7003CA77 // "_B0_"
callvirt 0xA0001A7 // bool System.String::Contains( string )
brtrue IL_0098
Replace them by these:
Code: [Select]
call 0xA0000BB // !0 PersistenSingleton`1<class EventEngine>::get_Instance()
ldfld 0x40019E6 // EventEngine::gMode
ldc.i4.2
beq IL_0098
It may have an inconvenient bug though: sometimes models will be messed up in the first screen you see after launching the game. Going to the menu -> Title Screen -> Continue, it will be fixed back, but it is annoying.

And, of course, you must setup the datas in the enemy's resources (at least setup the animations it uses ; the other datas won't make the game crash if they are at 0).

Another problem though is that the animation speed are slowed by a factor of 0.5 in battles, so the field models will have slower movements...
Hopefully, these troubles will find a convenient fix in the future.

@Trostboot: I will fix that bug for the PSX version for the next release, but you can use an older version of HW in which there is not this bug. The version 0.37c doesn't seem to have that bug. Also, most recent features are for the Steam version mainly so you don't miss a lot. Sorry about that.

429
About the SFX identifier, it is indeed dependant on the character only (the "serial_no" number). The method "btl_vfx::SelectCommandVfx" defines which Spell Animation is used depending on the command: most of the time, the Spell Animation used is the one given by the Spell, but for some special cases, like the Attack or Throw or a few others, it is handled by the engine.
The Spell Animation used by the Attack command should be around the position IL_0091 and it's "100 + btl_util.getSerialNumber(regist)".
For Zidane, the serial number is 0 or 1 depending on his weapon, for Vivi, the serial number is 2, etc...
There are only the 19 slots of Spell Animations used by the characters between 100 and 118 included. There are also 64 slots of Spell Animations used by the enemies for their physical attacks, ranging from 313 to 376, but the game won't allow a character to use one of these like an attack (it only displays the strike, without the animations of the characters running to the enemy).

For the save spot, the Fields are loaded and initialized after a loaded game just like after entering the Field normally.
What they do is that they set the variable "VAR_GenBool_184 = 1" right before saving. Since that variable is saved in the memory card/Steam save, the script knows when a field is entered by a loaded game, and generally, it then sets the variable "General_FieldEntrance" to the special value 10000. You can see the position where Zidane is created after loading a save in "Zidane_Init" functions.
In the World Map, the character's exact position is also saved in the variables "VAR_GenInt24_64" (X), "VAR_GenInt16_67" (Z), "VAR_GenInt24_69" (Y) and "VAR_GenUInt8_72" (angle) ; you can use them for the field's position as well with something like that:
Code: [Select]
set VAR_GenInt24_64 = GetEntryPosX(255)
set VAR_GenInt16_67 = GetEntryPosZ(255)
set VAR_GenInt24_69 = GetEntryPosY(255)
set VAR_GenUInt8_72 = GetEntryAngle(255)
set VAR_GenBool_184 = 1
Menu( 4, 0 )
set VAR_GenBool_184 = 0
And then something like this in the character's "Init" function:
Code: [Select]
if ( General_FieldEntrance==10000 ) {
    MoveInstantXZY( VAR_GenInt24_64, VAR_GenInt16_67, VAR_GenInt24_69 )
    TurnInstant( VAR_GenUInt8_72 )
}
I think that the lines "if ( VAR_GenBool_184 == 1 ) { set General_FieldEntrance = 10000 }" are present in all the Fields of the game so you don't have to care about adding them.

430
It's the name of the flag from the engine's source code, but it doesn't seem to be used at all (I couldn't find anything that checks if this flag is on in the engine's code). It is most likely a flag dummied out during the game's development.

@Incinerator: Ok, I found a bug and it was, as usual, a pretty stupid one. I will make a fix update but I'll use the occasion to also add a couple of things. You can bypass the bug with the current version though: rename the texture dependancies in the FBX model to something else. The bug occurs when the model importer automatically catches the texture (more precisely, when another file as the same internal name as the texture, such as a material).
So you have to make sure that the program asks you what are the textures linked to the model.

With this, at least exported/reimported models work. I'll try to add compatibility with the UV indices by Polygon Vertex for the fix as well.

Not related, but I found where the "3 enemy types / 18 attacks" limit is: go to the CIL Code "FF9StateBattleSystem::.ctor", the limit is there.
Find the following lines and increase the numbers to whatever you need:
Code: [Select]
ldc.i4.3
newarr 0x2000062 // ENEMY_TYPE
...
ldc.i4.s 18
newarr 0x2000050 // AA_DATA
You may then ignore the warning that popups when adding too many enemy types or attacks in a battle.
There are other limits in that CIL method, but none of them can be modified as easily as just changing a number there.

431
These lines in the Yan's script are present in most of the enemies' Counter function. They precisely say to not counter to Zidane's What's That?!. Indeed, "return" means something like "skip everything's left". So actually, Yans counters to anything as long as it's not that single skill.

To give you ideas, you can also look the AI of Gizamaluke, who counters differently depending on a magical or a physical attack, and the AI of Soulcage, whose counter depends on the element of the attack (more complicated).

You can declare new local variables, yes. For AI, you should first import the "LocalVariables" .hws file that comes along with the tool: it declares all the used variables of the enemy scripts. If you import it, you'll see a few lines in the "Local Variable Panel" when editing an AI. These lines declare the used variables. You can add yours like this:
1) Select the function to which you want to add a local variable (or at least a function of the right enemy),
2) In the local variable panel, add a line like "local uint8 isBexecuted",
3) Use that variable in the function: when you parse, it will recognize the declared variable,
4) Most likely, you will still have a warning, like "Need to allocate more": change the "allocate N" line accordingly and parse again if that happens.

In the help (F2), you have some informations about variables (which types can be used, what is the difference between local, global and general, etc...).

Note that when you declare local variables in Field or World Map scripts, the local variables already used are not listed at all and you can overlap an existing variable if you're not careful. In order to be sure not to overlap an existing variable, you can write this kind of line instead for 2):
"local uint8 myVariable Loc_UInt8_[N]" where [N] is replaced by the number in front of "allocate".
You'll then need to increase the "allocate" number for sure.

432
Yeah, it should, Kaldarasha, minus the problems that importing a model seems to bug most of the time :/

So, I've tried to extract/reimport Zidane and it indeed crashes in-game. It's the meshes/materials that are causing the bug for some reason (the animations seem to be better done since Zidane's 401 animations were exported/reimported correctly).
Also tried with the Grimlock with the same result: it doesn't work anymore for me either... Since it worked previously, I can hope to find what I changed since I tested it.

Yes, the moogle book is the book you see when saving. That's the model 133, the first of the list when sorted, which is why I usually tested things on it.

I'll make a fix, but I'm busy this week, sorry.

433
So, @Incinerator:
You can't just replace the Mapping Information Type by another ; each type means that the datas are sorted differently (and usually not at the same place in the file). I'm also worried about that Zidane export/reimport as it shouldn't bug in-game. I'll test that today.
What I'm sure of, is that exporting/reimporting the moogle's book works perfectly, as well as the Grimmlock enemy model. Can you try one of these? If that doesn't work, then your archive must be corrupted somehow. If I can't export/reimport Zidane, I'll have something to work with and I can catch where the problem comes from.

Normals are good as they are in your screenshot. That's many polygons but there shouldn't be any data size restriction on the new model.
For the scale, the game expects models of size ~100. It's the same unit as the position in Fields, for instance. So a 100 radius scaled model is quite small, but still visible. For human-sized models, you'd take a height of ~700.

@ste459: Glad to hear that this works at least ^^
There shouldn't be any bug with changing this formula, as long as the frequency is positive. And these lines are only for the Regen frequency.

434
Yeah, that's the problem (at least that's A problem). I don't know how to change that setting in Metasequoia. That's not on the window you're displaying.
Do you have the free version or the licensed version of Metasequoia? I may look at it.

435
Urgh.
Maybe it's because the UV are refered by Polygon Vertex?
Search in your .FBX the lines "MappingInformationType". What do they say? (ByVertice, ByPolygonVertex, ByPolygon...)

436
So, here is how to use the model importer. I guess it will answer your questions, Incinerator ;)

Intro A - Supported Model Formats
You can only import FBX Binary and FBX ASCII files properly, much like exporting. Encrypted FBX are not supported. In general, the other formats have problems with animations or even bones so you should always convert your models to FBX beforehand. 3DS Max is the normal program you would need to create/edit models that can be imported, but it's not free. There is a free version, called Gmax, but I'm not sure if it supports FBX versions that are recent enough. Also, FBX ASCII format is a text file that can be edited with Notepad but it's tedious and won't bring you very far.
The FBX versions supported are:
- FBX ASCII versions 5, 6 and 7 up to 7.4
- FBX Binary versions 5 and 6 up to 6.1

Also, only (polygonal) Meshes are supported. No Nurbs, no Patches.
The Tangents, Normals and - more importantly - the UV coordinates must be stored by Control Points (not by Polygon vertex). I guess it's a simple setting to check in 3DS Max.

For animations, I wasn't able to import properly the Bezier interpolation data: animations will have a close-to-linear interpolation (it usually doesn't look very different).

Note that texture animations are not supported yet. They are stored in different files for which I didn't investigate the format.
And also, some animations have sounds in-game, like footsteps or a sword unsheathing. These are not inside the animation's data but in the Field script codes (usually either in the object's "Init" function, or in its "Reinit" function).

Intro B - The options
In the Unity Assets Viewer, you have the following options for importing models:

-) Only Update Existing Nodes: You will surely have no interest in this function except in very specific situations. It expects the imported model to have exactly the same nodes (mostly bones) as the one in-place. It popups a warning if not. Using this option, you're 100% sure that no new asset will be imported when you replace a model.
-) Update Existing and Import New: The default one. It will compare the hierarchy of the new model with the old one and keep as much as it can from the old one, adding a minimal number of assets to the archive.
-) Import All Nodes in New Files: With this, except for the top-level GameObject (the file selected), all the nodes of the new models will be imported in new assets. When you add a whole new model, that's also what happens except that the top-level GameObject is also new in that case.

-) Keep Unused Nodes: Doesn't remove any asset, even if they become dummied and unusable after replacing a model.
-) Delete Unused Nodes: Clean up the assets that are not used anymore after replacing a model. This option is not implemented yet and the only way to remove assets is to replace the whole Unity archive by a backup (or download it back).

-) Import Mesh/Material: Import the geometry, skeleton, material, UV mapping, etc... You may uncheck this option if you only want to update a model's animations and speed up the process.
-) Import Animations: Import the animations in the p0data5.bin archive file (the one dedicated to the game's animations). You may unckeck this if you only update the geometry, etc...

Also, you'll need to import/update the textures separatly. If you add new textures, you must check the "Bundle Info" flag and give it a path (anything not already used will be fine). Besides that, you must choose the options for Image Quality Conversion. The main ones are:
-) RGB: Full quality images without alpha channel,
-) RGBA: Full quality images with alpha channel, resulting in bigger files,
-) DXT5 - Medium Quality: Compressed images with DXT5 format, resulting in low-sized files. Medium quality is fast and still very good,
-) DXT5 - High Quality: A slightly better quality than the previous one, with the same file size but slower to process.

If the "Default Compression Method" is checked when importing new files, the RGBA format will be used (when replacing existing textures, this option use the same compression as the old texture).

I - Replacing an existing model with existing animations
The easiest thing to do is to replace a model and don't add more animations than those already there. I've tested the model importer on the models of the p0data4 archive only (the most important one). There are also the weapon models (I think it should work) and Battle Scenes (maybe it won't work) in p0data2, and World Map model in p0data3. That last one can't be replaced and can't even be exported properly for now (it mainly consists of plenty of .prefab files, that are parts of the ground and I didn't investigate how all these parts are placed to draw the big thing).

The importing option for this should be either "Only Update Existing Nodes" or "Update Existing and Import New".
The animations of your model must match with the old model's animation internal names ("ANH_" something ; that's the names of the animations when you export the old model).

First, if you use a new texture, you must start by importing that texture. In the same archive as your model (surely p0data4), right-click on the asset list and select "Add". Once you selected your texture, choose "Texture2D" as the file type, give it a name and give it a Full Name. The Full Name is not very important but remember what you chose and be sure to use a full name that is not already used.
Typically, Full Names of the models' textures are "assets/resources/models/[MODEL_TYPE]/[MODEL_ID]/[MODEL_ID]_[TEXTURE_NUMBER].png".
Also, it may be a good idea to remember what was the Internal File ID.

Once you have all the textures set, verify that your updated model is placed in the "HadesWorkshopAssets" folder at the right place and with the right name. It must be at the same place as where the model is exported with the Unity Assets Viewer.
Right-click on the model you want to replace (Reminder: the relevant asset is the one of type "1 (GameObject)" and with the .fbx extension in his file name) then "Import Selection".
Warning: due to a bug that will take a little time to fix, you should never import more than 1 model at a time.
It is possible that the program will ask you to select the texture assets. Select the texture in the asset list or you may also copy/paste the file internal ID that was used when adding that texture.

Then wait for it and it's done!

If the program popups the window for importing assets, displaying the animation names of your model, that means you have more animations than expected and/or they don't have the right names. If your goal was not to add new animations but only replace existing ones, you can choose Full Names that you'll remember and confirm the importations. Then go in the archive "p0data5", export the .anim assets that you just added, identify the animations of the old model and replace them by the .anim you just exported (rename them with the right name and move them in the right folder, like for replacing the model).
You may also hit "Cancel" when the popups for importing new animations appears: it will cancel the update of all the animations and only update the model instead.

If your new model is lacking animations, the related old ones won't be modified at all and will still be valid.

I bis - Adding a new animation by taking advantage of dummied data
If the model you want to update as dummied animations, you can do exactly the same as in I and still add one or a few animations.
The dummied animations appear in the Field script animation list with the description "Unexisting". They are registered by the game's engine and only await to have a related asset to be usable. Here is a list of dummied animations:
Code: [Select]
// Enemy Basilisk
5458, 379, "ANH_MON_B3_011_B", "Unexisting B"
// Enemy LizardMan
5459, 390, "ANH_MON_B3_019_B", "Unexisting B"
// Enemy Carve Spider
5460, 376, "ANH_MON_B3_021_015", "UnexistingA"
5460, 360, "ANH_MON_B3_021_040", "UnexistingB 1"
5460, 366, "ANH_MON_B3_021_041", "UnexistingB 2"
5460, 354, "ANH_MON_B3_021_042", "UnexistingB 3"
// Enemy Clipper
150, 8693, "ANH_MON_B3_039_P", "Unexisting P"
// Enemy Blazer Beetle
84, 9257, "ANH_MON_B3_042_B", "Unexisting B"
// Enemy Cactuar
244, 9239, "ANH_MON_B3_061_B", "Unexisting B"
244, 9900, "ANH_MON_B3_061_TEST", "Unexisting Test"
// Enemy Valia Pira
354, 9340, "ANH_MON_B3_130_B", "Unexisting B"
354, 13578, "ANH_MON_B3_130_ILLUST","Unexisting Illust"
354, 8833, "ANH_MON_B3_130_P", "Unexisting P"
354, 13581, "ANH_MON_B3_130_TEST", "Unexisting Test"
// Enemy Vivi
558, 12302, "ANH_MON_B3_151_001", "UnexistingA"
558, 12306, "ANH_MON_B3_151_005", "UnexistingB"
558, 9675, "ANH_MON_B3_151_B", "Unexisting B"
558, 9677, "ANH_MON_B3_151_P", "Unexisting P"
// Enemy Dagger
671, 9957, "ANH_MON_B3_169_002", "Unexisting"
// Enemy Freya
297, 10317, "ANH_MON_B3_174_B", "Unexisting B"
297, 10319, "ANH_MON_B3_174_P", "Unexisting P"
// Enemy Gigan Toad B
663, 8374, "ANH_MON_B3_197_034", "Unexisting"
// Battle Steiner B
655, 6744, "ANH_MAIN_B0_018_000", "Unexisting 000"
655, 6746, "ANH_MAIN_B0_018_001", "Unexisting 001"
655, 6747, "ANH_MAIN_B0_018_002", "Unexisting 002"
655, 6750, "ANH_MAIN_B0_018_010", "Unexisting 010"
655, 6752, "ANH_MAIN_B0_018_011", "Unexisting 011"
655, 6753, "ANH_MAIN_B0_018_020", "Unexisting 020"
655, 6755, "ANH_MAIN_B0_018_021", "Unexisting 021"
655, 6758, "ANH_MAIN_B0_018_022", "Unexisting 022"
655, 6759, "ANH_MAIN_B0_018_023", "Unexisting 023"
655, 6761, "ANH_MAIN_B0_018_032", "Unexisting 032"
655, 6763, "ANH_MAIN_B0_018_033", "Unexisting 033"
655, 6766, "ANH_MAIN_B0_018_040", "Unexisting 040"
655, 6768, "ANH_MAIN_B0_018_050", "Unexisting 050"
655, 6769, "ANH_MAIN_B0_018_100", "Unexisting 100"
655, 6771, "ANH_MAIN_B0_018_101", "Unexisting 101"
655, 6774, "ANH_MAIN_B0_018_102", "Unexisting 102"
655, 6776, "ANH_MAIN_B0_018_103", "Unexisting 103"
655, 6777, "ANH_MAIN_B0_018_104", "Unexisting 104"
655, 6779, "ANH_MAIN_B0_018_105", "Unexisting 105"
655, 6782, "ANH_MAIN_B0_018_200", "Unexisting 200"
655, 6784, "ANH_MAIN_B0_018_201", "Unexisting 201"
655, 6785, "ANH_MAIN_B0_018_202", "Unexisting 202"
655, 6787, "ANH_MAIN_B0_018_210", "Unexisting 210"
655, 6789, "ANH_MAIN_B0_018_220", "Unexisting 220"
655, 6791, "ANH_MAIN_B0_018_300", "Unexisting 300"
655, 6794, "ANH_MAIN_B0_018_310", "Unexisting 310"
655, 6795, "ANH_MAIN_B0_018_400", "Unexisting 400"
655, 6797, "ANH_MAIN_B0_018_401", "Unexisting 401"
655, 6799, "ANH_MAIN_B0_018_402", "Unexisting 402"
655, 6802, "ANH_MAIN_B0_018_410", "Unexisting 410"
655, 6803, "ANH_MAIN_B0_018_420", "Unexisting 420"
655, 6805, "ANH_MAIN_B0_018_430", "Unexisting 430"
655, 6807, "ANH_MAIN_B0_018_500", "Unexisting 500"
655, 6809, "ANH_MAIN_B0_018_501", "Unexisting 501"
655, 6812, "ANH_MAIN_B0_018_600", "Unexisting 600"
// Unexisting Battle model 002
568, 12511, "ANH_MAIN_B2_003_ALL", "Unexisting All"
// Unexisting Battle model Cam
649, 14461, "ANH_MAIN_B2_CAM_011_1ST", "Unexisting 1st"
649, 14460, "ANH_MAIN_B2_CAM_011_2ND", "Unexisting 2nd"
649, 14463, "ANH_MAIN_B2_CAM_011_DOWN", "Unexisting Down"
649, 14458, "ANH_MAIN_B2_CAM_011_END", "Unexisting End"
649, 14451, "ANH_MAIN_B2_CAM_011_JUMP", "Unexisting Jump"
649, 14454, "ANH_MAIN_B2_CAM_011_OPENING", "Unexisting Opening"
649, 14455, "ANH_MAIN_B2_CAM_011_RUN", "Unexisting Run"
649, 14462, "ANM_MAIN_B2_CAM_011_1ST", "Unexisting 1st"
649, 14459, "ANM_MAIN_B2_CAM_011_2ND", "Unexisting 2nd"
649, 14464, "ANM_MAIN_B2_CAM_011_DOWN", "Unexisting Down"
649, 14457, "ANM_MAIN_B2_CAM_011_END", "Unexisting End"
649, 14452, "ANM_MAIN_B2_CAM_011_JUMP", "Unexisting Jump"
649, 14453, "ANM_MAIN_B2_CAM_011_OPENING", "Unexisting Opening"
649, 14456, "ANM_MAIN_B2_CAM_011_RUN", "Unexisting Run"
// Unexisting Battle model 001
29, 838, "ANM_MAIN_B2_001", "Unexisting 001"
// Gargant
306, 4650, "ANH_ACC_F1_GRG_B", "Unexisting B"
306, 6132, "ANH_ACC_F1_GRG_RUN_1F", "Unexisting Run_1f"
// Zidane
98, 179, "ANH_MAIN_F0_ZDN_JUMP1", "Unexisting Jump1"
// King Leo
5501, 1135, "ANH_SUB_F1_BAK_ANXIETY_3", "Unexisting Anxiety_3"
5501, 9435, "ANH_SUB_F1_BAK_B", "Unexisting B"
5501, 9154, "ANH_SUB_F1_BAK_P", "Unexisting P"
// Puck
121, 2195, "ANH_NPC_F0_RTC_SK_ANGRY", "Unexisting Sk_Angry"
121, 2192, "ANH_NPC_F0_RTC_SK_CRUSH", "Unexisting Sk_Crush"
121, 2183, "ANH_NPC_F0_RTC_SK_GET_LD", "Unexisting Sk_Get_Ld"
121, 2193, "ANH_NPC_F0_RTC_SK_GO_UP1_LD", "Unexisting Sk_Go_Up1_Ld"
121, 2194, "ANH_NPC_F0_RTC_SK_GO_UP2_LD", "Unexisting Sk_Go_Up2_Ld"
121, 2187, "ANH_NPC_F0_RTC_SK_HURRY_UP_LD","Unexisting Sk_Hurry_Up_Ld"
121, 2177, "ANH_NPC_F0_RTC_SK_IDLE", "Unexisting Sk_Idle"
121, 2184, "ANH_NPC_F0_RTC_SK_IDL_LD", "Unexisting Sk_Idl_Ld"
121, 2188, "ANH_NPC_F0_RTC_SK_LIFT_LD", "Unexisting Sk_Lift_Ld"
121, 2191, "ANH_NPC_F0_RTC_SK_PUT_LD", "Unexisting Sk_Put_Ld"
121, 2181, "ANH_NPC_F0_RTC_SK_ROGER", "Unexisting Sk_Roger"
121, 2186, "ANH_NPC_F0_RTC_SK_RUN", "Unexisting Sk_Run"
121, 2190, "ANH_NPC_F0_RTC_SK_RUN_LD", "Unexisting Sk_Run_Ld"
121, 2182, "ANH_NPC_F0_RTC_SK_TURN_", "Unexisting Sk_Turn_"
121, 2179, "ANH_NPC_F0_RTC_SK_TURN_L_LD", "Unexisting Sk_Turn_L_Ld"
121, 2185, "ANH_NPC_F0_RTC_SK_TURN_R", "Unexisting Sk_Turn_R"
121, 2180, "ANH_NPC_F0_RTC_SK_TURN_R_LD", "Unexisting Sk_Turn_R_Ld"
121, 2196, "ANH_NPC_F0_RTC_SK_WALK", "Unexisting Sk_Walk"
121, 2189, "ANH_NPC_F0_RTC_SK_WALK_LD", "Unexisting Sk_Walk_Ld"
121, 2178, "ANH_NPC_F0_RTC_SK_WHICH_LD", "Unexisting Sk_Which_Ld"
The first number is the MODEL_ID, the second number is the ANIM_ID, the "ANH_" string is the internal animation name and the last string is the description as you find it in the field script.
So, in order to import one of these animations, do like in section I, but expect for a window to popup to import the new animation. As a full name, use the following:
assets/resources/animations/[MODEL_ID]/[ANIM_ID].anim

For instance, if you have a whole new animation to Zidane, import it with the full name "assets/resources/animations/98/179.anim". Then, in the field script, you can use the animation ID 179 to refer to it (in a "RunAnimation" line for instance).

Note that:
- There are also dummied models. I guess that you can use these as well in order to import a whole new model without the need to change the engine's code. I didn't try it though.
- there are other "dummied" animations: somes are described as "Unused", meaning that they exist and are all good, but never used in the game (unless I missed something). For now, only the animations of the enemy models were spotted as "Unused" ; some animations of the field models may be unused but not flagged (I know that Steiner at least has an unused animation that I used in AF). There are also "Dummy" animations, which means one thing: it's a very quick animation consisting of only 2 frames. Most of the time ("Dummy P", "Dummy B"...), they are also unused in the sense that they are default animations that are never actually played in-game. You can replace them as well without any regrets.

II - Importing whole new animations
Do the same as in section I, but be sure to use the following when asked to import your new animations:
assets/resources/animations/[MODEL_ID]/[NEW_ANIM_ID].anim

The NEW_ANIM_ID should be some unused animation ID. I think that it's safe to use any number between 20000 and 30000.

Once you've done that, you also need to register the animation in the engine's database. In the engine's source code (available through Albeoris's Memoria tool), go in the class "FF9DBAll". There is a Dictionary definition that takes most of the class's script:
public static Dictionary<int, string> AnimationDB

In this dictionary, add the following entry:
Code: [Select]
{ [NEW_ANIM_ID], [NEW_ANIM_STRING_ID] },
The NEW_ANIM_ID is the one you've already chosen. The NEW_ANIM_STRING_ID must follow some pattern:
ANH_[MODEL_SHORT_STRING_ID]_[Anything you want that's not already used]

The MODEL_SHORT_STRING_ID is like "MAIN_ZDN" or something. You can easily retrieve it because all the animations of that same model share the same part. You can thus search for another animation ID that belongs to the same model.

III - Importing a whole new model
Do the same as in section I (in particular, don't forget to add your model's texture first). You must import the model with the GameObject type and the following full name:
assets/resources/models/[TYPE]/[NEW_MODEL_ID]/[NEW_MODEL_ID].fbx

The full names of the animations must also follow the same pattern as in section II (with your NEW_MODEL_ID instead).

The TYPE is 1, 2, 3, 4 or 5 depending on whether the model type is an Accessory, a "Main" model, an Enemy, a NPC or a "Sub" model. Main models are typically the main characters' field models. Sub models are pretty much the remains. I don't think the model type has such an importance but you should remember what is your choice.
Also, in p0data2, there's a TYPE of 6 for Weapon models.

NEW_MODEL_ID must be an unused one. You can choose it between 6000 and 10000 without problem normally.

Then, you must register the model in the engine's code. This time, it's in the class "FF9BattleDB". There's the following dictionary:
public static Dictionary<int, string> GEO

Add an entry to it:
Code: [Select]
{ [NEW_MODEL_ID], "GEO_[MODEL_SHORT_STRING_ID]" },
The MODEL_SHORT_STRING_ID must itself follow a pattern:
[TYPE_STR]_[F/B/W][VERSION]_[Anything you want that's not already used]

TYPE_STR must be either one of these depending on the chosen model's type:
ACC, MAIN, MON, NPC, SUB, WEP

F/B/W is one letter depending on whether it's supposed to be a Field model, a Battle model or a World model. It doesn't seem too strict as some Battle models are also used inside Fields.

VERSION is a 1-digit number ; I'm not sure what it corresponds to...

The tail of the string ID can be anything you want without special character.
Example:
Code: [Select]
{ 6000, "GEO_MAIN_F0_RED_DOG" },
This model's animations must use the same pattern as in section II but with the MODEL_SHORT_STRING_ID that you've chosen.
Example:
Code: [Select]
{ 20000, "ANH_MAIN_F0_RED_DOG_TALK" },
{ 20001, "ANH_MAIN_F0_RED_DOG_RUN" },
etc...

IV - Using a whole new model and/or animation in-game
Now, hopefully, everything is correctly set but if the animation or the model never appear in-game, that wasn't worth it.

If your model/animation is supposed to be used in a Field or in a World Map, you can simply edit the script of this Field/World Map in Hades Workshop and use these assets in "SetModel" or "RunAnimation" lines. You only need to have a list of the IDs next to you because new models and new animations won't appear in the drop-list menu (unless it was "Unexisting") and you need to write the ID yourself.

However, since Hades Workshop and Memoria are not compatible, you'll need to do that on a fresh backup of your game, without Memoria installed. Then, export the mod as Steam files ; it will create a p0data7.bin archive that contains the script. You may either extract the script asset out of it using the Unity Assets Viewer (in the archive p0data7, there are descriptions that should be more than enough to spot the right asset corresponding to the Field script) or, even simpler, just replace the whole p0data7.bin file of the Memoria-modded game (but it will replace all the scripts at once so it can cancel other changes if that's not the first time you replace it).

You can't use new models/animations for enemies yet. I'm also planning on enabling it for the next version.
Finally, using other animations for the party's characters is all done in the game's engine. Maybe I'll describe how to do it another day.

I didn't lie when I said it would be a wall of text  :evil:

437
Quote
“And hast thou done the model importer?
Come to my arms, my beamish boy!
O frabjous day! Callooh! Callay!”
He chortled in his joy.

Update to v0.39 !
- Added the ability to import FBX models and/or animations in the Unity Assets Viewer,
- You can now also add new files in the game's archive instead of replacing existing ones,
- Added a first version of multi-language support (more below),
- Added the database for animations (thanks Satoh), making cutscene scripting much easier,
- Added a sound database for the enemy attack sequencing,
- Allow to add minimal comments when batch exporting scripts, for readability,
- Fixed a few bugs, including the copy/paste of enemies or their attacks ; be very careful if you used that feature in v0.38, your enemy's data is potentially corrupted (all the datas are wrong, such as a lvl of 157 or things like that).

So, the big thing of this update is the model importer. However, I will write about it in more details in my next post because - even if replacing an existing model by another can be easy - fully explaining how it works is a big wall of text. With the model importer, you can add/replace FBX models in the game, including adding/replacing animations.

Another big improvement is the first version of multi-language. Previously, you had to choose a language when opening a Steam game. As a side effect, you couldn't save mods compatible with multiple languages (nor .hws nor Steam modded files).
Now you can freely switch from one language to another by opening "File -> Preferences". You can also decide which languages you want to save (this applies to .hws files, Steam modded files and text batching). However, the loading time of several panels is increased because the data of all the languages is loaded. You have thus the possibility to decide, before opening a Steam game, to get in the old single-language mode, where only one language is loaded and you can't switch after opening the game anymore.

Now, this is only the first step of multi-language because, while you can make your mod and translate it one language by one,
1) It may be tedious to swap between languages each time you want to translate a name, description or dialog,
2) Remember that there are 2 things in HW that are language-dependant: the texts but also the script! If you modify enemy AIs or Field scripts, you need to do it for all the languages (at least those you want to be compatible).

So for the next release, I plan on reworking the text editing window (I'll use the occasion to handle these Steam text opcodes) to make the translations more convenient. I will also try, even if I'm not sure if it will be successful (fingers crossed), to add an "auto-translate" feature that can give a rough translation of your text. Of course, it will be nowhere as satisfying as a real translation but it will already be something for those who want their mod compatible in any language and don't have access to translators in all the 7 languages supported by the game.

For multi-language script editing, I think I will be able to identify scripts that are identical or very close to be identical in different languages (except for the dialog text IDs, most of the Field scripts are the same in all languages and nearly all the AI are the same). Then you can do the job only once.

Also, before moving to model importer, there's a little thing you should know about adding new assets through the Unity Assets Viewer:
- For now, you can't remove assets, only add more,
- In most cases, when you add an asset, you must check the "Bundle Info" option and add a path to your asset (something like "assets/custom_resources/my_image.png"). For making the game use your asset directly, you must refer to that path in the game's engine code,
- Because of the previous remark, you can't add a whole new asset using HW only (you can't edit the strings in the game's engine code with HW). You must use Albeoris's Memoria tool for that... but Memoria is incompatible with HW right now... However, Memoria is not incompatible with the Unity Assets Viewer so you may still decide to use HW for extracting/replacing/adding assets, give up the other features of HW and use Memoria for engine modding. Hopefully one day there will be full compatibility but I don't see that day coming anytime soon.

There's an exception for that last remark: a few dummied assets are referenced in the game's engine code but they are missing from the archives. For instance, there is a field, surely meant to be another version of the "Alexandria Castle/Public Seats" that is referenced in the game's code, has a valid ID and path to access to it and even a very small Field script file (in p0data7.bin) but no background or walkmesh. You might be able to use it for adding 1 field without replacing any other. Here are his specs:
Code: [Select]
Field ID (to use in the Field script): 1805
Event files name (file containing its Field script): EVT_ALEX3_AC_SEAT_N
Background files name (background files to add in the archive p0data11): FBG_N02_ALXC_MAP038_AC_AST_0
Since you won't be able to edit that field's script in HW, you'd need to use another field as a temporary container, do all the changes you want on that field, export its files - event files (ie. script) from p0data7, and background files (ie. .bgs, .bgi and atlas texture from p0data1X) - and add them back with adjusted names (since there's already a script file, you only need to replace it, not add).

Likewise, there seems to be unused animations that you can add without the need to change the engine's code. It's a matter I will develop in my next message.

EDIT: I will write that message tomorrow.

438
Indeed, "Sfx" in FF9's code refers to sounds of battle special effects. They use "Vfx" for the visual of battle special effects as well.

So, for removing the pitch of every sound, go to "FF9Snd::IsShiftPitchInFastForwardMode" and replace the second-to-last line "ldc.i4.1" by "ldc.i4.0". With this, all the sounds will be unaffected by the fast forward booster. I couldn't find anything specific to the cinematics' musics so I think this will remove the fast forward for these as well.

For the next update, I'm currently in the phase of fixing bugs. I had to change a big part of the background system so it was all scrambled. Hopefully, I've fixed bugs about copy/pasting spells, and I'm fixing every bug that I see, but there's still the possibility that I miss some of them.

For the dummy battle, you have two choices. Either use "RunBattleCode( 33, 1 )" that will force the battle to end with a victory (you get exp/rewards from Valia Pira but none from the dummies), or use "set (SV_EnemyTeam & (~SV_FunctionEnemy))[HP] =$ 0" that will kill all the dummies and thus trigger victory (you also get rewards from the dummies).

In both cases, put the code after the Valia Pira's death animation, in his loop function:
Code: [Select]
    AttackSpecial( 9 ) // Death Animation
    while ( IsAttacking != 0 ) {
        Wait( 1 )
    }
    set SV_FunctionEnemy[DEFEATED_ON] =$ 1 // This line is here by default and is also needed
    // Put the line here
    return

EDIT @Rosevalt: Ok ! I found what was likely to be your problem. I know that you had a workaround but I still say it so that people know.
Some characters have one of their command linked to their trance command counterpart. All of that can be seen/modified in the "Stats" panel. It is useful for letting the trance spells learned at the same rate as the normal ones, like Zidane's Dyne which are learned along his Skills. However, it has a specific requirement (else, it soft locks in battle like what you had):
all the spells under the normal command must be present in the Ability Set (in the stats panel).

That means, since you modified the spells under the "Skills" command, you should have also replaced the spells in Zidane's Ability Set in the stats panel to match the difference.

I think that this behavior holds only for the Steam version: the PSX version shouldn't have this subtility.

439
Those are the bubbles' size for dialogs (another features of the texts that is handled in PSX but not conveniently in Steam). By default, they are adjusted to the default text, but it's usually not important to edit them.
For enemy/spell names, it's useless and you can let them (or even remove them I think) ; for dialogs, I think the bubble sizes are automatically computed in some languages (at least that was the case in PSX), or maybe the vertical size (= number of lines) is automatically computed but not the horizontal size...

440
No problem. I also had the reaction of "Damn! Steam version will just offer so much more possibilities" :p

So, for Venom and Poison's frequency, it's in the exact same method as Regen's freqency, sooner in the method. The formula is "Frames to wait = wpr << 2" instead (for both). You can add lines like "ldc.i4.s 10 ; mul" or "ldc.i4.s 10 ; add" if you want to play with it.
The formula's lines are these:
Code: [Select]
ldarg.0 // This is the 1st argument passed to the method, of type BTL_DATA ; it contains a character's (or enemy's) battle infos
ldfld 0x400022B // BTL_DATA::elem ; contains the statistics
ldfld 0x4000811 // ELEMENT::wpr ; spirit
ldc.i4.2 // Put the number "2" on the stack for later left shift
shl // LeftShift( spirit, 2 )
conv.u2 // Just a conversion to unsigned short integer
stloc.1 // Store the result in a variable (used later)

However, for the durations of the statuses, they are in 2 spots and it is not possible to edit either of them :/
- In "btl_stat::AlterStatus", a page before the end, there are 3 similar formulas "Duration = (60 - spirit) << 3" (for bad statuses and jump), "Duration = spirit << 3" for good ones and "Duration = spirit << 2" by default (it doesn't seem to be used). You can't edit this method because it's too big and CIL editing tends to bug with big methods.
- In FF9BattleDB (.ctor), there is the setup of "STAT_DATA", a class for status informations, including a multiplier used after the formulas I gave above. You can't modify the method because it's too big and anyway it is one of the few methods that are specially handled by HW and modified by other means.

Maybe in a next version I'll add these multipliers to things you can edit in "Party - Special".

441
Alright, found it back.
So it's in the CIL code method "EventEngine::ProcessEncount". That's the "ldc.r4 960.000000" line, as you'd have guessed.
Note that the code that you quoted there is not exactly the code in the engine, but a summary of it (the real code lies in different methods, amid other stuff in the field's and world map's main loop).
But yeah, lowering this number seems the best option to me.

Warning: I just saw that, in the CIL code, there's some "INVALID" lines, meaning that the method uses some assembly code that I didn't register for some reason.
When editing the method, also replace the last 5 lines by these (normally, IL_00A8 should point to the last "ldc.i4.0" and IL_00A9 to "ret"):
Code: [Select]
ldc.i4.0
beq.s IL_00A8
ldc.i4.1
br.s IL_00A9
ldc.i4.0
ret

For PSX saves, I think that gjoerulv's Memoria tool can do the conversion.

442
You can use Hades Workshop to re-enable them:
First, you need a FF9 folder without gameplay mod, so remove Alternate Fantasy or use a copy of the game.
In Hades Workshop, "File -> Open" your unmodded game (select the FF9_Launcher.exe) and choose the language "English (US)" since that's the only language compatible with AF for now.
Then "File -> Open Mod" and select the file "AlternateFantasy_v4.3.hws" which is shared along with the mod. Let everything checked and apply. It will take some time to load.
Once it's imported, go to the panel "CIL Code" and sub-panel "Macros". You'll see an option "Disable Cheats" that is applied. Click on "Unapply Macro" to re-enable the cheats.
Finally, "File -> Save Steam Mod" will generate modded files with that change.

443
That may be because of that, yes. It is very easy to make your mods compatible with the HD backgrounds though. First of all, the CSharp is the only file causing problems: the p0data1X.bin are not problematic to HW. Then, for creating a mod that is compatible with HD backgrounds, open a non-modded game (or with only the p0data1X.bin swapped), go to the CIL Code -> Macros panel, then "Custom Backgrounds".
Once you're there, change the "Resolution" parameters from 32 (normal backgrounds) to 64 (upscaled backgrounds) and click on "Apply Macro". Now when you'll create the Steam Mod files, the CSharp.dll will also contain what is needed for the HD backgrounds.

Something else to know about HD backgrounds and HW: if you opened a game with the modded p0data1X.bin, containing the upscaled backgrounds, you should better go to "File -> Preferences" and change the Steam's background resolution to 64 as well. It has no effect on the mods you create, but it will display the backgrounds correctly (and HD) when viewing them in the "Fields" panel. In exchange, the loading of this panel is a bit slower, which can be boresome because it's already slow with normal backgrounds.

444
Oh yes, I forgot about the enemies' spells. It's true that they are a pain to rename :/
You can also wait for an update that allows importing PSX text in Steam. That won't be the next one because it'd already be too much, but surely the one after. I plan on working on the texts a lot after the next update:
- conversion between PSX and Steam texts,
- easy way to edit the different languages,
- make the option "Edit similar enemies" apply to the spells as well.

445
Hey Kefka :)

1) The text still can't be imported properly from PSX to Steam, and it concerns all the texts, not only the ones in the "Texts" panel.
If there is one thing that HW does less well for Steam than for PSX, it's editing and managing the texts... I have been working on multi-language support lately but I will need more time to work on the Steam text opcodes (that's what makes it troublesome).
The best solution for now would be to use file batching for dialogs, I guess, but for the rest, you'll have to copy/paste and write the Steam opcodes yourself (you can have 2 windows/panels of HW opened: one of PSX and the other for Steam).

2) Yes, the encounter rate is definitely lower in the Steam version, but the difference is indeed not in the field script. It is unclear to me what makes this difference... I've said what I saw and what I think of it here (comparing the Steam engine's code with the description of SoftReset of the PSX engine's code, it would really look like they are the same):
https://www.gamefaqs.com/boards/197338-final-fantasy-ix/75389893

3) No. What you say is correct except that it only change the few files that need to be changed (that contain the modded data). If you use the 1st choice I describe, you don't have to copy/paste files since they will be replaced directly.

@Rosevalt: I am afraid that you tried to use HW on an already modded game and that what made that bug. You should follow the advices that Kefka just quoted. Also, always think to save your mod as .hws files (Ctrl+S): they are usually the safest way to save the mods that you make, and in a very small format.

446
Ah... Then no it's not possible to do that with the PSX version, sorry :/
More precisely, it is possible because I'm quite sure that this code is in the MIPS assembly code reachable within HW, but it's not in one of the parts that are related to spell effects, so you would need to be an expert in MIPS + spend several hours to search for that code (I guess it's humanly possible by firstly spot the code using NO$PSX and then hex-searching for it, but it's barely possible).

Actually, Tiamat can increase his strength above 99 up to 255 with his strength stealing skill and there's the same skill existing for magic. I guess that only the spirit and speed can cause problems. For speed, a value of 60 is already the fastest possible, instantatly filling the ATB. I'd say that it has no effect to increase it even further.

447
For the missing enemy deaths, the sound files are present in the assets and all is correctly setup except that they forgot to register these sounds in the meta-data. You need to replace one meta-data file in the resources.assets by this one:
https://www.dropbox.com/s/n3vt8hqv2f503c9/PC_DeathSoundFix.zip?dl=1

XenoBrain did a great job fixing the audio quality here:
http://steamcommunity.com/app/377840/discussions/0/353916838206972073/

448
That one is in the method "SfxSoundPlayer::PlaySfxSound". You have, in the second half of the method, the following lines:
Code: [Select]
ldloc.1
conv.r4
ldloc.0
ldfld 0x40038A0 // SoundProfile::Pitch
mul
stloc.2
ldloc.0
ldloc.2
stfld 0x40038A0 // SoundProfile::Pitch
Remove the last 3 lines (ldloc.0, ldloc.2, stfld).
Surely that, because you don't have high pitch, you will still end up with weird sounds, with each one on top of the others. It's something to try but I'm not sure that the result will be satisfying.

449
@ste459: Controlling the ATB that accurately is not possible with Hades Workshop. It is possible with Albeoris's Memoria but you'd need to recode part of the engine for that.
However it is indeed possible to increase the Regen frequency, with both HW and Memoria. In HW, you go to CIL Code, search for the method "btl_stat -> SetOprStatusCount" and remove that part of the code:
Code: [Select]
ldarg.0
ldfld 0x400022A // BTL_DATA::elem
ldfld 0x400080F // ELEMENT::wpr
sub
It's the four lines under a "ldc.i4.s 60". The Regen frequency formula is indeed "Frames to wait = (60 - wpr) << 2", which is, in a more standard writing, "(60 - Spirit) * 4". Removing these four lines will remove the spirit part so you will always regen with the same frequency (the overall duration is something else and will still increase though). You may change the number in "ldc.i4.s 60" to adjust it if you think it's too slow (or too fast).

@Incinerator: I was bugged by the task of giving a precise answer but replying to ste459 gave me one : if you use regen on a character with 60 spirit or more, the formula above goes to negative which can either mean regen will never trigger or it will trigger every single frame (having a quick look at the code, I would incline to the latter).

450
Yes for most of it. I am not sure about changing the Max values of stats though.

For changing the stat progressions:
Go to CIL Code, then search for "ff9level" in the list on the left, then "FF9Level_GetDex", then Edit Code.
Spot the following lines near the bottom of the code.
Code: [Select]
ldarg.1
ldc.i4.s 10
div
add
ldloc.2
ldfld 0x4000885 // FF9LEVEL_BONUS::dex
ldc.i4.5
shr
add

Replace that portion by this:
Code: [Select]
ldarg.1
ldc.i4.s 5
mult
ldc.i4.s 13
div
add
ldloc.2
ldfld 0x4000885 // FF9LEVEL_BONUS::dex
ldc.i4.s 44
div
add

Then do the same for the "FF9Level_GetStr", "GetMgc" and "GetWpr". The codes are pretty similar (always replace the few lines between "ldarg.1" and "shr/add").

For changing the max values, it's at the same place but right below: you have two lines "ldc.i4.s 50" at the end of these codes (or "ldc.i4.s 99" for Str and Mgc). Replace that with 99 or 125.
In "FF9Level_GetCap", you have the limit for the magic stones ; the code is similar to the others and you'll find two lines "ldc.i4.s 99" at the end.
In "FF9Level_GetHP" (resp. "GetMP", the code is much smaller but still with two lines "ldc.i4 9999" (resp. "ldc.i4 999").

If you increase the limit of strength, magic, spirit or speed, you also need to remove the limitation from equipment boosts. It's in the method "ff9play::FF9_GetSkill". Near the 4/5 of the method, you'll find lines like these:
Code: [Select]
ldfld 0x40008AD // FF9PLAY_SKILL::Base
ldloc.0
ldelem.u1
ldloc.s 6
ldloc.0
ldelem.u1
ble IL_0328
ldarg.1
ldind.ref
ldfld 0x40008AD // FF9PLAY_SKILL::Base
Just replace the line "ble IL_0328" by "br IL_0328" and it should remove the limit totally.
It is not easy to choose the limit yourself by CIL code editing because the limit is stored in an unreachable array ("<PrivateImplementationDetails>::$$field-545").
In practice, it will then be that the base stats are limited (by whatever limit you want) and the equipment stat boosts can still increase that limit a bit.

I am not sure that increasing the max values is safe. If the HP of a character is beyond 9999, it will display a bit strangely but work just fine. However, there might be more troublesome bugs.

Pages: 1 ... 13 14 15 16 17 [18] 19 20 21 22 23 ... 35