Hi-Tech: A Chrono Trigger tech editor for Temporal Flux! Beta 31 out!

Started by Mauron, February 25, 2011, 09:19:59 AM

Previous topic - Next topic

Cthulhu88

Quote from: Mauron on September 08, 2019, 04:39:26 PM
Definitely no on the that change, but there is a simpler change to remove two commands. db $35, 0 at $0E2D7C. Actually, db $71 at $0E2D77 might work better (Drawing Status: Show Effect to Drawing Status: Hide Effect). 00 works as an object terminator, so any commands beyond it would be ignored.

What if I move the other ones up and zero the trailing bytes? The two commands I need to remove are at the end of the object.

Mauron

Mauron wuz here.

Cthulhu88

Sorry for taking so long to get back at this. I was busy with the MSU-1 patch and the SNES checksum calculator.

Anyway, your suggestion to suppress that last Draw Effect command turned out to be undesirable. It would not play the final pink heart animation.

This is what I ended up with for Charm and Twin Charm:
// +++ Ayla's Charm Tech +++

// Control Header
seek($CC1DE2) // [Hit Effects]
    db $00    // None
    db $00    // None
    db $00    // None

// Effect Header 1
seek($CC235B) // [Mode]
    db $02    // Status Impact
    db $01    // Negative Status
seek($CC235D) // [Status]
    db $80    // Stop
seek($CC2360) // [Success]
    db 80     // Base
    db 0      // Bonus
seek($CC2362) // [Options]
    db $40    // Ignore Shield Status

// Animation Objects
seek($CE2D7C) // [Effect Object #6]
    db $35    // Increment Counter 1C Flow Control
    dw $0523  // Wait for Counter 1C Flow Control ($05)
    db $71    // Drawing Status: Hide Effect
    fill 5    // Return

// Tech Description
if {defined EX} {
seek($F68417)
} else {
seek($CC3E23)
}
    db $B2,$32,$C9,$EF,$33,$BE,$C6,$D2 // Stop enemy
    fill 4

// --- Ayla's Charm Tech ---

// +++ Marle & Ayla's Twin Charm Tech +++

// Control Header
seek($CC1F67) // [Overrides]
    db $00    // None
seek($CC1F6E) // [Hit Effects]
    db $1E    // 100% chance of 50% HP damage
    db $00    // None
    db $00    // None

// Effect Header 1
seek($CC2463) // [Mode]
    db $03    // Damage
seek($CC2464) // [Status]
    db 100    // Chance
    db $04    // Confuse
seek($CC2468) // [Damage]
    db $03    // Formula (Magic Attack)
seek($CC246A) // [Options]
    db $E4    // Ignore Barrier Status, Ignore Shield Status, Ignore Hit and Evade
seek($CC246B) // [Damage]
    db $00    // Modifier
    db $01    // Power

// Animation Objects
seek($CE4F6B) // [Effect Object #7]
    db $35    // Increment Counter 1C Flow Control
    dw $0523  // Wait for Counter 1C Flow Control ($05)
    db $71    // Drawing Status: Hide Effect
    fill 5    // Return

// Tech Description
if {defined EX} {
seek($F686ED)
} else {
seek($CC40F1)
}
    db $A7,$4D,$3A,$CC,$EF,$33,$BE,$C6,$D2,$EF,$A7,$AF // Halves enemy HP

// --- Marle & Ayla's Twin Charm Tech ---


What do you think? I did some basic testings in game and everything seems to be working as intended.
I still need to figure out what I am going to do with Charm Top. I'll probably turn that into a Marle only accessory and add something that makes her more useful late game. Thing is, I am fairly sure the item has some ad hoc code checking for it, should I care to find this code and nop it out or since I am disabling stealing, is it effectively harmless?
Ideas on what I could turn the Charm Top into without adding new code into the game (trying to keep this hack as simple as possible) would be greatly appreciated aswell.

As for HiTech, I've used it mostly for finding offsets and values and here is my list of issues:
  • Lots and lots of GUI bugs. I am not sure whether this is related to the fact that I am running 1024x768 due to me lacking a GPU at the moment or not, but HiTech will glitch out constantly. Widgets being rendered over other elements, widgets vanishing and requiring a restart, scroll bugging out and not letting you fully scroll down or letting you scroll out of bounds, etc.
  • Clicking on the Layer 3 Packet header will cause an unhandled exception (index out of bounds) if the Tech has no layer 3 packet.
  • Damage Modifier in the Effect headers is way too bugged to be used. It will either not input the correct value or write the wrong value to the ROM, despite the plugin showing the correct one.

