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] 2 3 4 5 6 ... 36
1
I guess devs had some kind of "macros", ie. they only wrote a single line for changing the party formation and that line was converted into all these lines, doing the process step by step in a way that adapts to all situations. That's why it heals everyone even if they didn't join the party yet or why there are "if ( 0 )" blocks that just never happen. I never added a feature for having macros there.

The "VAR_GlobInt" are restricted to a field.
"local" variables are restricted to the entry, so "VAR_LocInt8_0" in the function "Main_Init" is a different variable than "VAR_LocInt8_0" in the function "Zidane_Init".
"global" variables are restricted to the field, so "VAR_GlobInt8_0" in the field "Prima Vista/Cargo Room" is not the same as in the field "Prima Vista/Meeting Room".
Only "general" variables are unrestricted (and they are the ones saved in save games). It would require a lot of work to identify all of the general variables already and I don't advance on that part anymore since a long time.
If you understand what a global or local variable does, you can name it inside the "local variable panel" right above the function's script. It's lines like
Code: [Select]
global int8 {variable_name} VAR_GlobInt8_0
Please don't edit your posts to remove the question after it is solved. It helps other people that read the topic.

2
Hello Asmorano.

That's not a counter-attack, just their unique attack (one of them casts Catastrophe, the other casts Jinx). It is not that unusual to have them run out of MP but indeed that's the most unsatisfying way to get through this battle. Blind is meant to be that annoying, although there are tips to mitigate its effect (only use items on yourself or use them on the only character on your left/right) and the accuracy malus is negated by using things like Free Energy or Quadraslash.
Jinx is indeed a very special ability. The "dummy" effect is the only spell visual effect that is in the game's database but never used and it was used for debugging purpose, but I found it fitting for this fight. It's not exactly Trouble that they inflict to you (they don't attack physically) but it's another kind of damage spreading status, indeed.

There are a couple of fights that have gimmicks like that. The intent there is to make the fight much easier by understanding the gimmick, but also to make it possible to win without understanding the gimmick, so it's not blocking.

There's another occasion to fight Zorn & Thorn in which they have similar abilities, much later in the game. Maybe you'll get it better by then.

3
Hello HopefulTarnished
You can use "GetEntryUniqueID(250)". It converts the special UIDs 250-255 to their number counterpart. Let's say if Zidane is the entry 11 (then Garnet is the entry 13), you can do:
Code: [Select]
if ( GetEntryUniqueID(250) == 11 ) {
    // Zidane is the player character
}
if ( GetEntryUniqueID(250) == 13 ) {
    // Garnet is the player character
}
I have not tested it but I think that should be the way to go.

Good luck too!

4
Sorry, there was a couple of hours with a mismatch between the update of Memoria and the update of Alternate Fantasy; they had to be simultaneously updated this time. Now if you update both Memoria and AF with the latest versions (v2024-08-18 for Memoria and v6.6 for AF), it should work fine.

Most of the time, updates of Memoria shouldn't break compatibility with mods, even heavy gameplay mods like AF, but sometimes we cannot avoid breaking the compatibility (this time, we didn't break compatibility with Trance Seek for example, only AF).

(I answered Yosharian a while ago on Discord but the "Short Range" attacks can still be performed on the back row, that's normal: it's only that they cannot reach far-away enemies like Deathguise and that they deal less damage from the back row, just like the attack command in vanilla)

5
FF9 Tools / Re: Stiltzkin's Bag a FFIX Randomizer Tool
« on: 2024-08-14 10:51:07 »
I think Stilzkin's bag still works. I did a quick test and it seems to be still 100% functional with the latest version of Memoria.

6
Hello RoSoDude.
That's most likely MIPS code indeed. I am not sure that would be feasible by modifying the parts of the MIPS code that are accessible through Hades Workshop but there's a chance it is.

