Author Topic: [PSX/PC] General editor - Hades Workshop (0.41b)  (Read 331210 times)

ToraCarol

  • Crazy poster
  • *
  • Posts: 116
  • Karma: 11
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1550 on: 2019-06-11 10:19:32 »
Marcus's model might not have a jump animation as I don't think there is any point in the story that he jumps.
This sounds like the model moving, trying to execute an animation that doesn't exist, so instead doesn't do anything for the duration that the animation is meant to happen and then returning to the normal state.

Yeah, I think so too..so what's Jump3 stands for?  :| Probably nothing of what I used to think!

Tirlititi

  • Freak
  • *
  • Posts: 594
  • Karma: 78
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1551 on: 2019-06-11 14:30:35 »
@masagrator: Yes, that's a problem happening because of the Steam version.
Basically, they used a weird alpha channel for rendering the edges of the tiles while it was a "completly opaque/completly transparent" alternative in the PSX format.
The shift on the carpet (wow, I had a hard time seeing it even with your mark...) surely comes from the way they upscaled the images for the Steam version (because it's not a tile edge).
Fragosso knows better than me this kind of things...

@ToraCarol: There should not be any "return" line if the first "if" block that you show.
The problem with the jump animation is more likely to be the one described here. You need to use this jump animation before in the script to let the game load it (using "SetRightAnimation( 5041 )" just before "SetRightAnimation( 5224 )" is enough).
Emulating a "Change disc" screen requires modding the C# code and adding new assets (textures) to the game. I don't know if it can work, sorry.
You may more easily add a "Would you like to save?" screen, as it can simply be emulated with a dialog box... but I can understand that it's not what you want.

ToraCarol

  • Crazy poster
  • *
  • Posts: 116
  • Karma: 11
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1552 on: 2019-06-11 15:28:32 »
Quote
@ToraCarol: There should not be any "return" line if the first "if" block that you show.

The problem with the jump animation is more likely to be the one described here. You need to use this jump animation before in the script to let the game load it (using "SetRightAnimation( 5041 )" just before "SetRightAnimation( 5224 )" is enough).

Emulating a "Change disc" screen requires modding the C# code and adding new assets (textures) to the game. I don't know if it can work, sorry.
You may more easily add a "Would you like to save?" screen, as it can simply be emulated with a dialog box... but I can understand that it's not what you want.

Thank you for all you replies, as always.
I was already thinking of adding a dialog box, but I was hoping that somebody has an idea of how to emulate this thing, because as I said i'm not good on C# code an stuff... but it's ok anyway! Let's hope someone someday will find a way! For now i'll just add a dialog box!
« Last Edit: 2019-06-11 15:42:26 by ToraCarol »

ToraCarol

  • Crazy poster
  • *
  • Posts: 116
  • Karma: 11
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1553 on: 2019-06-15 16:06:21 »
I fixed the "following Character" and Marcus thing..thanks a bunch!


1) About the save dialog box, you know guys where can i put it between the Disc 1 and 2? Is kinda complicated because there's a cinematic/unexisting field and the Borden field without any particular main loop..and I don't know where to put properly without mess everything! :|

2) Also, have you find a way to solve this,Tirlititi? I've tried with "Raise Windows" but for some reason it seem to not work!

Spoiler: show


3) Last but not least, what about if I want to set in a "Trance Mode at start of the battle" other characters instead only Zidane, Steiner and Vivi? It's possible?
 I know there is something that enables "Trance Mode" in the main enemy attacks, is it correct?

« Last Edit: 2019-07-04 12:31:48 by ToraCarol »

Satoh

  • Insane poster
  • *
  • Posts: 386
  • Karma: 6
  • Assuming this statement is correct, I'm alive.
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1554 on: 2019-06-18 01:48:35 »
[...]
3) Last but not least, what about if I want to set in a "Trance Mode at start of the battle" other characters instead only Zidane, Steiner and Vivi? It's possible?
 I know there is something that enables "Trance Mode" in the main enemy attacks, is it correct?
[...]
Prison Cage; Garnet battle does this.
It has an attack that fills the Trance meter. It may be a different name in later versions of HW, but in version 0.38 its called Transfer.
in that fight there are a few important things that happen related to the trance bar filling. I'll try to show each of the important parts of the code. You can load the battle up yourself if you want to compare.

Code: [Select]
Function Main_Init
    if ( IsBattleInitialized ) {
        CloseAllWindows(  )
        Wait( 5 )
        TerminateBattle(  )
    } else {
        set SV_EnemyTeam[ATB] =$ FirstOf(SV_EnemyTeam[MAX_ATB])
        set #( VAR_GlobUInt16_33 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 0 ) )
        set #( VAR_GlobUInt16_33 |= ( SV_PlayerTeam[MODEL_TYPE] ==$ 1 ) )
    }
    return