And here is a suggestion, not just for HiTech but for all your TF plugins.
If you do know the name of an item, enemy or tech but not its index, it becomes incredibly frustating to find the specific entry within the dropdown menus, more so with the bigger ones that go all the way to index 255.
My suggestion is to either add sorting, allowing you to sort either by index or by alphanumeric order, or combine the dropdown menus with a text box widget that will search for the specific substring.

Regards.

Mauron

I think the only Charm Top code is at $C1E9DB, where it checks against the current accessory index and modifies the charm chance loaded. It should be safe to ignore. I'm not 100% sure on what a good replacement would be though.

Those GUI bugs: I thought I squished them all. It has something to do with the docking used by Temporal Flux and different resolutions. I'll take another look at the larger problem, and if I don't see a solution I'll adjust my quick fix.
Layer 3 exception: Dealt with in my current build.
Damage Modifier: Found the issue, dealt with in current build.

I'll definitely look into sorting or search for dropdowns. I have a rough idea where many things are in various lists because there's no way to sort them, in Temporal Flux as well as my plugins, but never thought to improve that.
Mauron wuz here.

Cthulhu88

Just one more thing to complete my annoying OCD duty. On Tech Mode Damage, Status Chance is placed in the middle of the status flags (below Blind), which is kind of odd, not to mention the address for chance is one byte before the status byte.

Also, while working on Twin Charm options, checking Ignore Shield Status, Ignore Barrier Status and Ignore Evade and Hit would give me the value $E0 ($20|$40|$80), however, after setting the Confuse status flag ($04) the value above would become $E4, despite bit 2 already being set on the status byte. Is this a bug or an undefined behavior?

Mauron

Yeah, that's bad organization. Maybe I'll move Status Chance into its own category?

In the options flag, $4 is the Inflicts Status flag used for Damage techs. I chose to set this bit if any statuses were chosen, rather than having it a UI option. I did notice it isn't cleared if the mode is changed from damage to anything else, which could cause unpredictable behavior.
Mauron wuz here.

Cthulhu88

By any chance, do you understand why the game does this?

fdac10 cmp $cc5e05,x
fdac14 beq $ac4d


When you kill an enemy and that enemy can drop an item, it will compare the drop slot with the charm slot, and if they are the same item, it jumps to a much simpler code. The ending for both codes are almost the same, with the only difference being where it stores the dropped item. When drop != charm, it stores on $7EB2A7-$7EB2A9, and when drop == charm, it stores on $7EB2AA-$7EB2AC.

EDIT: Seems to be related to how Ayla can charm items from enemies from the drop slot if the charm slot doesn't have an item/enemy was already charmed. Apparently when an enemy has the same item on both slot, it will always drop one, even when the same item was already charmed.

Ended up with this hack:
scope Rewards {

seek($FDAC08)
scope Items: {
    // This hack allows for more than 3 items to be dropped per battle and
    // repurposes the charm slot into the maximum number of the same item
    // that can be dropped per battle.

    lda.l $CC5E04,x // Enemy rewards (drop).
    beq .Exit
    sta.b $10

    lda.l $CC5E05,x // Enemy rewards (charm).

    sep #$10

    ldy.b #$00
-
    ldx.w $B2A7,y // Memory location containing the dropped items.
    beq .Drop

    cpx.b $10
    bne +
    cmp.b #null
    beq .NoDrop // No more items of this type should drop.
    dec
+
    iny
    cpy.b #6 // Maximum number of items (all).
    bcc -

.NoDrop:
    rep #$10

    rtl

.Drop:
    rep #$10

    lda.b $10
    sta $B2A7,y

    lda.b #$20
    tsb.w $B2AF

    rtl

assert("Rewards.Items", pc(), .Exit)

fill (.Exit - pc()),$FF // Initialize unused bytes to $FF.

seek($FDAC6D)
.Exit:
}

}

I am unsure if by removing the != code (which involves some big functions) I've broken something. My testings show everything is working fine.

Mauron

Biggest difference I'm seeing between the two versions. Drop == charm has a guaranteed drop, while drop != charm has a 90% chance of dropping an item.

lda #$64
jsl $C1FDCB
cmp #$5a


$c1fdcb has a jsr $af22, which is used throughout battle as a percentage routine. So far it's always been preceded a lda #$64, but maybe somewhere a different value is loaded?
Mauron wuz here.

Cthulhu88

