[PSX/PC] General editor - Hades Workshop (0.50b)

  • Thread starter Thread starter Tirlititi
  • Start date Start date
Status
Not open for further replies.
Hello Tirlititi,
I need your help. I use the Steam version and Albeori's Memoria. HadesWorkshopMod works correctly, but during ATE Cleyra [Meeting with the King and the High Priest] the text "debug" appears instead of dialogs. The same problem is observed during the balloon mini-game.
 
Hum... By default, these dialogs are not translated in all the languages. The balloon mini-game was translated in french but not in english for example and the ATE in Cleyra was not translated in any language if I recall correctly. In these situations of a missing translation (but with good remnants of the deleted scene in the script), the lines are often replaced by "debug" as a placeholder or empty text. In other situations, the line was completly removed, resulting in a shift in the text IDs depending on the language (that is why there is not always the same number of texts depending on the language).

So you don't have these lines properly translated, either because you unlocked those scenes yourself in the scripts (in which case, congrats!) or because you imported only a part of a mod unlocking them (typically you unticked the "Texts" box when loading the .hws) or because the script-related modifications are properly installed but somehow the text-related modifications are not (the scripts are stored in a sub-folder of "StreamingAssets" while the texts are stored in a subfolder of "FF9_Data").
 
why this message appear when opening ff9 psx image?
Untitled.png
 
HW is quite sensible to mods, even those it generates itself. Other than that, there should be no problem. It used to scan correctly the japanese, US, UK, french, italian, german and spanish PSX images; I don't have copies of them anymore to thoroughly check but it still scans correctly at least the US version.

When it scans a game successfully, it generates a "Final Fantasy IX (Disc 1).hwf" file next to your PSX image that contains the results of the scan so you don't need to do that anymore next time.