The first check is to see if battle has ended already, that seems to be normal for most battles. Then at [else] there are some commands and one of them is setting the enemy's ATB to the MAX_ATB of the first enemy. Tirlititi will have to explain how the list assignments work because I don't fully understand them, but I know that's what's happening in that line anyway.
Next we have a variable that is looking for Zidane's dagger animation model, and one that's looking for his thief sword animation model, and setting the party slot either of them is in, to VAR_GlobUInt16_33. The code does this twice for unknown reasons, the second time fully overwriting the first one.
(if you want to change this to a random party member you can change it to this
Code: [Select]
set #( VAR_GlobUInt16_33 = RandomInTeam(SV_PlayerTeam) )now, this variable is important for later, because in that fight ONLY Zidane is supposed to start with Trance, and the game needs to know which party slot he's in, in order to target him. (the battle also tracks all the other characters this way too so there is a variable for each specific character you might want to target)

Next since we already set Prison Cage to have full ATB at the start, we have the Prison Cage ATB code (I've again removed some code not related to Trance):
Code: [Select]
Function Prison_Cage_ATB
    if ( !VAR_LocUInt8_3 ) {
        set VAR_LocUInt8_3 = 1
        set #( SV_Target = VAR_GlobUInt16_33 )
        Attack( 8 )
        return
    }
    return
VAR_LocUInt8_3 is for tracking the cutscene progression for Zidane and Steiner explaining what Trance is. To begin with, its not set, so the battle checks if it doesn't exist yet (it doesn't) and then it sets it to 1, sets the SV_Target variable to the VAR_GlobUInt16_33, which it previously set as the party slot for Zidane, so now the next attack to execute will hit Zidane. Finally, it executes Attack( 8 ) which in this battle is Transfer, which fills up a character's Trance meter completely, and then returns out of the [if] and then processes some other things I removed for brevity, and then returns again to allow the game to continue into the next cycle.

If you wanted to change the character to say, Freya, in the prison cage fight, the game locates her model and stores it in VAR_GlobUInt16_45 using this code
Code: [Select]
        set #( VAR_GlobUInt16_45 = ( SV_PlayerTeam[MODEL_TYPE] ==$ 12 ) ) just like it did for Zidane in UInt16_33
A full list of character models can be seen in the Function List, under Var Code > [DATA ACCESS]
Code: [Select]
[MODEL_TYPE]
Zidane : 0 or 1
Vivi : 2
Dagger : 3, 4, 5 or 6
Steiner : 7 or 8
Quina : 9
Eiko : 10 or 11
Freya : 12
Amarant : 13
Cinna : 14
Marcus : 15
Blank : 16 or 17
Beatrix : 18

Note, that if the character you want to target is not in the battle, the code may freeze while it looks for that character specifically, or it may skip right over the Transfer attack completely. I don't know the exact effects, but if the variables aren't set correctly in the PSX version, the battle will just stall as the game tries to attack something that doesn't exist. Tirlititi may have advice on doing other things with targetting.

Battle code is all pretty new to me, but I did just look into this last night, ironically, so I figured I'd explain what I already figured out.
« Last Edit: 2019-06-18 02:03:10 by Satoh »

ToraCarol

  • Crazy poster
  • *
  • Posts: 116
  • Karma: 11
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1555 on: 2019-06-20 10:02:25 »
Thank you for the reply Satoh! Il check soon  8)
« Last Edit: 2019-07-04 12:31:56 by ToraCarol »

TheHobgoblin

  • Fast newbie
  • *
  • Posts: 6
  • Karma: 2
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1556 on: 2019-06-23 22:47:52 »
Not really a technical question, but since I want to develop the temporary characters into full ones...

I think I can just move Beatrix over to Sword Art and White Magic-- in fact, link all 3 white mages to the same White Magic command. That will free up some space.

I think I will get rid of the SFX commands and instead just make the "theater" versions of everyone the same as their normal version. They only do 1 fight using those commands anyway.

I can also get rid of the superfluous Magic commands.

That leaves me with choices with the other three.

Being able to do away with the SFX commands gives me 14 new abilities I can make.

So should I

1) Make 4 unique commands for one and 5 for the other two
2) Make Cinna "Green Mage/Gray Mage" so that he would make use of spells from the White Magic and Black Magic lists. Then I can maybe give Marcus and Blank 7 unique commands each (I think I might be able to squeeze this in without running into the command limit since I am pruning unneeded ones)
3) Find a way to expand the Ability List as well as the Command list so that all 3 can have 8 unique commands each.

Since I am already editing the assembly file in order to try to increase the number of slots from 9 to 12 so that the additional characters can be used uniquely and I haven't completely solved that, the only trick to increasing the lists for spells and commands is that I won't be able to further edit it with Hades Workshop. And it would be so much easier to use it to edit the abilities than try to figure out how to do it via hex-editor or something.

And I haven't completely solved the puzzle on how to do it yet anyway. I honestly haven't been working on it much for the past few months.
But I have worked out how to turn that starting area into a test area by assigning it a random encounter script and then putting the characters I want to test into the initial party.

Addendum:

Seeing what I could free up in the Commands list by combining similar commands and removing the unused/1 time use ones, I can arrange this to 34 command blocks free.
That it plenty enough to turn Cinna into a proper mage with plenty of spells taken from the black mage/white mage/blue mage lists and still leave enough room for the other two to get 8 commands each, even if 1 has to be a pre-existing ability.
« Last Edit: 2019-06-23 23:28:59 by TheHobgoblin »

TheHobgoblin

  • Fast newbie
  • *
  • Posts: 6
  • Karma: 2
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1557 on: 2019-07-08 05:00:15 »
I think I am 95+% of the way to expanding the character slots from 9 to 12, allowing the remaining 3 characters to be fully utilized.

I have spent basically the past two days on it.

To get as far as I did involved editing all of these classes

Under the "-" category
Actor
btl_init
ETb
EventEngine
FF9PARTY_INFO
ff9play
FF9StateGlobal
FieldHUD
NameSettingUI
NGUIText
PartySettingUI
PLAYER
ShopUI


Under the "FF9" category
ff9abil
ff9shop
FFSHOP_INFO

I will try to give more detailed information in the future.

It seems like Beatrix has to remain the slot 8 character with Cinna, Marcus and Blank becoming 9, 10 and 11 respectively. Initially I was going to try to match their slots to their character numbers, but for whatever reason it didn't work out. I was getting everyone's models shifted by 1 place (Blank was using Beatrix's model, Marcus had Blanks and Cinna had Marcus's)