Quote from: Mauron on September 17, 2019, 08:18:47 PM
Biggest difference I'm seeing between the two versions. Drop == charm has a guaranteed drop, while drop != charm has a 90% chance of dropping an item.

lda #$64
jsl $C1FDCB
cmp #$5a


$c1fdcb has a jsr $af22, which is used throughout battle as a percentage routine. So far it's always been preceded a lda #$64, but maybe somewhere a different value is loaded?

Interesting. I'd figured out the guaranteed drop chance on == on my edit, but I didn't continue looking into it and certainly didn't know the game had a 90% chance for the drop slot.
And it does make sense to always pass $64 to a random int percentage function. I had given up looking into that jsl and its jsrs because of their depth.

Either way, I believe I am better off with the way I've it coded right now.
I've greatly reduced the overall amount of loot from enemies (mainly consumables) while most unique items are dropped from bosses. It seems appropriate to always give an item from an enemy that has one in its drop slot.

Normal enemy:
enemy($CC5E5F) // ($0D) Green Imp
    Items.drop(Items.NONE)
    Items.max(0)


Special enemy:
enemy($CC5E43) // ($09) Panel
    Items.drop(Items.SPEED_TAB)
    Items.max(inf)


Boss enemy:
enemy($CC5E4A) // ($0A) Mammon M.
    Items.drop(Items.MEGAELIXIR)
    Items.max(0)


I also have some normal enemies drop some consumables that can't be bought or easily obtainable through chests.
enemy($CC5FA1) // ($3B) Mage
    Items.drop(Items.BARRIER)
    Items.max(0)

Items.max(0) also makes it follow the vanilla procedure and only allow one item per type.

I think I'll break my system if I add the 90% chance back. Imagine not being able to obtain some of the unique items from bosses.

One thing is still puzzling me though, why does it store the item indexes into different offsets based on whether it's equal to the charm slot or not.

Mauron

I get the benefit of using $64 as a value, but not passing the same value in every time. If it's always the same, why set it outside the function?

I'm curious about the address change as well. I think I'll poke into that a little.


Edit: It was designed with 6 potential dropped items in mind, 3 with a chance and 3 with a guarantee. Right now I'm wondering if at some point multiple items of one type were considered.
Mauron wuz here.

Cthulhu88

Quote from: Mauron on September 17, 2019, 09:29:30 PM
I get the benefit of using $64 as a value, but not passing the same value in every time. If it's always the same, why set it outside the function?

I'm curoius about the address change as well. I think I'll poke into that a little.

Generally you push the range into the stack before calling the function, as most of these functions are just generic randint/randfloat functions.

This is an usual generic random range function for C++ that gets used as % chance:
int System::Random(int end, int start = 0)
{
    // seed: CryptGenRandom, /dev/urandom, etc
    // algorithm: linear, mersenne twister, etc
}


You can test with my code above, just by changing the store instruction to store to all 6 bytes:
    lda.b $10
-
    sta $B2A7,y
    iny
    cpy.b #6
    bcc -


You will be getting 6 items per battle. The routine that actually adds the items seems to iterate over 7EB2A7 until 7EB2AC or until a zero'ed byte is found. It might be used by charm, as the routine that writes those bytes do check for the drop flag ($40).
Or it might've been 'artistic integrity'  ::)

I'll set some read breakpoints in there tomorrow and further study this.

Mauron

You beat me to finishing my slow edit, but I think it's to make sure guaranteed drop items will be dropped.

I think with the original setup, you could actually get 3 of a guaranteed item with Charm, since the guaranteed version doesn't check if the drop has been stolen.
Mauron wuz here.

Cthulhu88

Do you know if it's possible to make 1/2 HP never deal any damage when the target is immune to it without extra code? 40% instant death chance from Blackhole will not deal any damage when it fails or when the target is immune to it, but 1/2 will still deal some damage.
The best I was able to do was reduce that damage by setting the defense byte and setting power to 1 (0 is considered a miss).

Mauron

From what I've seen of the code, it would require at least some changes. I'm not 100% on how much though.
Mauron wuz here.

Cthulhu88

Quote from: Mauron on September 19, 2019, 06:03:33 PM
From what I've seen of the code, it would require at least some changes. I'm not 100% on how much though.

That's what I thought. Unfortunately, I really don't want to allocate physical space for this hack. I'll see if I can at least make it do just 1 damage by messing with the formula and defense.

Thanks for all your help.

September 20, 2019, 10:56:11 PM - (Auto Merged - Double Posts are not allowed before 7 days.)

0x19 is the stats index for Tech Immunities. You've it as unknown.