The parts that are accessible and that are indexed correspond to effects of abilities. That code (which was most likely written in C for the PSX version before it got compiled to MIPS) has been ported into C# that can be read there: btl_calc.cs
Having both MIPS and C# there might help you to see how that MIPS is written and maybe identify data banks that would be relevant to change what you want. For example, there are references to BTL_DATA's "cur.hp": the current ATB of each fighter is very close to that field because "cur" is a structure like that:
Code: [Select]
public class POINTS
{
public ushort hp;
public short mp;
public short at;
public sbyte at_coef;
public byte capa;
}
with "at" being the ATB and "at_coef" being its speed (that depends both on Haste/Slow but also on the battle speed configuration).

Unfortunatly, I don't know about the parts that identify whether an animation (SFX) is running or not in MIPS. I guess using a debugger there (to scan the RAM during runtime) would be the best way. You can see the list of different SFX identifiers here; that should help you when looking for that kind of info.

There are functions that handles ATB progression globally, not just each individual "at_coef", but the C# port of it is surely not as close to the original MIPS code as other parts. The following C# method determines if ATB should be advancing (and would ideally be the place you'd add the condition regarding SFX) but is part of the HUD class, which were much more re-factored than other parts of the code:
Code: [Select]
public bool FF9BMenu_IsEnableAtb()
{
if (!this.commandEnable)
return false;
if (FF9StateSystem.Settings.cfg.atb != 1uL)
return true;
if (this.hidingHud)
return this.currentPlayerId == -1 || this.currentButtonGroup == BattleHUD.CommandGroupButton || this.currentButtonGroup == string.Empty;
return this.currentPlayerId == -1 || ButtonGroupState.ActiveGroup == BattleHUD.CommandGroupButton || ButtonGroupState.ActiveGroup == string.Empty;
}

Good luck.

7
You removed the following lines from the base script:
Code: [Select]
    SetTextVariable( 0, 300 ) // Replace "[ITEM=0]" by "Red Stone"
    SetTextVariable( 1, 301 ) // Replace "[ITEM=1]" by "Blue Stone"
    SetTextVariable( 2, 302 ) // Replace "[ITEM=2]" by "Yellow Stone"
    SetTextVariable( 3, 303 ) // Replace "[ITEM=3]" by "Green Stone"

8
Hello g_west,

After checking the code, there's indeed an extra subtlety in the way that side-quest is coded. The possibility to deposit the stones depends on a treasure variable instead of whether you have the stones themselves (the key items) in your inventory. Here are the scripts explained:

Code: [Select]
// The function to pick the Blue Stone, in Mountain Path/Trail (1551)
Function Zidane_15
    // The following lines are the movement of Zidane crouching in front of the statue
    TimedTurn( Angle(2679, 3842), 32 )
    WaitTurn(  )
    SetStandAnimation( 2605 )
    RunAnimation( 2606 )
    WaitAnimation(  )

    // This replaces "[ITEM=0]" in the dialog right below by the name of the item 301 (Blue Stone)
    SetTextVariable( 0, 301 )
    // Display the dialog with two choices: "[ITEM=0] is set on the stone. Take it out Leave it alone"
    WindowSync( 0, 0, 143 )

    // The check "!GetDialogChoice" is synonymous to "GetDialogChoice == 0", eg. the player chose "Take it out"
    if ( !GetDialogChoice ) {
        Wait( 10 )
        // Play the pickup sound
        RunSoundCode3( 53248, 1340, 0, -128, 125 )
        Wait( 10 )
    }

    // The following lines are the movement of Zidane standing up
    SetStandAnimation( 200 )
    RunAnimation( 2590 )

    if ( !GetDialogChoice ) {
        // So, this whole block executes only if the player chose "Take it out"
        RunSoundCode3( 53248, 108, 0, -128, 125 )

        // Give the key item "Blue Stone" to the player
        AddItem( 301, 1 )
        // Same as above: replaces "[ITEM=0]" by "Blue Stone" in the upcoming dialog
        SetTextVariable( 0, 301 )

        // Blocks with "if ( 1 )" always execute; it's a technical leftover to have a "if" block there and it could just have been "WindowSync( 7, 0, 58 )"
        if ( 1 ) {
            // Display the dialog "Received [ITEM=0]!"
            WindowSync( 7, 0, 58 )
        } else {
            // That part is thus never executed and could be completly removed, it wouldn't make any difference
            WindowSync( 7, 0, 59 )
        }

        // THERE, this is the added subtlety: this variable is a "treasure picked" memo.
        // It is enabled once you picked the treasure and usually it
        // (1) makes sure that you cannot pick the same treasure multiple times
        // (2) counts toward the treasure rank score
        // But there, it will also be used to allow the player to place the Blue Stone in the other statue
        set VARL_GenBool_2865 = 1
    }
    WaitAnimation(  )
    return