In fact, the entire thing might be working now, but the issue I am having is that at the end of that initial battle, when the mask is supposed to come off, the game crashes and it reports a violation with the SFX file. I don't know if it is the character animation of the mask falling off or if it is the game trying to focus the camera on the opponent that is causing the crash, but it is one of the two.

But, after experimentation I found that if I leave every other change, but just change two numbers in the EventEngine file, that the game runs smoothly (at least for that first room) but Cinna, Marcus and Blank take the models of Quina, Eiko and Amarant respectively.

I feel like if I can just track down this one error then the job will be completed.


In the meantime, to experiment with this further, I would like to know how to change the game script so that I can add a change party members NPC in the first room. I already figured out how to put battles there. Any clues on how to do it?

Also, is there any possible way to change the settings for Hade's Workshop that would allow me to edit my already edited assembly instead of having to switch back and forth between an edited and unedited one?

ToraCarol

  • Crazy poster
  • *
  • Posts: 116
  • Karma: 11
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1558 on: 2019-07-17 12:59:00 »
Hello guys, I'm sorry if I bother but I really hope anyone can help me with this one

Spoiler: show


As you can see in this image, there's a text window..with no text inside it! Why this happens? How to solve?
« Last Edit: 2019-07-17 15:22:48 by ToraCarol »

DavidBest1996

  • Newbie
  • *
  • Posts: 2
  • Karma: 1
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1559 on: 2019-07-18 11:59:36 »
Hello, sorry for the silly question but in Hades Workshop I modify some Ending texts but I can't modify the arguments of Text Command "Center" (I think opcode 0x48). Whatever number I write in, it become default again automatically after closing the window, I dunno why, and I don't find any answer about it (sorry for bad english)
« Last Edit: 2019-07-18 12:04:36 by DavidBest1996 »

Incinerator

  • Guest
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1560 on: 2019-07-19 20:43:05 »
Hello guys, I'm sorry if I bother but I really hope anyone can help me with this one

Spoiler: show


As you can see in this image, there's a text window..with no text inside it! Why this happens? How to solve?

Looks like a script called text that doesn't exist!.

ToraCarol

  • Crazy poster
  • *
  • Posts: 116
  • Karma: 11
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1561 on: 2019-07-20 11:36:29 »
Looks like a script called text that doesn't exist!.

Thank you for the reply Incinerator..so how can I solve this missing? What did I or didn't I do? I've tried some things but looks like i really don't know how to come through this  :(

Incinerator

  • Guest
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1562 on: 2019-07-23 21:10:24 »
Thank you for the reply Incinerator..so how can I solve this missing? What did I or didn't I do? I've tried some things but looks like i really don't know how to come through this  :(

I'm a such a turtle!
Is you text added in right text block for this field (iirc Text Panel -> Alexander)

anxietymafia

  • Newbie
  • *
  • Posts: 4
  • Karma: 0
    • View Profile