So I guess you are trying to open a modded version of a PSX image. If you know which mod it is and you can remove it (eg. it's a .ppf with an "undo" feature), do that then open it with HW. In many cases, HW will then generate a .hwf that you can use even after re-applying the mod (close HW, re-apply the mod but keep the .hwf next to the game and with the same name, then re-open the PSX image with HW).
If you don't know what mod your game has, you'll have to get another version of the PSX image first, one that is not modded or only very slightly modded. If you're using the US version, I can share .hwf files as well; hopefully they'll work.
 
HW is quite sensible to mods, even those it generates itself. Other than that, there should be no problem. It used to scan correctly the japanese, US, UK, french, italian, german and spanish PSX images; I don't have copies of them anymore to thoroughly check but it still scans correctly at least the US version.

When it scans a game successfully, it generates a "Final Fantasy IX (Disc 1).hwf" file next to your PSX image that contains the results of the scan so you don't need to do that anymore next time.

So I guess you are trying to open a modded version of a PSX image. If you know which mod it is and you can remove it (eg. it's a .ppf with an "undo" feature), do that then open it with HW. In many cases, HW will then generate a .hwf that you can use even after re-applying the mod (close HW, re-apply the mod but keep the .hwf next to the game and with the same name, then re-open the PSX image with HW).
If you don't know what mod your game has, you'll have to get another version of the PSX image first, one that is not modded or only very slightly modded. If you're using the US version, I can share .hwf files as well; hopefully they'll work.
I'm using US version this time. maybe share hwf will work ?
 
Last edited:
@Tirlititi hi , does this program have somewhere an option to increase the drop rate of the items that can be stolen or dropped by the monsters and to do the same with the card drop ?




another thing i need to know is why when i modify a group of enemies , the new enemy i am enabling just don't do anything , for example , enemy id 360 , pyton and goblin , there is a group that only have one pyton , i enabled even the goblin , but then  ,the goblin didn't attacked , just like it didn't got atted at all @Trilititi




also it seem that hades workshop corrupted some of the files i modified , infact after i saved the latest modifications , i had to use my back up files because at some point , the game crashed and i couldn't even open hades workshop , but the moment when i used my back up of the modified files , i could immediately open the game again and use hades workshop




i know the reason of those corrupted data , it is for a problem occurred even long ago, basically , if there are too many data to save all at once , it may happen that the program cause the corruption of the modded files , it happened to me while modifying the data of the monsters all at once , and so i tried to save only half of all the mods , and after i saved the changes , i closed and reopened the program , that solved the problem for now , but clearly the program need a fix to handle all those changes saved at once

Consolidated quad post. - Bonez
 
Last edited:
@akirat9: Here they are.

@carl09876: About item/card steals/drops, mostly no. These are hardcoded in the battle code, which is MIPS in the PSX version and CIL/C# in the Steam version. I guess you can try changing the steal % of each item slot on the PSX version in the MIPS panel (with a bit of luck, these "256/64/16/1" pourcentages are written plainly in the code, so you'd just have to change these figures, even though it will change the rates for all the enemies). If you are on the Steam version, then you can change the code of the Steal script for this kind of result (check out the documentations on how to use Memoria). It is actually not a bad idea to add fields to change these % chances; I'll see what I can do for the next version of Memoria.

When you add/remove an enemy to a group, make sure to change the script accordingly (Edit Script -> function Main_Init -> make sure that the "InitObject" lines match with the changes you made).

The corruption of .hws files happen when you try to modify the script of the field "Opening-for FMV" or when you change something in the panels "Environment -> World Maps -> Place Names" and "Environment -> World Maps -> Battle Spots". I am currently working on an update of HW that will fix that bug amongst other things.
 
@akirat9: Here they are.

@carl09876: About item/card steals/drops, mostly no. These are hardcoded in the battle code, which is MIPS in the PSX version and CIL/C# in the Steam version. I guess you can try changing the steal % of each item slot on the PSX version in the MIPS panel (with a bit of luck, these "256/64/16/1" pourcentages are written plainly in the code, so you'd just have to change these figures, even though it will change the rates for all the enemies). If you are on the Steam version, then you can change the code of the Steal script for this kind of result (check out the documentations on how to use Memoria). It is actually not a bad idea to add fields to change these % chances; I'll see what I can do for the next version of Memoria.

When you add/remove an enemy to a group, make sure to change the script accordingly (Edit Script -> function Main_Init -> make sure that the "InitObject" lines match with the changes you made).

The corruption of .hws files happen when you try to modify the script of the field "Opening-for FMV" or when you change something in the panels "Environment -> World Maps -> Place Names" and "Environment -> World Maps -> Battle Spots". I am currently working on an update of HW that will fix that bug amongst other things.
hmm , are you sure that there isn't nothing in the cil code section that allow to change the values of the steal rate ? i prefer to modify the files rather than change something in the executable ,also you said that memoria and hades workshop aren't compatible , so if you use one , then the game won't respond properly to the changes in the other program , as for the corruption , i don't think the problem is the mdofication in the battle spot , because i managed to change some battle spots , for example , i placed hades and quera in the desert , and i placed dantarian and ozma in the little island were you usually only find the yan , but it also mean that the problem occur only some times , possible ?




@Trilititi can you be more specific about this: "Edit Script -> function Main_Init -> make sure that the "InitObject" lines match with the changes you made" what should i do ? i am checking that section but i don't understand what i should change , because i am looking now at the scripts , for a group that i didn't modified and a group were i enabled some more enemies , they are identical , i am talking about the main init




ok , the game crashed because i added to group 1 for group id 360 the goblin , making a group of two monsters , then i parsed , and still no warnings or errors , the modification to the main init consisted in copy and paste the line for the goblin from a group were it already existed , so what i am doing wrong ?




another thing that happened is that when i placed a group of monsters that come from the ice cavern (is 029 , kannibal and gelatine) , in the  battle spot of the mist continent , the battle trigger properly , but the music don't , so where is the data of that group there is the option to trigger the music ?




ok , so it seem that the game really crashed for changing the battle spots , to be more precise  , for the fact of have places the group 029 (kannibal and gelatine) in the battle spot of the mist continent , the very first that you visit after the evil forest , the one were you find the group of enemies 360 (pyton and goblin) , so yeah , the problem is really what you said , a bug in the program that somehow corrupt the files for the very fact of have switched certain battle spots , still ti is very strange , because as i said , i could place hades and queera in the desert without any kind of problems , so why some changes works and some other changes doesn't ?




i discovered what was causing the crash: if you change the group of enemies in the battle spot without change the background image then the game crash , but if you do it by changing the background image first and then you change the battle spot , the game doesn't crash , still it is a bug in the program that need to be fixed of course , along with the music that doesn't trigger when for example you put a group of enemies that come from the  ice cavern and you put them in the first open field of the mist continent right after the evil forest

Consolidated sextuple post. my dude. I understand you can't yet edit posts, but bruh... 4 and then 6? So figure out everything you want to say before you post and say it at once please.  - Bonez

Posting Etiquette Rule 1: Double posting is generally not allowed. If your last post was less than 24-48 hours ago, edit your post. Some leeway will be given for new users who do not have access to the edit function yet, but please don't abuse this.
 
Last edited:
@Trilititi helooo ??? fucking answer you dick , this bullshit about ignore people's messages must end once and for all
 
@Trilititi helooo ??? fucking answer you dick , this bullshit about ignore people's messages must end once and for all
 ::) Couldn't wait 5 whole days for a reply... @Tirlititi don't worry about answering him. He obviously has issues. He's already been banned before for this exact reason. He subverted the ban but is gone again.

Normally I would have deleted his last post and just banned him quietly, but considering he wrote you a novel, I didn't want you to put any work or thought into any replies to him without being aware.
 
Last edited:
I am obviously not going to answer his new questions.

@carl09876: I don't know what is your age or your situation, so I'm not going to lecture you on how to behave, on the internet or elsewhere. I'll only say that, without even considering the insult, I have been thinking that you don't pay attention to what people write to you and mostly ignore them. It is very dishonest of you to accuse someone else of doing that.
 
Hello,
working with field scripts right now. I want to make a window on the bottom of the screen, which shows a token string of a random field that the field exit will lead to.
Now the textwindow should disappear when the player leaves the Region on the walkmesh, but that is kinda hard to handle since there is no boolean "isinregion" or sth like that.
this is my approach so far:
region range loop opening textbox if globool1 false, set true then
Code: [Select]
Code:
Function Region16_Range    if ( VAR_GlobBool_1 == 0 ) {        SetTextVariable( 0, 1 )        WindowAsync( 0, 4, 9 )        set VAR_GlobBool_1 = 1    }    return
loop code for globool1 waiting ticks until its set false
Code: [Select]
Code:
Function Code1_Loop    if ( VAR_GlobBool_1 == 1 ) {        set VAR_GlobUInt8_1++    }    if ( VAR_GlobUInt8_1 == 59 ) {        set VAR_GlobBool_1 = 0        set VAR_GlobUInt8_1 = 0    }    Wait( 1 )    loop
Code: [Select]
Code:
[STRT=160,1][TAIL=LOC][IMME]press x to go to[WDTH=0,160,6,0,-1][TEXT=0,0][TIME=60]
if anyone know if there is a better way, im glad to read.

less important Question1: im declaring global and local variables, which i dont see written in the edited field script. like globool_1 in this case. Might it be used in the backengine?
less important Question2: came up bcs i saw, especially in the worldmap scripts, stuff going on not happening in the scripts, like the alexandria worldmap model dependency on the scenariocounter, which is not articulated in the script.

less important Question3: Is there a way to edit 300:IceCavern Entrance or Daguerro? they seem independent
less important Question4: Is there a way to edit "field" 70 to have the "new game" button open an other field than 50:Primavista, as of now when i edit it i cant save the mod in .hws
 
Last edited:
also here is a rather lazy written code for a world moogle dialog option that will get you around town and change scenario counter. applies to WorldMap:Hilda Garde 3. just take care you hit the spot and not get lost in the void ;D
Code: [Select]
Code:
Function World_Moogle_27    RunWorldCode( 35, 1 )    set VAR_LocUInt8_20 = GetData_199    set VAR_LocUInt8_19 = GetRandom    set VAR_LocUInt8_0 = ( 192 - ( VAR_LocUInt8_20 + VAR_LocUInt8_19 ) )    TurnInstant( Op60(ObjectUID_250) )    set VAR_LocUInt8_21 = 1    set VAR_LocUInt8_22 = 0    while ( VAR_LocUInt8_22 < 10 ) {        set VAR_LocInt24_1 = ( ( Cos(VAR_LocUInt8_0) * 2 ) + ( ( ( Cos(VAR_LocUInt8_0) * 4 ) - ( Cos(VAR_LocUInt8_0) * 2 ) ) / VAR_LocUInt8_21 ) )        set VAR_LocInt24_4 = ( ( Sin(VAR_LocUInt8_0) * 2 ) + ( ( ( Sin(VAR_LocUInt8_0) * 4 ) - ( Sin(VAR_LocUInt8_0) * 2 ) ) / VAR_LocUInt8_21 ) )        MoveInstantXZY( GetEntryPosX(250) + VAR_LocInt24_1, GetEntryPosZ(255), GetEntryPosY(250) + VAR_LocInt24_4 )        set VAR_LocUInt8_21 = ( VAR_LocUInt8_21 + 1 )        if ( VAR_LocUInt8_22 == 0 ) {            MoveInstantXZY( GetEntryPosX(250) + VAR_LocInt24_1, 2000, GetEntryPosY(250) + VAR_LocInt24_4 )        } else {            SetObjectFlags( 7 )        }        Wait( 1 )        set VAR_LocUInt8_22++    }    set VAR_LocInt24_1 = ( Cos(VAR_LocUInt8_0) * 2 )    set VAR_LocInt24_4 = ( Sin(VAR_LocUInt8_0) * 2 )    MoveInstantXZY( GetEntryPosX(250) + VAR_LocInt24_1, GetEntryPosZ(255), GetEntryPosY(250) + VAR_LocInt24_4 )    SetObjectFlags( 7 )    set VAR_LocInt24_7 = ( Cos(VAR_LocUInt8_0) / 3 )    set VAR_LocInt24_10 = ( Sin(VAR_LocUInt8_0) / 3 )    RunScriptAsync( 4, 4, 34 )    InitWalk(  )    Walk( GetEntryPosX(250) + VAR_LocInt24_7, GetEntryPosY(250) + VAR_LocInt24_10 )    SetWalkSpeed( 60 )    RunScriptAsync( 4, 4, 35 )    TurnInstant( GetEntryAngle(7) - 64 )    RunAnimation( 6151 )    set VAR_LocInt24_13 = ( Cos(VAR_LocUInt8_0) / 8 )    set VAR_LocInt24_16 = ( Sin(VAR_LocUInt8_0) / 8 )    InitWalk(  )    Walk( GetEntryPosX(250) + VAR_LocInt24_13, GetEntryPosY(250) + VAR_LocInt24_16 )    set VAR_LocInt8_25 = 0    while ( VAR_LocInt8_25 >= 0 ) {        RunWorldCode( 16, 6 )        RunWorldCode( 17, 126 )        RunWorldCode( 20, 0 )        WindowAsync( 5, 4, 42 )        do {            Wait( 1 )        } while ( !IsButton(196608L) )        CloseWindow( 5 )        if ( ( GetDialogChoice == 3 ) && IsButton(131072L) ) {            RunWorldCode( 16, 39 )            RunWorldCode( 17, 126 )            RunWorldCode( 20, 0 )        }        switch 4 ( GetDialogChoice ) from 0 {        case +0:            set VAR_LocUInt8_24 = 0            RunWorldCode( 16, 39 )            RunWorldCode( 17, 126 )            RunWorldCode( 20, 0 )            WindowAsync( 5, 4, 43 )            do {                Wait( 1 )            } while ( !IsButton(196608L) )            CloseWindow( 5 )            if ( ( GetDialogChoice == 1 ) && IsButton(131072L) ) {                RunWorldCode( 16, 39 )                RunWorldCode( 17, 126 )                RunWorldCode( 20, 0 )            }            switch 2 ( GetDialogChoice ) from 0 {            case +0:                RunWorldCode( 16, 5 )                RunWorldCode( 17, 126 )                RunWorldCode( 20, 0 )                WindowSync( 5, 4, 45 )                while ( GetData_200 ) {                    Wait( 1 )                }                RunWorldCode( 39, 0 )                Menu( 4, 0 )                RunWorldCode( 40, 0 )                set VAR_LocUInt8_23 = 2                break            case +1:                set VAR_LocUInt8_23 = 1                break            }            break        case +1:            set VAR_LocUInt8_24 = 0            RunWorldCode( 16, 39 )            RunWorldCode( 17, 126 )            RunWorldCode( 20, 0 )            set VAR_GlobUInt8_42 = GetItemCount(253)            if ( !VAR_GlobUInt8_42 ) {                WindowSync( 5, 4, 46 )            } else {                SetTextVariable( 1, VAR_GlobUInt8_42 )                WindowAsync( 5, 4, 44 )                do {                    Wait( 1 )                } while ( !IsButton(196608L) )                CloseWindow( 5 )                if ( ( GetDialogChoice == 1 ) && IsButton(131072L) ) {                    RunWorldCode( 16, 39 )                    RunWorldCode( 17, 126 )                    RunWorldCode( 20, 0 )                }                switch 2 ( GetDialogChoice ) from 0 {                case +0:                    RemoveItem( 253, 1 )                    RunScriptAsync( 5, 4, 37 )                    FadeFilter( 2, 24, 0, 255, 255, 255 )                    Wait( 25 )                    RunScriptAsync( 5, 7, 38 )                    RunScriptAsync( 5, 250, 38 )                    RunScriptSync( 5, 10, 40 )                    FadeFilter( 3, 16, 0, 0, 0, 0 )                    Wait( 40 )                    FadeFilter( 2, 24, 0, 255, 255, 255 )                    Wait( 25 )                    RunScriptAsync( 5, 10, 41 )                    RunScriptAsync( 5, 7, 39 )                    RunScriptSync( 5, 250, 39 )                    FadeFilter( 3, 16, 0, 0, 0, 0 )                    Wait( 20 )                    set VAR_LocUInt8_23 = 2                    break                case +1:                    set VAR_LocUInt8_23 = 1                    break                }            }            break        case +2:            WindowAsync( 5, 4, 90 )            do {                Wait( 1 )            } while ( !IsButton(196608L) )            CloseWindow( 5 )            if ( ( GetDialogChoice == 1 ) && IsButton(131072L) ) {                RunWorldCode( 16, 39 )                RunWorldCode( 17, 126 )                RunWorldCode( 20, 0 )            }//Dialog Option starts here            switch 2 ( GetDialogChoice ) from 0 {            case +0:                set VAR_LocInt24_2 = 0                set VAR_LocInt24_5 = 1                set VAR_LocInt24_6 = 0                SetTextVariable( 5, VAR_LocInt24_2 )                SetTextVariable( 6, VAR_LocInt24_5 )                SetTextVariable( 4, General_ScenarioCounter )                WindowAsync( 5, 4, 10 )                do {                    if ( IsButton(16) ) {                        if ( VAR_LocInt24_5 == 1000 ) {                            set VAR_LocInt24_5 = 1000                        }                        if ( VAR_LocInt24_5 == 100 ) {                            set VAR_LocInt24_5 = 1000                        }                        if ( VAR_LocInt24_5 == 10 ) {                            set VAR_LocInt24_5 = 100                        }                        if ( VAR_LocInt24_5 == 1 ) {                            set VAR_LocInt24_5 = 10                        }                        SetTextVariable( 6, VAR_LocInt24_5 )                    }                    if ( IsButton(64) ) {                        if ( VAR_LocInt24_5 == 1 ) {                            set VAR_LocInt24_5 = 1                        }                        if ( VAR_LocInt24_5 == 10 ) {                            set VAR_LocInt24_5 = 1                        }                        if ( VAR_LocInt24_5 == 100 ) {                            set VAR_LocInt24_5 = 10                        }                        if ( VAR_LocInt24_5 == 1000 ) {                            set VAR_LocInt24_5 = 100                        }                        SetTextVariable( 6, VAR_LocInt24_5 )                    }                    if ( IsButton(128) ) {                        set VAR_LocInt24_2 = ( VAR_LocInt24_2 - VAR_LocInt24_5 )                        SetTextVariable( 5, VAR_LocInt24_2 )                    }                    if ( IsButton(32) ) {                        set VAR_LocInt24_2 = ( VAR_LocInt24_2 + VAR_LocInt24_5 )                        SetTextVariable( 5, VAR_LocInt24_2 )                    }                    if ( IsButton(8) ) {                        set General_ScenarioCounter = VAR_LocInt24_2                    }                    Wait( 1 )                } while ( !IsButton(196608L) )                break            case +1:                set VAR_LocInt24_2 = 0                set VAR_LocInt24_5 = 1                set VAR_LocInt24_6 = 0                SetTextVariable( 5, VAR_LocInt24_2 )                SetTextVariable( 6, VAR_LocInt24_5 )                WindowAsync( 5, 4, 9 )                do {                    if ( IsButton(16) ) {                        if ( VAR_LocInt24_5 == 1000 ) {                            set VAR_LocInt24_5 = 1000                        }                        if ( VAR_LocInt24_5 == 100 ) {                            set VAR_LocInt24_5 = 1000                        }                        if ( VAR_LocInt24_5 == 10 ) {                            set VAR_LocInt24_5 = 100                        }                        if ( VAR_LocInt24_5 == 1 ) {                            set VAR_LocInt24_5 = 10                        }                        SetTextVariable( 6, VAR_LocInt24_5 )                    }                    if ( IsButton(64) ) {                        if ( VAR_LocInt24_5 == 1 ) {                            set VAR_LocInt24_5 = 1                        }                        if ( VAR_LocInt24_5 == 10 ) {                            set VAR_LocInt24_5 = 1                        }                        if ( VAR_LocInt24_5 == 100 ) {                            set VAR_LocInt24_5 = 10                        }                        if ( VAR_LocInt24_5 == 1000 ) {                            set VAR_LocInt24_5 = 100                        }                        SetTextVariable( 6, VAR_LocInt24_5 )                    }                    if ( IsButton(128) ) {                        set VAR_LocInt24_2 = ( VAR_LocInt24_2 - VAR_LocInt24_5 )                        SetTextVariable( 5, VAR_LocInt24_2 )                    }                    if ( IsButton(32) ) {                        set VAR_LocInt24_2 = ( VAR_LocInt24_2 + VAR_LocInt24_5 )                        SetTextVariable( 5, VAR_LocInt24_2 )                    }                    if ( IsButton(8) ) {                        Field( VAR_LocInt24_2 )                    }                    Wait( 1 )                } while ( !IsButton(196608L) )                break            }            break        case +3:            switch 2 ( VAR_LocUInt8_23 ) from 1 {            case +0:                WindowAsync( 5, 4, 47 )                break            case +1:                WindowAsync( 5, 4, 48 )                break            default:                if ( VAR_LocUInt8_24 < 8 ) {                    WindowAsync( 5, 4, 50 )                } else {                    if ( VAR_LocUInt8_24 == 8 ) {                        WindowAsync( 5, 4, 51 )                    } else {                        if ( VAR_LocUInt8_24 == 12 ) {                            WindowAsync( 5, 4, 52 )                        } else {                            if ( VAR_LocUInt8_24 >= 16 ) {                                WindowAsync( 5, 4, 49 )                            } else {                                WindowAsync( 5, 4, 50 )                            }                        }                    }                }                break            }            if ( ( !VAR_LocUInt8_23 ) && ( VAR_LocUInt8_24 < 32 ) ) {                set VAR_LocUInt8_24 = ( VAR_LocUInt8_24 + 1 )            }            RunScriptSync( 5, 7, 42 )            set VAR_LocInt8_25 = 65535            set VAR_LocUInt8_23 = 0            break        }        Wait( 1 )    }    return
Code: [Select]
Code:
[STRT=167,5][TAIL=DEFT][WDTH=0,61,64,0,64,1,-1][IMME][D06050][HSHD] [C8B040][HSHD]Set Field()[68C0D8][HSHD]New=[NUMB=5], Increment=[NUMB=6][DBTN=START]: Overwrite[TIME=-1]
Code: [Select]
Code:
[STRT=167,5][TAIL=DEFT][WDTH=0,61,64,0,64,1,-1][IMME][D06050][HSHD] [C8B040][HSHD]Set Scenario Counter()[68C0D8][HSHD]Old=[NUMB=4], New=[NUMB=5], Increment=[NUMB=6][DBTN=START]: Overwrite[TIME=-1]
Code: [Select]
Code:
[STRT=136,3][TAIL=UPC][PCHC=2,1][IMME]Debug?[CHOO][MOVE=18,0]Scenario Counter[MOVE=18,0]Field[TIME=-1]
 
Last edited:
Hi Seramera,
Congrats on doing all that already. That's really neat.

Many script variables are indeed used by the back engine. The scenario counter (General_ScenarioCounter) is used indeed a lot (for city destroyed and whether Iifa roots expand to post-Terra spots on the World Map, but also whether Garnet has long or short hair and surely I'm missing some). The friendly flags (FriendlyMonster_Progress and the first bit of Ragtime_QuizzSuccess) disable the possibility to encounter those friendly monsters. The pepper spot flags (Chocobo_ParadiseFound and Chocobo_MognetFound) change the appearance of the entrance on the world map etc...
The "General" variables are usually the ones used by the engine. It sometimes happens that the engine fetch local or global variables for "hotfixes", especially on the Steam version of the game. At the end of the day, that's very rare though so you'll most likely never get to one of these instances. Here's an example of such hotfix that can be found in the engine's source code: it increases the score of the Blank sword fight minigame by checking that the field map is 64 (A. Castle/Public Seats), that the running script is a function of the object 4 (Code4_Init or Code4_Loop) and even the exact binary position of the code executed (after the normal score is computed but before the "SetTextVariable" line). So you can see in that example that hotfixes are very specific: you'll almost surely won't have issues because of them. Also, these hotfixes aside, script variables (local or global) are never used by the engine so you can't mess with it by using "VAR_GlobBool_1" especially if it weren't used in the field's script already.

I don't have a complete list of these hotfixes or how the engine uses general-type variables for purposes like the ones you spotted.
Unfortunatly, these uses are spread in the code and hard to interpret.

I don't understand your 3rd question. Ice Cavern's Entrance and Daguerro's field scripts should be editable like any other. I'll check if there is a problem with these but there shouldn't.

I am currently working on an update of the tool that will fix the issues with the field 70: Opening for FMV (among other things).

I don't know of a better way to check if the player character is in the region. I think that your solution is actually the best suited and fits with the spirit of programming tricks they usually used.

(By the way, Global-type variables can be used up to index 79. If you use "VAR_GlobUInt8_80", it will get out of the array range and probably at least throw an exception on Steam, effectively at least terminating the script function, or have an unexpected behaviour on the PSX version. I'm not sure if that limit is documented correctly in the tool.)
 
Hello Tirlititi,
thank you for the elaborate answer.
Having built the Randomizer and other stuff, I indeed found out some Variables are used in the back engine.
It got me burst out laughing when i suddenly swapped control with the npc I interacted with. Bugs can be funny creatures. :-D

So the method (that works for me now) is to look for Variables that are already used on the field, but dont interfere with the added use, instead of searching for unused variables.

Here is a little Speak Script that i use to test Battles.

Code: [Select]
Code:
Function YoungWomanB_SpeakBTN    ifnot ( IsMovementEnabled ) {        return    }    set VAR_GlobBool_158 = 0    if ( VAR_GlobBool_159 == 1 ) {        DisableMove(  )        if ( VAR_GlobBool_144 == 0 ) {            DisableMenu(  )        } else {            Wait( 1 )        }    }    SetTriangleFlagMask( 127 )    WaitTurn(  )    set VAR_GlobUInt8_16 = GetEntryAngle(255)    TurnTowardObject( 250, 32 )    WaitTurn(  )    WindowSync( 5, 2, 2 )    switch 1 ( GetDialogChoice ) from 0 {    case +0:        set VAR_GlobInt16_6 = 0        set VAR_GlobInt16_4 = 1        set VAR_GlobBool_21 = 0        SetTextVariable( 4, VAR_GlobBool_21 )        SetTextVariable( 5, VAR_GlobInt16_6 )        SetTextVariable( 6, VAR_GlobInt16_4 )        WindowAsync( 5, 4, 3 )        do {            if ( IsButton(16) ) {                if ( VAR_GlobInt16_4 == 1000 ) {                    set VAR_GlobInt16_4 = 1000                }                if ( VAR_GlobInt16_4 == 100 ) {                    set VAR_GlobInt16_4 = 1000                }                if ( VAR_GlobInt16_4 == 10 ) {                    set VAR_GlobInt16_4 = 100                }                if ( VAR_GlobInt16_4 == 1 ) {                    set VAR_GlobInt16_4 = 10                }                SetTextVariable( 6, VAR_GlobInt16_4 )            }            if ( IsButton(64) ) {                if ( VAR_GlobInt16_4 == 1 ) {                    set VAR_GlobInt16_4 = 1                }                if ( VAR_GlobInt16_4 == 10 ) {                    set VAR_GlobInt16_4 = 1                }                if ( VAR_GlobInt16_4 == 100 ) {                    set VAR_GlobInt16_4 = 10                }                if ( VAR_GlobInt16_4 == 1000 ) {                    set VAR_GlobInt16_4 = 100                }                SetTextVariable( 6, VAR_GlobInt16_4 )            }            if ( IsButton(128) ) {                set VAR_GlobInt16_6 = ( VAR_GlobInt16_6 - VAR_GlobInt16_4 )                SetTextVariable( 5, VAR_GlobInt16_6 )            }            if ( IsButton(32) ) {                set VAR_GlobInt16_6 = ( VAR_GlobInt16_6 + VAR_GlobInt16_4 )                SetTextVariable( 5, VAR_GlobInt16_6 )            }            if ( IsButton(8) ) {                if ( VAR_GlobBool_21 == 0 ) {                    set VAR_GlobBool_21 = 1                    SetTextVariable( 4, VAR_GlobBool_21 )                } else {                    set VAR_GlobBool_20 = 0                    SetTextVariable( 4, VAR_GlobBool_21 )                }            }            Wait( 1 )        } while ( ( !IsButton(196608L) )  )         break    default:        break    }    Wait( 5 )    if ( VAR_GlobBool_21 == 1 ) {        Battle( 0, VAR_GlobInt16_6 )    }    CloseAllWindows(  )    0xA9( 250 )    set VAR_GlobBool_158 = 1    if ( VAR_GlobBool_159 == 1 ) {        if ( VAR_GlobBool_156 == 0 ) {            EnableMove(  )            SetTriangleFlagMask( 255 )            if ( VAR_GlobBool_144 == 0 ) {                EnableMenu(  )            }        }    }    TimedTurn( VAR_GlobUInt8_16, 16 )    WaitTurn(  )    return
Code: [Select]
Code:
[STRT=100,3][IMME]What u wanna do?[CHOO=2,1] Go BattleNothing
Code: [Select]
Code:
[STRT=200,4] [IMME]Increment: [NUMB=6] Destination: [NUMB=5]startbattlebool: [NUMB=4] (0=no, 1=yes)[JCBT=START] change startbattlebool[JCBT=UP] [JCBT=DOWN]Increment[JCBT=LEFT] [JCBT=RIGHT]Destination
I'll report when I'm stuck elsewhere or have finished sth playable.
 
Last edited:
Hello to the whole community, I wanted to thank you Tirlititi for this incredible tool. I am creating a difficulty mod thanks to your tool and I am learning how to implement npcs. With the latter I have a big problem, when I try to add an npc. I don't know how to add the npc function, for example, if there is Man_A in a scenario and I want to introduce a second NPC called Man_B, I can't change the name of the functions. When you have time can you tell me how I can do it? Thanks in advance. (the english not is my native languaje sorry >.<)
 
Hello stir472.

The name of the function is automatically using the entry's model. You can't change it indeed: it's automatically set when it finds a line "SetModel" in the entry's functions.

In order to add a NPC, first get off the "Edit Script" window and start by adding an entry in the "Edit Entries" window. Set that entry's type to "Object" (I think it is the type number "2" if I recall correctly), remember the newly added entry's ID and confirm.
Then only, go back to the "Edit Script" window and right-click on the function list to add a function. Select the newly added entry and create a function of type "0" (the "_Init" function). In there, add the code to initialize your NPC (you can copy/paste the content of another "_Init" function of an object-type entry and change the positions and the "SetModel" value). Also add a line "InitObject" in the "Main_Init" function to actually initialize it when entering the screen.
Then add whatever code you want for your NPC (most likely, add a function of type "talk button").
 
Update to v0.43.
That's a big update, with several new features, half of which I still don't know why I did them and who will ever really use them...

- Added a Damage Calculator: that's something I wanted for a long time. It doesn't take into account the enemy's elemental boost bug in the PSX version so it can be inaccurate for a couple of enemy attacks depending on the language you play (in PSX, enemies can benefit from elemental boosts but that depends on the language, eg. Sealion has a Water boost but only in the PSX japanese version).

- Added a Walkmesh editor, a Walkmesh OBJ exporter and a Walkmesh OBJ importer. Now walkmeshes can be (almost) fully edited. The editor of the tool is not very convenient or practical, but it allows to change path flags that cannot be passed to an OBJ model. The addition of this editor makes the script editor a bit more convenient regarding the functions "EnablePathTriangle" and "EnablePath" as you can now double-click on the 3D model of the walkmesh to select the triangle/walkpath you want to enable/disable.
Although the walkmesh editor is accessible for both the Steam and the PSX version, it is very buggy on the PSX version and sometimes place newly-added triangles at random positions in-game.

- Added "command" version of the tool. It is a fake command-line version because it still uses an interface but it allows HW to be used by external programs by providing it a sequence of commands written into a file. In the ZIP, I added a file, "CommandSample.txt", that shows how to use this feature and should run fine if you have the Steam version of the game installed.

- Added the options "Memoria -> Export as Custom Field/Battle". These take an existing field or battle and simply create Steam assets (same as "Save Steam Mod" with the option "Raw Assets") with the correct paths and filenames so they can be used by Memoria as additional fields/battles without the need to replace existing ones. I tested a adding a custom field and that worked correctly.
In addition to using that option, creating a custom field/battle requires:
-- reference them in another script, adding a "Field" or "Battle" line using that custom field/battle's script ID,
-- create a file "DictionaryPatch.txt" in your mod folder and copy/paste a line that Hades Workshop provides,
-- for fields, you need to edit the files "[ModFolder]/FF9_Data/embeddedasset/text/[LANG]/location/loc_name.mes" and adding an entry for specifying the custom field's name (these files are generated when you have modified another field name and saved Steam mod with "Raw Assets" and they can be edited with a text editor).
I guess that the convenient workflow for making a mod with custom fields/battles is to have 2 HWS files: one without the custom fields/battles but with all other modifications and the scripts referencing to custom IDs, a the other HWS with only custom fields/battles (because you can't add fields/battles in the lists in Hades Workshop, so you can't have the base field/battle and the custom field/battle simultaneously).
The assets generated this way are not removed when generating a Steam mod (except if you picked the same identifiers as existing fields/battles, which is not advised).

- Added a couple of datas that can be changed in field backgrounds: the depths and positions of tiles (individual tiles or tile sets) can now be changed. I think that most (all?) bug fixes provided by the Moguri mod concerning incorrect tile depths (as described in this topic) could be done using that feature instead of editing the scripts (and potentially make mod compatibility more difficult).

- Fixed several bugs and added several improvements. The world map battle spots or place names should now work correctly (both when saving HWS files and generating Steam mods). "Opening-for-FMV" should not cause any problem anymore. Several script functions were given a name and description instead of the "0xXX" default names. Script batch exporting are a bit better commented because entries are correctly named in the Main_Init function (typically the "InitObject" lines). etc.
 
Last edited:
Thank you for your work. Tell me please. Is it possible to overcome the limit of hit points for the mark 65535? In the editor, this is the maximum value...  :-(
 
No, it's not possible to overcome that limit with HW but you can bypass it using a trick (basically healing the enemy to simulate a max health increase; that's what I did for my own mod for Necron).

On the Steam version of the game, using Albeoris's Memoria tool, it is possible to really overcome the max HP limit without any drawback or side effect. It is not very convenient to do it right now but it should be better relatively soon, and when that comes the information will be provided in the wiki (it doesn't explain how to do that yet).
 
Status
Not open for further replies.
Back
Top