Code: [Select]
// The function to place the different stones, in Mountain Path/Roots (1554)
// I'll write much less details there
Function Zidane_16
    SetWalkTurnSpeed( 64 )
    SetPathing( 0 )
    SetWalkSpeed( 30 )
    InitWalk(  )
    WalkXZY( 1445, 174, 1243 )
    TimedTurn( 160, 32 )
    WaitTurn(  )
    SetStandAnimation( 2605 )
    RunAnimation( 2607 )
    WaitAnimation(  )
    set VAR_LocUInt8_0 = 0
    SetTextVariable( 0, 300 ) // Replace "[ITEM=0]" by "Red Stone"
    SetTextVariable( 1, 301 ) // Replace "[ITEM=1]" by "Blue Stone"
    SetTextVariable( 2, 302 ) // Replace "[ITEM=2]" by "Yellow Stone"
    SetTextVariable( 3, 303 ) // Replace "[ITEM=3]" by "Green Stone"


    // Here's the tricky part: the variable "VARL_GenUInt8_358" is tied to "VARL_GenBool_2865"
    // "VARL_GenBool_2865" is actually the second bit in "VARL_GenUInt8_358"

    // So "VARL_GenUInt8_358" is organised in 8 bits:
    // The first 4 bytes are "have you picked up the stones"
    // The last 4 bytes are "have you placed the stones"

    // "VARL_GenUInt8_358 != 255" is "as long as there's a bit that is not set"
    // ie. "as long as the side-quest isn't over"

    // "( ( VARL_GenUInt8_358 & ( ~( VARL_GenUInt8_358 >> 4 ) ) ) & 15 )" is a complex formula that enables the different choices
    // It enables a choice if the related item (1) has been picked and (2) has not been placed yet

    while ( ( !VAR_LocUInt8_0 ) && ( VARL_GenUInt8_358 != 255 ) ) {
        EnableDialogChoices( ( ( VARL_GenUInt8_358 & ( ~( VARL_GenUInt8_358 >> 4 ) ) ) & 15 ) | 16, 0 )

        // "There’s a hole. Put [ITEM=0] in. Put [ITEM=1] in. Put [ITEM=2] in. Put [ITEM=3] in. Leave it alone"
        WindowSync( 0, 0, 144 )

        if ( GetDialogChoice == 4 ) {
            // "Leave it alone" -> Exit the loop
            set VAR_LocUInt8_0 = 1
        } else {
            // Update "VARL_GenUInt8_358" in order to say that the stone has been placed
            set VARL_GenUInt8_358 |= ( 1 << ( GetDialogChoice + 4 ) )
            SetTextVariable( 4, GetDialogChoice + 300 )
            RemoveItem( GetDialogChoice + 300, 1 )
            WindowSync( 0, 0, 145 ) // "Put in [ITEM=4]"
            RunSoundCode3( 53248, 1339, 0, -128, 125 )
        }
    }

    // etc...
    if ( VARL_GenUInt8_358 == 255 ) {
        WindowSync( 0, 128, 146 ) // "Zidane “Hmm?  Something came out from the back...”"
            if ( GetItemCount(229) < 99 ) { // Can carry another Moonstone
                if ( VARL_GenBool_7381 == 0 ) {
                    RunSoundCode3( 53248, 108, 0, -128, 125 )
                    set VARL_GenBool_7381 = 1
                    SetTextVariable( 0, 229 )
                    AddItem( 229, 1 )
                    WindowSync( 7, 0, 58 ) // "Received Moonstone!"
                }
            } else {
                WindowSync( 7, 0, 62 ) // "Cannot carry another Moonstone."
            }
        }
    }
    SetStandAnimation( 200 )
    RunAnimation( 2591 )
    WaitAnimation(  )
    TimedTurn( 32, 32 )
    WaitTurn(  )
    InitWalk(  )
    WalkXZY( 1327, 170, 1228 )
    MoveInstantXZY( 1327, 170, 1228 )
    SetPathing( 1 )
    return