Re: [FF9] General editor - Hades Workshop (0.31b)
« Reply #1563 on: 2019-07-24 08:13:51 »
I took Eiko on Lv1 editing Field scripts at Conde Petie Mountain Path in the function "Main_Loop" (Marcus' level was 21)

Hi Vivigix (or anyone else),
Realize this is old but,
I was wondering if what your wrote here is specific to the PSX version? Recently decided to add it to my game, but the code seems to be different for steam (although similar). Would appreciate any advice you'd have for achieving this on the steam version (also for the other characters).

In Hades workshop, for Eiko the code is:

Code: [Select]
Function Main_Loop
    if ( General_FieldEntrance == 65535 ) {
        set Setting_PartyReserve = 103
        SetPartyReserve( Setting_PartyReserve )
        if ( IsInParty(5) ) {
            RemoveParty( 5 )
            set VARL_GenUInt8_303 = 0
            set VAR_GenInt8_60 = ( VAR_GenInt8_61 = ( VAR_GenInt8_62 = ( VAR_GenInt8_63 = ( VAR_GlobInt16_8 = ( VAR_GlobInt16_10 = ( VAR_GlobInt16_12 = ( VAR_GlobInt16_14 = 65535 ) ) ) ) ) ) )
            set VAR_GlobInt16_14 = 0
            while ( VAR_GlobInt16_14 <= 11 ) {
                if ( IsInParty(VAR_GlobInt16_14) ) {

EDIT: Actually, you know what I figured this out I think. You only need to change 1 number in each. I’m going to release this as a hws for anyone else who needs help. Thanks for the info!
« Last Edit: 2019-07-27 17:36:15 by anxietymafia »

Tirlititi

  • Freak
  • *
  • Posts: 594
  • Karma: 78
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1564 on: 2019-07-24 11:38:15 »
Sorry for not answering. I am working back a bit on HW in view of releasing a new version. I'll mainly try to fix compatibility issues (Albeoris's Memoria, Moguri Mod, Audio fix and other DLL editing mods...). I'll use the occasion to fix a couple of bugs too.

Thanks a bunch DavidBest1996 for telling me about that one; it's fixed and the next version will be working better on PSX files again.

Good job so far TheHobgoblin ^^
You can see examples of NPC scripts here, there and there. The important steps are: add an NPC entry (or use one of the free "player" entries that are after all the others and usually have no functions at first), add an "Init" and a "SpeakBTN" function, setup the model+position in the "Init" and use "SetPartyReserve( xxx )" and "Party( 4, 0 )" in the "SpeakBTN".
« Last Edit: 2019-07-24 11:41:00 by Tirlititi »

ToraCarol

  • Crazy poster
  • *
  • Posts: 116
  • Karma: 11
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1565 on: 2019-07-24 20:48:59 »
I'm a such a turtle!
Is you text added in right text block for this field (iirc Text Panel -> Alexander)

In my case (Invincible-Garland) the text is on "Alexandria (Night)". I simply added new dialogs next the other ones for Garland,Kuja etc.. and in the script it let me ready the Dialog Window

Spoiler: show


What I don't get,so, is why it give me this kind of error...

It's a scene added after the "Hilda Garde I" talk with Zorn and Thorn, I simply added a new Variable and a general field entrance... like the other scene on Lindblum that work perfectly..kinda strange..idk.

Spoiler: show


And not worries Tirlititi you're doing such an amazing and huge of work so it's ok to not have time for everything anyway  ;D
« Last Edit: 2019-07-24 20:52:10 by ToraCarol »

DavidBest1996

  • Newbie
  • *
  • Posts: 2
  • Karma: 1
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1566 on: 2019-07-29 06:35:59 »
You're welcome, Tirlititi, on the contrary, thanks to you to fix that :)... I seriously thought to be dumb not figuring out why not working.
I look forward to download the newer version, thanks for your great job in this, I hope that my problem doesn't slow down too much your working  :D (again sorry for bad english)

Tirlititi

  • Freak
  • *
  • Posts: 594
  • Karma: 78
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1567 on: 2019-08-02 19:03:49 »
Update to v0.41:
- Added a Randomizer tool, including the slightly modified features of Meteor On FFIX (which was only working on the PSX US version) and a way to randomize the enemies' spells (unfairness is guaranteed),
- Added more flexibility and compatibility with other mods or modding tools:
--- You should now be able to open and append changes to Assembly-CSharp.dll mods created by other means (Sound Fix, dnSpy-edited DLL, etc...) as long as they don't change the structure of some key things (the datas read by Hades Workshop, such as the spells (AA_DATA)...),
--- Since Albeoris's Memoria change the structure of these key things, you still can't open the Memoria-modded DLL; however, you can now generate .csv files that are suitable to Memoria for most of the modifications. There's a couple of modifications that requires a bit of dnSpy hacking to complete the merging of the mod though: the Magic Sword requirement spells and the Battles' battleground changes (both of them are not editable yet using only Memoria),
--- You may directly generate the assets instead of the full-fledged archive files; this way, assets can be imported into archives modded in different manners and easily merge mods as long as they don't change the same assets (but do change the same archives),
--- Fixed different bugs with the PSX versions of the game; Hades Workshop should fully work on them again (also, the Randomizer works on the PSX version, minus the possibility to have non-updated spell names or descriptions due to the lack of space),
- Fixed a few other bugs (the one pointed by DavidBest1996, the very large numbers bugging in the Script editor, a "switch case + do-while loop" decompilation error...) and improved a few things.

I am still on a break with FF9 modding. I will surely just update my mod Alternate Fantasy to have compatibility with other mods, but then I'll return to not making things.

Note that Gael-Honorez-sb added CMake files to generate Hades Workshop projects using CMake on GitHub. I always have troubles with CMake (but with Visual Studio as well anyway) but it will surely ease the work of people trying to use the tool's source code. Let him be thanked for that.


@ToraCarol: Maybe it has something to do with the dialog itself? What text opcodes are you using?
« Last Edit: 2019-08-02 19:10:19 by Tirlititi »

Incinerator

  • Guest
Re: [PSX/PC] General editor - Hades Workshop (0.40b)
« Reply #1568 on: 2019-08-02 20:52:36 »
Excellent update @Tirlititi!  8)
Everyone on compiled CSharp works well with edited one (using dnspy). Did a brief test changing an spell animation and generated CSharp caused no crash!.

Tirlititi

  • Freak
  • *
  • Posts: 594
  • Karma: 78
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.41)
« Reply #1569 on: 2019-08-03 12:16:32 »
Hold everything!
I found a bug when loading HWS files containing Spell Animations. It corrupts the saves done after that.

If you loaded HWS files containing Spell Animations and then saved HWS again with the version 0.41, you must do that, using the version 0.41b:
- Open the HWS with your latest changes (saved with v0.41) without the Spell Animations (it should crash anyway if you load them),
- Open a previous HWS with Spell Animations changes (saved with <= v040b) if you have a backup or do the Spell Animations changes again.
- Save as HWS; that's fine.

If you don't have a backup, you can also send me your (corrupted) HWS file and I will fix it.

Sorry for the troubles...
« Last Edit: 2019-08-03 13:14:08 by Tirlititi »

Incinerator

  • Guest
Re: [PSX/PC] General editor - Hades Workshop (0.41)
« Reply #1570 on: 2019-08-03 15:47:30 »
Hold everything!
I found a bug when loading HWS files containing Spell Animations. It corrupts the saves done after that.

If you loaded HWS files containing Spell Animations and then saved HWS again with the version 0.41, you must do that, using the version 0.41b:
- Open the HWS with your latest changes (saved with v0.41) without the Spell Animations (it should crash anyway if you load them),
- Open a previous HWS with Spell Animations changes (saved with <= v040b) if you have a backup or do the Spell Animations changes again.
- Save as HWS; that's fine.

If you don't have a backup, you can also send me your (corrupted) HWS file and I will fix it.

Sorry for the troubles...

Good to know warning;
Luckily for me, I didn't use .hws file from v040b!  8-) I literally went this whole test ride without saving .hws. How risky!

anxietymafia

  • Newbie
  • *
  • Posts: 4
  • Karma: 0
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.41b)
« Reply #1571 on: 2019-08-05 11:09:45 »
Hi Tirlititi,

Thanks for your tool, I am having heaps of fun with it.

In regards to ongoing modding using the tool, I have made some mods I liked, saved the binary file. If I then later want to mod the disc further, is it safe to use Hades Workshop to open the disc, further mod, and save again? Is there harm in doing so?

I noticed you have said not to use the ppf on previously modified binaries. So if you saved the binary, then tried to mod it with a ppf on the modded binary, bugs can occur? When first playing with the tool, I noticed data corruption of a sort doing that, soft locks and such. I guess what I am asking, if I want to continually mod a binary file is simply overwriting it with Hades workshop safe vs ppf which is not?

Thanks.

btw, I used info in this thread from pesmerga and vivigix to make hws files for all party members join the party at lvl 1, (blank, freya, quina, amarant, and eiko), and to remove the time requirement for the excalibur II. i had trouble figuring it out at first, so i thought id upload for posterity and for anyone else. Feel free to use them as you see fit. https://www.mediafire.com/file/m9l71byhuwcf27o/LVL_1_and_EXII_scripts.7z/file
« Last Edit: 2019-08-06 13:38:44 by anxietymafia »

Tirlititi

  • Freak
  • *
  • Posts: 594
  • Karma: 78
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.41b)
« Reply #1572 on: 2019-08-08 22:11:11 »
For the PSX version, it is always safe to open a non-modded version of the game, save mods as .hws and then overwrite binary files.