In order to check for the presence of the items in the player's inventory instead of the treasure pickup flag, you can use the following code instead and use "allocate 2" in the local variable panel.
Code: [Select]
    set VAR_LocUInt8_1 = GetItemCount(300)
    set VAR_LocUInt8_1 |= (GetItemCount(301) << 1)
    set VAR_LocUInt8_1 |= (GetItemCount(302) << 2)
    set VAR_LocUInt8_1 |= (GetItemCount(303) << 3)

    // Replace "VARL_GenUInt8_358 != 255" by "(VARL_GenUInt8_358 & 240) != 240"
    while ( ( !VAR_LocUInt8_0 ) && ( (VARL_GenUInt8_358 & 240) != 240 ) ) {
        EnableDialogChoices( ( ( VAR_LocUInt8_1 & ( ~( VARL_GenUInt8_358 >> 4 ) ) ) & 15 ) | 16, 0 )
        // etc..
    }

    // Also for the reward that marks the end of the side-quest
    if ( (VARL_GenUInt8_358 & 240) == 240 ) {
        WindowSync( 0, 128, 146 ) // "Zidane “Hmm?  Something came out from the back...”"
        // etc...
    }

9
FF9 Tools / Re: [PSX] FF9 Blender Importer (0.2)
« on: 2024-05-25 22:22:40 »
Awesome! Good luck with that!

10
Hello charlie_38,

Regarding the non-complete CSV and MES files, that's normal. You must get an up-to-date version of Memoria in order for it to work properly though. So once you've updated Memoria, it should be all good.

Regarding that note in the Help window, it only concerns the PSX Japanese version of the game. If I recall correctly, one of the World Maps used for debugging had a "corrupted" script that would make Hades Workshop crash if it tried to read it. In the Steam version of the game, that's not a problem anymore and you can indeed edit the Japanese World Maps' scripts if you change language setting in HW to Japanese and it will work fine.

11
You should better always save your mod as "Steam Mod" but also as HWS saves ("File -> Save Mod").
You cannot resume the modding of the game after closing Hades Workshop if you don't do that: Hades Workshop should always load the base game when you open it: you can resume a mod you previously started by using "File -> Open Mod" and selecting the HWS file you previously saved.

12
Hi,
Fortunatly, that shouldn't be too hard. You only need to emulate the method "TryCriticalHit" and change the increase formula it uses.
Code: [Select]
// In your "CommonScript.cs"

public static void TryCriticalHitAdjusted(BattleCalculator _v)
{
Int32 quarterWill = _v.Caster.Data.elem.wpr >> 2;
if (quarterWill != 0 && (Comn.random16() % quarterWill) + _v.Caster.Data.critical_rate_deal_bonus + _v.Target.Data.critical_rate_receive_bonus > Comn.random16() % 100)
{
_v.Target.HpDamage = (Int32)(_v.Target.HpDamage / 4f + Math.Min(15000, _v.Target.HpDamage) / 4f + Math.Min(10000, _v.Target.HpDamage) / 2f);
// Do the same for "_v.Target.MpDamage"; apparently you don't use "_v.Context.Attack" in your situation when the critical strike triggers
_v.Target.Flags |= CalcFlag.Critical;
}
}
And then you use "CommonScript.TryCriticalHitAdjusted(_v)" in place of "_v.TryCriticalHit()".
I think the rounding in my formula is correct, but you'd better check how it behaves exactly in practice to be sure about it.

13
I don't understand why there is this issue with a counter-float on themselves, sorry. I don't know where it comes from. I'm afraid that you'll have to investigate that issue yourself. "CounterBetterTarget" only applies to party members' counters so you don't need to take it into account when checking things. I would say you should rather check Yan's IA.

I don't get why they would target themselves because they don't have any spell that would target themselves normally. So even if there is some kind of mess because of 2 counters being queued simultaneously (and there shouldn't: the behaviour now should be that any new counter is dismissed until the 1st counter is performed), I don't see how the target could end up being themselves.

14
Exactly, you need a target loop thread with the option "Chain". You also need to redo a "LoadSFX" operation when you change the target, which is the reason why it applied to all the targets everytime.

Something like:
Code: [Select]
StartThread: TargetLoop ; Chain ; Sync
LoadSFX: SFX=Iai_Strike_1 ; Target=AllTargets ; Reflect=True ; UseCamera=False
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=670 ; UseCollisionRadius=True ; Anim=MP_RUN
Turn: Char=Caster ; BaseAngle=AllTargets ; Time=4
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=400 ; UseCollisionRadius=True ; Anim=MP_RUN_TO_ATTACK
WaitMove: Char=Caster
StartThread
Wait: Time=4
WaitSFXLoaded: SFX=Iai_Strike_1
PlaySFX: SFX=Iai_Strike_1
WaitSFXDone: SFX=Iai_Strike_1
EndThread
PlayAnimation: Char=Caster ; Anim=MP_ATTACK
WaitAnimation: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=-200 ; UseCollisionRadius=True ; Time=0
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=1100 ; UseCollisionRadius=True ; Anim=MP_STEP_BACK
WaitMove: Char=Caster
EndThread

15
Since you have the Steam version of the game, you can use Memoria's feature for doing things like that. For that, you need to have Memoria updated to some recent version if you haven't done that already: https://github.com/Albeoris/Memoria/releases/latest.
Then, use custom ".seq" files. These are similar to the animation sequences you can edit in Hades Workshop but they allow much more things.

For example, in Alternate Fantasy, I used this sequence file for one of Zidane's ability: it performs a double-hit much like what you want (I think).
Code: [Select]
// Player sequence of SFX Iai_Strike_2
// Used by Zidane (Windfall with a dagger)

WaitAnimation: Char=Caster
Message: Text=[CastName] ; Priority=1 ; Title=True ; Reflect=True
SetupReflect: Delay=SFXLoaded
LoadSFX: SFX=Iai_Strike_1 ; Reflect=True ; UseCamera=False
PlayAnimation: Char=Caster ; Anim=MP_SET
WaitAnimation: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=670 ; UseCollisionRadius=True ; Anim=MP_RUN
Turn: Char=Caster ; BaseAngle=AllTargets ; Time=4
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=400 ; UseCollisionRadius=True ; Anim=MP_RUN_TO_ATTACK
WaitMove: Char=Caster
StartThread
Wait: Time=4
WaitSFXLoaded: SFX=Iai_Strike_1
PlaySFX: SFX=Iai_Strike_1
WaitSFXDone: SFX=Iai_Strike_1
EndThread
PlayAnimation: Char=Caster ; Anim=MP_ATTACK
WaitAnimation: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=-200 ; UseCollisionRadius=True ; Time=0
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=1100 ; UseCollisionRadius=True ; Anim=MP_STEP_BACK
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=670 ; UseCollisionRadius=True ; Anim=MP_RUN
Turn: Char=Caster ; BaseAngle=AllTargets ; Time=4
WaitMove: Char=Caster
MoveToTarget: Char=Caster ; Target=AllTargets ; Distance=400 ; UseCollisionRadius=True ; Anim=MP_RUN_TO_ATTACK
WaitMove: Char=Caster
StartThread
Wait: Time=4
WaitSFXLoaded: SFX=Iai_Strike_1
PlaySFX: SFX=Iai_Strike_1
WaitSFXDone: SFX=Iai_Strike_1
EndThread
PlayAnimation: Char=Caster ; Anim=MP_ATTACK
WaitAnimation: Char=Caster
MoveToPosition: Char=Caster ; AbsolutePosition=Default ; Anim=MP_BACK
Turn: Char=Caster ; BaseAngle=Default ; Time=4
WaitMove: Caster
PlayAnimation: Char=Caster ; Anim=Idle
WaitTurn: Char=Caster
ActivateReflect
WaitReflect
By having this file saved as "{Mod Folder}/StreamingAssets/Data/SpecialEffects/ef030/Sequence.seq", the abilities that use the spell effect "Iai Strike 2" (that you can pick in Hades Workshop) will perform a double-hit with the Iai Strike effect.

You can find more informations on how to write .seq files on the wiki: https://github.com/Albeoris/Memoria/wiki/Battle-SFX-Sequence

16
Hi.
I'm pretty sure that's the mod Dragon Knight Rising messing with abilities (and surely the items as well, hence the Cotton Robe price). I don't think you can do much about that right now: either you'll have these differences or you need to disable it. Mod compatibility of two mods that both change the gameplay is difficult to maintain unfortunatly.

17
Sorry, I can't help you with those.

1) Yes, the game script isn't meant to allow Beatrix in multiple instances. The Desert Palace / Oeilvert split being surely the biggest obstacle. You'd need to create a bunch of functions to have Beatrix appear in these scenes or even to avoid crashes and soft-locks.
Everytime the script uses something like "RunScriptSync( XX, 252, XX )", it searches for a script linked to one of the 4 party members. It soft-locks if Beatrix is that party member and doesn't have the corresponding function. That kind of thing is used a lot for animations, walks, dialogs... in places where the characters present aren't fixed. And as you said, there are also a lot of "IsInParty" checks, sometimes in scripts that assume that "IsInParty(X)" works for exactly 3 characters when X ranges from 1 to 7...
Honestly, that's a huge work to make and it couldn't even be automatized because each script works differently and should be fixed in a different way.