Here is how it works:
- Save Mod (.hws files) registers the modifications done with the tool since you opened the .bin file; it doesn't know anything about previous modifications you could have done before.
- Export as PPF does a comparison between the file on your hard drive and the modifications done with the tool since you opened the .bin file; it produces a patch that is only good for the file you had on your hard drive at the time you created it (hence the need to use that on non-modded versions).
- Overwrite binary files changes the file on your hard drive but also resets the modification track (if I remember correctly... it may not be the case anymore), that's why it should be used after saving a .hws, or else you'll lost the capability to update your mod after closing the tool.

Also, .hws files can be used to move your mod from a disc to another (instead of repeating the same modifications 4 times).

There can be bugs when opening a modded PSX game file and even if there is no bug by chance, the tool has no way to remember what were the modifications you did on a file before, so it won't mark some parts as modified (for exporting PPF for instance) even though they are not the vanilla (non-modded) datas anymore.

lvb

  • Newbie
  • *
  • Posts: 4
  • Karma: 0
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.41b)
« Reply #1573 on: 2019-08-10 10:01:34 »
Greetings, I'm new member here.
I have looked up some tools for FF IX and found this gem to make the game harder.
My problem is understanding the script, which I didn't know how to find the code reference, i.e the meaning of
VAR_LocInt24_9 means ????, and something like that.

I am now in the editing script of Necron attack pattern.
I just looked at https://finalfantasy.fandom.com/wiki/Necron_(boss) which there show some sort of Ai Script.
Have compared the script between HadesWorkshop script and ff fandom wiki script shown but still I have difficulties to understand it because some code were different i.e:

- On Hades Workshop
Code: [Select]
set VAR_LocInt8_29 = VAR_LocUInt8_28
        while ( VAR_LocInt8_29 >= 0 ) {
            switch 8 ( VAR_LocInt24_24 ) from 0 {
            case +0:
                set #( SV_Target = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
                break

- FF fandom wiki
Code: [Select]
if ( dummyindex == 1 )
      if ( ( #NotMatching(SV_PlayerTeam[STATUS_CURRENT], PETRIFY | VENOM | DEATH | STOP | LOW_HP) < 4 ) && ( targetamount != 0 ) )
         set SV_FunctionEnemy[PREVENT_ATTACK] = 1
   elseif ( dummyindex == 2 )

I don't understand how to relate these. What is 257, what is 64, can i put random number like 200 or 120 as I like, and why < 4, why >=0, etc .



If someone could raw translate this Necron script (what is "VAR_LocUInt8_1", or "VAR_LocUInt16_4", or "SV_PlayerTeam[STATUS_CURRENT_B], 32", etc means) :
Code: [Select]
Function Dummy_ATB
    switch 3 ( VAR_LocUInt8_1 ) from 1 {
    case +0:
        if ( VAR_LocUInt8_8 ) {
            set #( VAR_LocUInt16_4 = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
        } else {
            set #( VAR_LocUInt16_4 = 1 )
        }
        set VAR_LocInt24_24 = ( VAR_LocInt24_21 & 7 )
        set VAR_LocInt24_33 = GetRandom
        set VAR_LocInt24_36 = 128
        set VAR_LocInt8_29 = ( VAR_LocUInt8_28 - 1 )
        while ( VAR_LocInt8_29 >= 0 ) {
            if ( VAR_LocInt24_33 > VAR_LocInt24_36 ) {
                break
            }
            set VAR_LocInt24_36 >>= 1
            set VAR_LocInt8_29--
        }
        if ( VAR_LocInt8_29 == 65535 ) {
            set VAR_LocInt8_29 = ( VAR_LocUInt8_28 - 1 )
        }
        if ( VAR_LocInt8_29 == ( VAR_LocUInt8_28 - 1 ) ) {
            set VAR_LocInt24_21 = ( ( VAR_LocInt24_21 >> 3 ) & 2097151L )
            set VAR_LocInt24_21 |= ( VAR_LocInt24_24 << ( VAR_LocInt8_29 * 3 ) )
        } else {
            if ( VAR_LocInt8_29 ) {
                set VAR_LocInt24_30 = ( VAR_LocInt24_24 << ( VAR_LocInt8_29 * 3 ) )
                set VAR_LocInt24_33 = ( ( 1 << ( ( VAR_LocInt8_29 + 1 ) * 3 ) ) - 1 )
                set VAR_LocInt24_36 = ( ( VAR_LocInt24_33 & VAR_LocInt24_21 ) >> 3 )
                set VAR_LocInt24_36 |= VAR_LocInt24_30
                set VAR_LocInt24_33 ^= 16777215L
                set VAR_LocInt24_21 &= VAR_LocInt24_33
                set VAR_LocInt24_21 |= VAR_LocInt24_36
            }
        }
        set VAR_LocInt8_29 = VAR_LocUInt8_28
        while ( VAR_LocInt8_29 >= 0 ) {
            switch 8 ( VAR_LocInt24_24 ) from 0 {
            case +0:
                set #( SV_Target = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
                break
            case +1:
                set #( SV_Target = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
                break
            case +2:
                set #( SV_Target = SV_PlayerTeam )
                break
            case +3:
                set #( SV_Target = VAR_LocUInt16_4 )
                break
            case +4:
                set #( SV_Target = VAR_LocUInt16_4 )
                break
            case +5:
                set #( SV_Target = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
                break
            case +6:
                set #( SV_Target = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
                break
            case +7:
                set #( SV_Target = SV_FunctionEnemy )
            }
            if ( VAR_LocInt24_24 >= 4 ) {
                set VAR_LocInt24_33 = ( ( VAR_LocInt24_18 >> ( ( VAR_LocInt24_24 - 4 ) * 6 ) ) & 63 )
            } else {
                set VAR_LocInt24_33 = ( ( VAR_LocInt24_15 >> ( VAR_LocInt24_24 * 6 ) ) & 63 )
            }
            set VAR_LocInt24_30 = ( #SV_Target )
            set VAR_LocInt24_36 = FirstOf(SV_FunctionEnemy[MP])
            if ( VAR_LocInt24_30 && ( VAR_LocInt24_33 <= VAR_LocInt24_36 ) ) {
                break
            }
            if ( VAR_LocInt8_29 <= 0 ) {
                break
            }
            set VAR_LocInt24_24 = ( VAR_LocInt24_21 & 7 )
            set VAR_LocInt24_21 = ( ( VAR_LocInt24_21 >> 3 ) & 2097151L )
            set VAR_LocInt24_21 |= ( VAR_LocInt24_24 << ( ( VAR_LocUInt8_28 - 1 ) * 3 ) )
            set VAR_LocInt8_29--
        }
        if ( VAR_LocInt24_24 >= 4 ) {
            set VAR_LocUInt8_27 = ( ( VAR_LocInt24_12 >> ( ( VAR_LocInt24_24 - 4 ) * 6 ) ) & 63 )
        } else {
            set VAR_LocUInt8_27 = ( ( VAR_LocInt24_9 >> ( VAR_LocInt24_24 * 6 ) ) & 63 )
        }
        if ( VAR_LocUInt8_27 == 9 ) {
            set VAR_LocUInt8_8 = 1
        }
        break
    case +1:
        set VAR_LocInt24_24 = ( VAR_LocInt24_21 & 7 )
        set VAR_LocInt24_33 = GetRandom
        set VAR_LocInt24_36 = 128
        set VAR_LocInt8_29 = ( VAR_LocUInt8_28 - 1 )
        while ( VAR_LocInt8_29 >= 0 ) {
            if ( VAR_LocInt24_33 > VAR_LocInt24_36 ) {
                break
            }
            set VAR_LocInt24_36 >>= 1
            set VAR_LocInt8_29--
        }
        if ( VAR_LocInt8_29 == 65535 ) {
            set VAR_LocInt8_29 = ( VAR_LocUInt8_28 - 1 )
        }
        if ( VAR_LocInt8_29 == ( VAR_LocUInt8_28 - 1 ) ) {
            set VAR_LocInt24_21 = ( ( VAR_LocInt24_21 >> 3 ) & 2097151L )
            set VAR_LocInt24_21 |= ( VAR_LocInt24_24 << ( VAR_LocInt8_29 * 3 ) )
        } else {
            if ( VAR_LocInt8_29 ) {
                set VAR_LocInt24_30 = ( VAR_LocInt24_24 << ( VAR_LocInt8_29 * 3 ) )
                set VAR_LocInt24_33 = ( ( 1 << ( ( VAR_LocInt8_29 + 1 ) * 3 ) ) - 1 )
                set VAR_LocInt24_36 = ( ( VAR_LocInt24_33 & VAR_LocInt24_21 ) >> 3 )
                set VAR_LocInt24_36 |= VAR_LocInt24_30
                set VAR_LocInt24_33 ^= 16777215L
                set VAR_LocInt24_21 &= VAR_LocInt24_33
                set VAR_LocInt24_21 |= VAR_LocInt24_36
            }
        }
        set VAR_LocInt8_29 = VAR_LocUInt8_28
        while ( VAR_LocInt8_29 >= 0 ) {
            switch 8 ( VAR_LocInt24_24 ) from 0 {
            case +0:
                set #( SV_Target = SV_PlayerTeam )
                break
            case +1:
                set #( SV_Target = SV_PlayerTeam )
                break
            case +2:
                set #( SV_Target = SV_PlayerTeam )
                break
            case +3:
                set #( SV_Target = SV_FunctionEnemy )
                break
            case +4:
                set #( SV_Target = SV_FunctionEnemy )
                break
            case +5:
                set #( SV_Target = SV_FunctionEnemy )
                break
            case +6:
                set #( SV_Target = SV_FunctionEnemy )
                break
            case +7:
                set #( SV_Target = SV_FunctionEnemy )
            }
            if ( VAR_LocInt24_24 >= 4 ) {
                set VAR_LocInt24_33 = ( ( VAR_LocInt24_18 >> ( ( VAR_LocInt24_24 - 4 ) * 6 ) ) & 63 )
            } else {
                set VAR_LocInt24_33 = ( ( VAR_LocInt24_15 >> ( VAR_LocInt24_24 * 6 ) ) & 63 )
            }
            set VAR_LocInt24_30 = ( #SV_Target )
            set VAR_LocInt24_36 = FirstOf(SV_FunctionEnemy[MP])
            if ( VAR_LocInt24_30 && ( VAR_LocInt24_33 <= VAR_LocInt24_36 ) ) {
                break
            }
            if ( VAR_LocInt8_29 <= 0 ) {
                break
            }
            set VAR_LocInt24_24 = ( VAR_LocInt24_21 & 7 )
            set VAR_LocInt24_21 = ( ( VAR_LocInt24_21 >> 3 ) & 2097151L )
            set VAR_LocInt24_21 |= ( VAR_LocInt24_24 << ( ( VAR_LocUInt8_28 - 1 ) * 3 ) )
            set VAR_LocInt8_29--
        }
        if ( VAR_LocInt24_24 >= 4 ) {
            set VAR_LocUInt8_27 = ( ( VAR_LocInt24_12 >> ( ( VAR_LocInt24_24 - 4 ) * 6 ) ) & 63 )
        } else {
            set VAR_LocUInt8_27 = ( ( VAR_LocInt24_9 >> ( VAR_LocInt24_24 * 6 ) ) & 63 )
        }
        set #( VAR_LocUInt16_6 = RandomInTeam(( ( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_PlayerTeam[STATUS_CURRENT_B], 64) ) & ( ~( Matching(SV_PlayerTeam[STATUS_CURRENT_B], 32) | Matching(SV_PlayerTeam[STATUS_AUTO_B], 32) ) ) )) )
        if ( !( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 4355) & VAR_LocUInt16_6 ) ) ) {
            set #( SV_Target = 1 )
        }
        break
    case +2:
        set #( VAR_LocUInt16_2 = 0 )
        if ( ( FirstOf(VAR_GlobUInt16_24[HP]) - 10000 ) < ( ( FirstOf(VAR_GlobUInt16_24[MAX_HP]) - 10000 ) >> 1 ) ) {
            set #( VAR_LocUInt16_2 = VAR_GlobUInt16_24 )
        } else {
            set #( VAR_LocUInt16_2 = 1 )
        }
        set VAR_LocInt24_24 = ( VAR_LocInt24_21 & 7 )
        set VAR_LocInt24_33 = GetRandom
        set VAR_LocInt24_36 = 128
        set VAR_LocInt8_29 = ( VAR_LocUInt8_28 - 1 )
        while ( VAR_LocInt8_29 >= 0 ) {
            if ( VAR_LocInt24_33 > VAR_LocInt24_36 ) {
                break
            }
            set VAR_LocInt24_36 >>= 1
            set VAR_LocInt8_29--
        }
        if ( VAR_LocInt8_29 == 65535 ) {
            set VAR_LocInt8_29 = ( VAR_LocUInt8_28 - 1 )
        }
        if ( VAR_LocInt8_29 == ( VAR_LocUInt8_28 - 1 ) ) {
            set VAR_LocInt24_21 = ( ( VAR_LocInt24_21 >> 3 ) & 2097151L )
            set VAR_LocInt24_21 |= ( VAR_LocInt24_24 << ( VAR_LocInt8_29 * 3 ) )
        } else {
            if ( VAR_LocInt8_29 ) {
                set VAR_LocInt24_30 = ( VAR_LocInt24_24 << ( VAR_LocInt8_29 * 3 ) )
                set VAR_LocInt24_33 = ( ( 1 << ( ( VAR_LocInt8_29 + 1 ) * 3 ) ) - 1 )
                set VAR_LocInt24_36 = ( ( VAR_LocInt24_33 & VAR_LocInt24_21 ) >> 3 )
                set VAR_LocInt24_36 |= VAR_LocInt24_30
                set VAR_LocInt24_33 ^= 16777215L
                set VAR_LocInt24_21 &= VAR_LocInt24_33
                set VAR_LocInt24_21 |= VAR_LocInt24_36
            }
        }
        set VAR_LocInt8_29 = VAR_LocUInt8_28
        while ( VAR_LocInt8_29 >= 0 ) {
            switch 8 ( VAR_LocInt24_24 ) from 0 {
            case +0:
                set #( SV_Target = VAR_LocUInt16_2 )
                break
            case +1:
                set #( SV_Target = RandomInTeam(( ( NotMatching(SV_EnemyTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_EnemyTeam[STATUS_CURRENT_B], 64) ) & ( ~Matching(SV_EnemyTeam[STATUS_CURRENT_A], 4194304L) ) )) )
                break
            case +2:
                set #( SV_Target = RandomInTeam(( ( NotMatching(SV_EnemyTeam[STATUS_CURRENT_A], 257) & NotMatching(SV_EnemyTeam[STATUS_CURRENT_B], 64) ) & ( ~Matching(SV_EnemyTeam[STATUS_CURRENT_A], 8388608L) ) )) )
                break
            case +3:
                set #( SV_Target = SV_FunctionEnemy )
                break
            case +4:
                set #( SV_Target = SV_FunctionEnemy )
                break
            case +5:
                set #( SV_Target = SV_FunctionEnemy )
                break
            case +6:
                set #( SV_Target = SV_FunctionEnemy )
                break
            case +7:
                set #( SV_Target = SV_FunctionEnemy )
            }
            if ( VAR_LocInt24_24 >= 4 ) {
                set VAR_LocInt24_33 = ( ( VAR_LocInt24_18 >> ( ( VAR_LocInt24_24 - 4 ) * 6 ) ) & 63 )
            } else {
                set VAR_LocInt24_33 = ( ( VAR_LocInt24_15 >> ( VAR_LocInt24_24 * 6 ) ) & 63 )
            }
            set VAR_LocInt24_30 = ( #SV_Target )
            set VAR_LocInt24_36 = FirstOf(SV_FunctionEnemy[MP])
            if ( VAR_LocInt24_30 && ( VAR_LocInt24_33 <= VAR_LocInt24_36 ) ) {
                break
            }
            if ( VAR_LocInt8_29 <= 0 ) {
                break
            }
            set VAR_LocInt24_24 = ( VAR_LocInt24_21 & 7 )
            set VAR_LocInt24_21 = ( ( VAR_LocInt24_21 >> 3 ) & 2097151L )
            set VAR_LocInt24_21 |= ( VAR_LocInt24_24 << ( ( VAR_LocUInt8_28 - 1 ) * 3 ) )
            set VAR_LocInt8_29--
        }
        if ( VAR_LocInt24_24 >= 4 ) {
            set VAR_LocUInt8_27 = ( ( VAR_LocInt24_12 >> ( ( VAR_LocInt24_24 - 4 ) * 6 ) ) & 63 )
        } else {
            set VAR_LocUInt8_27 = ( ( VAR_LocInt24_9 >> ( VAR_LocInt24_24 * 6 ) ) & 63 )
        }
    }
    switch 9 ( VAR_LocUInt8_27 ) from 7 {
    case +0:
        if ( #( SV_FunctionEnemy[MP] <$ 46 ) ) {
            set VAR_LocUInt8_27 = 16
        }
        break
    case +1:
        if ( #( SV_FunctionEnemy[MP] <$ 36 ) ) {
            set VAR_LocUInt8_27 = 16
        }
        break
    case +2:
        if ( #( SV_FunctionEnemy[MP] <$ 40 ) ) {
            set VAR_LocUInt8_27 = 16
        }
        break
    case +3:
        if ( #( SV_FunctionEnemy[MP] <$ 24 ) ) {
            set VAR_LocUInt8_27 = 16
        }
        break
    case +4:
        if ( #( SV_FunctionEnemy[MP] <$ 24 ) ) {
            set VAR_LocUInt8_27 = 16
        }
        break
    case +5:
        if ( #( SV_FunctionEnemy[MP] <$ 24 ) ) {
            set VAR_LocUInt8_27 = 16
        }
        break
    case +6:
        if ( #( SV_FunctionEnemy[MP] <$ 20 ) ) {
            set VAR_LocUInt8_27 = 16
        }
        break
    case +7:
        if ( #( SV_FunctionEnemy[MP] <$ 8 ) ) {
            set VAR_LocUInt8_27 = 16
        }
        break
    case +8:
        if ( #( SV_FunctionEnemy[MP] <$ 8 ) ) {
            set VAR_LocUInt8_27 = 16
        }
        break
    }
    if ( SV_Target == 0 ) {
        set VAR_LocUInt8_27 = 16
    }
    switch 3 ( VAR_LocUInt8_1 ) from 1 {
    case +0:
        if ( ( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 4355) & ( ~Matching(SV_PlayerTeam[STATUS_CURRENT_A], 512) ) ) ) < 4 ) {
            set #( SV_Target = 0 )
            set VAR_LocUInt8_27 = 16
        }
        break
    case +1:
        if ( ( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 4355) & ( ~Matching(SV_PlayerTeam[STATUS_CURRENT_A], 512) ) ) ) < 3 ) {
            set #( SV_Target = 0 )
            set VAR_LocUInt8_27 = 16
        }
        break
    case +2:
        if ( ( #( NotMatching(SV_PlayerTeam[STATUS_CURRENT_A], 4355) & ( ~Matching(SV_PlayerTeam[STATUS_CURRENT_A], 512) ) ) ) < 2 ) {
            set #( SV_Target = 0 )
            set VAR_LocUInt8_27 = 16
        }
        break
    }
    set VAR_LocUInt8_39 = ( #SV_Target )
    Attack( VAR_LocUInt8_27 )
    return

And tell me how to understand this by relate the code to 'where', maybe later I can read the rest script used on another enemies, I will be very much helped.

I have read the tips on page 1 posted by Tirlititi and still confused. I have no background of reading the code but I want to know.
I am sorry for the inconvenience.
Thank you very much.

Tirlititi

  • Freak
  • *
  • Posts: 594
  • Karma: 78
    • View Profile
Re: [PSX/PC] General editor - Hades Workshop (0.41b)
« Reply #1574 on: 2019-08-10 13:59:39 »
I am the one who put the AI script on ffwikia. They are indeed a bit reworked there to make it more clear.

Firstly, the example you gave do not compare the same things. You are not in the same function or at the same point of the function.
Secondly, "VAR_LocInt24_9" is a variable but since it has no name inside the game's code, it is given an obtruse name by default. "Loc" specifies that it's a local variable, "Int24" specifies that it's a signed number using 24 bits (it can represent large numbers, unlike "Int8" that can represent only numbers from -128 to 127; that's binary computation stuff but it's not mandatory to understand it though it makes things easier).
You should totally use "File -> Open Mod -> LocalVariableSettings.hws" as it will give names to these variables according to their usage inside the AI scripts (the work is not done yet with the Field scripts).

Finally, I suggest to see first another AI script to understand how things are done. Necron's AI is not the simplest by a large margin (I mean, Necron's AI is simple but not the AI of his dummies who actually do most of the job).
I recommend looking at the AI script of Tantarian: you should be able to grab how things work and it also uses a feature shared with Necron, the "Stand Animation" alternative.

And don't hesitate to look around; there's a list of function codes available and ~60% of the screen is dedicated to give more information than the raw script text (in particular, the "257" that you spotted should be read as a "Status List A" value and means "Petrify | Death", Petrify or Death).