2) You can't do that for the PSX version. Removing the Change Model line is the furthest thing you can do there. I'm actually not even sure if Blank's Pluto Armor model exists in the discs 2, 3 and 4 in the PSX version (or maybe the battle model exists but not the field version).
I guess searching for the IDs of the trance models in the binary file could lead to some results. If you're lucky, these IDs are stored in a row or in a pattern that could be found. Again, that requires the use of a hexa-decimal file editor, not something that HW can do.
The list of model IDs used in the game can be downloaded here.

18
Hi.
No, that glitch is tied to the game's engine, not any field script. Unless I'm mistaken, it is fixed by Memoria for the PC version of the game (it may also be fixed by the PC version of the game already with some of the official updates).
You won't be able to fix that glitch for the PSX version of the game... except if you're willing to dig in the hexa-decimal file and decode MIPS assembly. That cannot be done with Hades Workshop anyway.

19
Hi Charlie_38.
There's no problem. Me and other people have done it without noticing any bug and there shouldn't be any. There would be issues if you tried to load a HWS that was created with HW v0.50b into the older version of HW v0.43, but the other way around is designed to work fine.

20
Ah yes, I didn't remember when I fixed that bug. It's a bug of Memoria and it's fixed in that commit... which is not part of a release yet.

I can't work on FF9 modding for some time. I have a few other bugs to fix / features to add before releasing the next version, and DV's great work to review, but I'm not sure when that will be done.

21
Thank you. Best wishes to you, wherever you are.

22
I think that's because you don't have the latest version of Memoria. Your installation sequence is the best but for some reason I think you didn't use the latest version (June 2023).

23
Hi ProudPumpkin.
You need Alternate Fantasy's HWS file for that. You can download it from there ("AF and PCP source files.zip"):
https://www.dropbox.com/sh/ac7sr4q3z2cx9vp/AACQDfqXPvn8c3ylXeGUrBKEa?dl=0

24
Yes, it works now with the new system provided by Memoria.

25
1) Install FF9
2) Install Moguri
3) Install latest version of Memoria

Pages: [1] 2 3 4 5 6 ... 36