Author Topic: Multi-Command Materia  (Read 7596 times)

MYTHOS

  • *
  • Posts: 5
    • View Profile
Multi-Command Materia
« on: 2014-05-04 23:40:09 »
Greetings,

I am trying to find out if it is possible to have multiple commands active on command materia.  Currently, it seems any new commands unlocked on a materia will replace the previous command. 

For example, if you have a single command materia with both sense and morph on it, sense will be replaced by morph on the command list once it is unlocked.

I would like to be able to add multiple commands to a single command materia that unlock by AP level.

I have read some older posts that state it can be done via a hex edit in the FF7.exe, but I did not want to necro those threads. 

I could make the edit if anyone happens to know what needs changed.  Figuring it out from scratch is beyond my skill level.

Any suggestions or information on this would be greatly appreciated.  I apologize if I missed a thread where this was already answered.

nfitc1

  • *
  • Posts: 3013
  • I just don't know what went wrong.
    • View Profile
    • WM/PrC Blog
Re: Multi-Command Materia
« Reply #1 on: 2014-05-05 02:43:42 »
This is possible through some clever editing of the exe. Unfortunately, I'm in the middle of a big move so I can't help just yet. I can probably have an answer to this query in a few days. I'd be good to have a reference on how to do this for future knowledge seekers. (though I'm probably not the only one that could help, but if I had the time I could get the answer pretty fast)

MYTHOS

  • *
  • Posts: 5
    • View Profile
Re: Multi-Command Materia
« Reply #2 on: 2014-05-05 03:54:22 »
Thank you very much, I appreciate your help.  I'm in no hurry at all, take your time and good luck with your move.  I look forward to hearing back at a later time.

nfitc1

  • *
  • Posts: 3013
  • I just don't know what went wrong.
    • View Profile
    • WM/PrC Blog
Re: Multi-Command Materia
« Reply #3 on: 2014-05-10 00:57:17 »
I finally got Internet again, but it's not a good time for me to dig it out. :(

Fear not. Answer still pending.

EDIT:
Here's my slightly-hasty initial solution candidate. When a command materia is equipped the game will cycle backwards through the max level to find the highest leveled non-null command on that materia. There is no traditional materia that this creates an issue for so I assume this is for a custom materia.
Code: [Select]
    for ( j = v7 - 1; j >= 0; --j )  //v7 is the level of this materia instance
    {
      v2 = (unsigned __int8)*(&MateriaAttrib1[20 * a1] + j);  //a1 is the materia index
      if ( v2 != 255 )
        break;
      v2 = j - 1;
    }
    LOBYTE(v2) = *(&MateriaAttrib1[20 * a1] + j);
    result = AddCommand(v2);
As you can see the "AddCommand" function call is outside of the loop. What needs to happen is to change the loop's boundries and conditions.
Code: [Select]
    for ( j = v7 - 1; j >= 0; --j )
    {
      v2 = (unsigned __int8)*(&MateriaAttrib1[20 * a1] + j);
      if ( v2 != 255 )
         AddCommand(v2);
    }

Here's the binary at 0x5CEC0B (0x1CE00B)
Code: [Select]
8B 45 FC mov eax, [ebp+MateriaAPLevel]
83 E8 01 sub eax, 1
89 45 F8 mov [ebp+LoopCounter], eax
EB 09 jmp short loc_5CEC1F
8B 4D F8 mov ecx, [ebp+LoopCounter]
83 E9 01 sub ecx, 1
89 4D F8 mov [ebp+LoopCounter], ecx
83 7D F8 00 cmp [ebp+LoopCounter], 0
7C 24 jl short loc_5CEC49
8B 55 08 mov edx, [ebp+arg_0]
81 E2 FF 00 00 00 and edx, 0FFh
6B D2 14 imul edx, 14h
8B 45 F8 mov eax, [ebp+LoopCounter]
33 C9 xor ecx, ecx
8A 8C 02 6E DF DB 00 mov cl, MateriaAttrib1[edx+eax]
81 F9 FF 00 00 00 cmp ecx, 0FFh
74 02 jz short loc_5CEC47
EB 02 jmp short loc_5CEC49
EB CD jmp short loc_5CEC16
8B 55 08 mov edx, [ebp+arg_0]
81 E2 FF 00 00 00 and edx, 0FFh
6B D2 14 imul edx, 14h
8B 45 F8 mov eax, [ebp+LoopCounter]
8A 8C 02 6E DF DB 00 mov cl, MateriaAttrib1[edx+eax]
51 push ecx ; CommandIndex
E8 84 00 00 00 call AddCommand ; MateriaAttrib based on level
83 C4 04 add esp, 4
EB 7A jmp short loc_5CECE4
Here's version one of what I think it should be:
Code: [Select]
8B 45 FC mov eax, [ebp+MateriaAPLevel]
83 E8 01 sub eax, 1
89 45 F8 mov [ebp+LoopCounter], eax
EB 09 jmp short loc_5CEC1F
8B 4D F8 mov ecx, [ebp+LoopCounter]
83 E9 01 sub ecx, 1
89 4D F8 mov [ebp+LoopCounter], ecx
83 7D F8 00 cmp [ebp+LoopCounter], 0
0F 8C BB 00 00 00 jl loc_5CECE4
8B 55 08 mov edx, [ebp+arg_0]
81 E2 FF 00 00 00 and edx, 0FFh
6B D2 14 imul edx, 14h
8B 45 F8 mov eax, [ebp+LoopCounter]
33 C9 xor ecx, ecx
8A 8C 02 6E DF DB 00 mov cl, MateriaAttrib1[edx+eax]
81 F9 FF 00 00 00 cmp ecx, 0FFh
74 1C jz short loc_5CEC65
8B 55 08 mov edx, [ebp+arg_0]
81 E2 FF 00 00 00 and edx, 0FFh
6B D2 14 imul edx, 14h
8B 45 F8 mov eax, [ebp+LoopCounter]
8A 8C 02 6E DF DB 00 mov cl, MateriaAttrib1[edx+eax]
51 push ecx
E8 84 00 00 00 call AddCommand
EB AF jmp short loc_5CEC16
90 90 90 nop
The last three nops are code alignment bytes. I think that should work. Here's what it translates into:
Quote
    for ( j = v7 - 1; j >= 0; --j )
    {
      v3 = (unsigned __int8)*(&MateriaAttrib1[20 * a1] + j);
      if ( v3 != 255 )
      {
        LOBYTE(v3) = *(&MateriaAttrib1[20 * a1] + j);
        result = AddCommand(v3);
      }
    }
So it looks like it should work. I don't have any materia to test it with so I can't say for sure. Make those changes and let me know if it works or what it does if it doesn't.
« Last Edit: 2014-05-11 03:11:24 by NFITC1 »

MYTHOS

  • *
  • Posts: 5
    • View Profile
Re: Multi-Command Materia
« Reply #4 on: 2014-05-11 05:24:11 »
Thanks for all of that information, it was pretty far over my head but I have it working.

Tested Command materia with 2 commands and 3 commands
Tested leveling up and mastering the materia
Tested using the unlocked abilities with Cloud
Tested removing and equipping materia, just in case.

In all tests everything worked great.  The only drawback I noticed was that the field menu text on the materia doesn't keep each name highlighted as new commands are unlocked.  Once the second command becomes available command1 greys out, although it still works.  If a third command is learned it also does not highlight, instead the command2 still stays highlighted.
Minor thing, not sure if that is handled in the ff7.exe or not, and I'm also using a menu overhaul that could be interfering. 

All text appears correctly in the battle menus.

Again, I really appreciate your help on this.  I hope all went well with your move, good luck in your new location.
« Last Edit: 2014-05-11 09:15:08 by MYTHOS »

nfitc1

  • *
  • Posts: 3013
  • I just don't know what went wrong.
    • View Profile
    • WM/PrC Blog
Re: Multi-Command Materia
« Reply #5 on: 2014-05-11 12:31:51 »
The only drawback I noticed was that the field menu text on the materia doesn't keep each name highlighted as new commands are unlocked.  Once the second command becomes available command1 greys out, although it still works.  If a third command is learned it also does not highlight, instead the command2 still stays highlighted.
Minor thing, not sure if that is handled in the ff7.exe or not, and I'm also using a menu overhaul that could be interfering. 

It actually is handled in that same function. I can provide a fix for that too, but that'll come later.

Bosola

  • Fire hazard!
  • *
  • Posts: 1749
    • View Profile
    • My YouTube Channel
Re: Multi-Command Materia
« Reply #6 on: 2014-05-11 15:36:43 »
How did you trace / find this? I was wondering if it might be worth writing a PSOne implementation.

nfitc1

  • *
  • Posts: 3013
  • I just don't know what went wrong.
    • View Profile
    • WM/PrC Blog
Re: Multi-Command Materia
« Reply #7 on: 2014-05-11 19:36:59 »
I have it labeled as the Materia Type 6 handler. That's where the "AddCommand" function exists that adds a command based on materia attribs.

nfitc1

  • *
  • Posts: 3013
  • I just don't know what went wrong.
    • View Profile
    • WM/PrC Blog
Re: Multi-Command Materia
« Reply #8 on: 2014-05-12 16:26:27 »
...the field menu text on the materia doesn't keep each name highlighted as new commands are unlocked...

This has a less obvious solution, but it picks up right where the previous one left off.
Code: [Select]
  v7 = GetMateriaAPLevel(a1, MateriaAP);
...
    v4 = dword_C06910;
    for ( i = 0; i < 5; ++i )
    {
      *(_BYTE *)(v4 + 2 * i + 26) = *(&MateriaAttrib1[20 * a1] + i);
      *(_BYTE *)(v4 + 2 * i + 27) = 0;
    }
    if ( *(_BYTE *)(v4 + 1) == v7 )
    {
      *(_BYTE *)(v4 + 2 * v7 + 23) = 1;  //this assumes that there are no materia that gain a command when mastered.
    }
    else
    {
      *(_BYTE *)(v4 + 2 * v7 + 25) = 1;
    }
v4 holds a structure that, among other things, tells the menu draw method which commands to display and which palette to use (0 is grey, 1 is white).
[v4 + 1] is the materia's highest level so if the current level equals this then the materia is mastered.
[v4 + 26] is which command name to draw
[v4 + 27] is which palette to use
There are five slots for this so potentially five commands can be granted with one materia (except for Master Command of course).
 v7 is always at least 1 so that last command will tell the current level to draw the AP level command as white. What we want this to be is:
Code: [Select]
v7 = GetMateriaAPLevel(a1, MateriaAP);
...
    v4 = dword_C06910;
    for ( i = 0; i < 5; ++i )
    {
      *(_BYTE *)(v4 + 2 * i + 26) = *(&MateriaAttrib1[20 * a1] + i);
      if ( i < v7 )
         *(_BYTE *)(v4 + 2 * i + 27) = 1;
      else
         *(_BYTE *)(v4 + 2 * i + 27) = 0;
    }
So like before, here's a before and after starting with before at 0x5CEC85 (0x1CE085):
Code: [Select]
83 7D F8 05 cmp     [ebp+LoopCounter], 5
7D 2D jge     short loc_5CECB8
8B 4D 08 mov     ecx, [ebp+arg_0]
81 E1 FF 00 00 00 and     ecx, 0FFh
6B C9 14 imul    ecx, 14h
8B 55 F8 mov     edx, [ebp+LoopCounter]
8B 45 F4 mov     eax, [ebp+var_C]
8B 75 F8 mov     esi, [ebp+LoopCounter]
8A 8C 31 6E DF DB 00 mov     cl, MateriaAttrib1[ecx+esi]
88 4C 50 1A mov     [eax+edx*2+1Ah], cl
8B 55 F8 mov     edx, [ebp+LoopCounter]
8B 45 F4 mov     eax, [ebp+var_C]
C6 44 50 1B 00 mov     byte ptr [eax+edx*2+1Bh], 0
EB C4 jmp     short loc_5CEC7C
8B 4D F4 mov     ecx, [ebp+var_C]
33 D2 xor     edx, edx
8A 51 01 mov     dl, [ecx+1]
3B 55 FC cmp     edx, [ebp+MateriaAPLevel]
75 0D jnz     short loc_5CECD2
8B 45 FC mov     eax, [ebp+MateriaAPLevel]
8B 4D F4 mov     ecx, [ebp+var_C]
C6 44 41 17 01 mov     byte ptr [ecx+eax*2+17h], 1
EB 0B jmp     short loc_5CECDD
8B 55 FC mov     edx, [ebp+MateriaAPLevel]
8B 45 F4 mov     eax, [ebp+var_C]
C6 44 50 19 01 mov     byte ptr [eax+edx*2+19h], 1
now after:
Code: [Select]
83 7D F8 05 cmp     [ebp+LoopCounter], 5
7D 52 jge     short loc_5CECDD
8B 4D 08 mov     ecx, [ebp+arg_0]
81 E1 FF 00 00 00 and     ecx, 0FFh
6B C9 14 imul    ecx, 14h
8B 55 F8 mov     edx, [ebp+LoopCounter]
8B 45 F4 mov     eax, [ebp+var_C]
8B 75 F8 mov     esi, [ebp+LoopCounter]
8A 8C 31 6E DF DB 00 mov     cl, MateriaAttrib1[ecx+esi]
88 4C 50 1A mov     [eax+edx*2+1Ah], cl
33 D2 xor     edx, edx
8B 55 F8 mov     edx, [ebp+LoopCounter]
3B 55 FC cmp     edx, [ebp+MateriaAPLevel]
7D 0D jge short loc_5CECC2
8B 55 F8 mov     edx, [ebp+LoopCounter]
8B 45 F4 mov     eax, [ebp+var_C]
C6 44 50 1B 01 mov     byte ptr [eax+edx*2+1Bh], 1
EB 0B jmp short loc_5CECCD
8B 55 F8 mov     edx, [ebp+LoopCounter]
8B 45 F4 mov     eax, [ebp+var_C]
C6 44 50 1B 00 mov     byte ptr [eax+edx*2+1Bh], 0
EB AD jmp short loc_5CEC7C
90 90 90 90 nop
90 90 90 90 nop
90 90 90 90 nop
90 90 nop
That should tell the menu to use palette 1 for all commands that are in attributes up to the level of the materia.

MYTHOS

  • *
  • Posts: 5
    • View Profile
Re: Multi-Command Materia
« Reply #9 on: 2014-05-13 03:13:33 »
I got to test the changes you posted above and it seems to be working great.  I tried out several triple command variations with no issues at all.  It even had the added benefit of separating the Coin/Throw commands when only one of the two were present on the materia.  I thought I would need to split the commands to do this, like I had seen done for x2cut/x4cut in another post you had made.

Having the variables defined definitely helped me understand it a *little* more.  I do a small amount of object-oriented MEL and Python for work, nothing close to this, rigging stuff mostly.  The basic syntax made sense but I was clueless to the variables.  I'm learning slowly, but still trying to grasp the basics.

When you post two offsets, for example: "0x5CEC85 (0x1CE085)" are these for PSX (PC), respectively?
My offsets are always the second, and I've seen a few other posts where an offset is given that is not present in my exe file.  This one in particular:
0x5DE704: 83 78 28 20  ->  83 78 28 50
I wanted to ask, but didn't want to necro that thread.  My assumption is, based on your post, it is an offset for PSX.  That particular hex code only shows up twice (I think) so it's pretty easy to test, but I was curious for future reference if there was a method to convert PSX offsets to PC offsets.

I can't stress how much I appreciate your contributions to the forum and your help.  Just browsing your posting history is a tutorial session.  I've spent more hours in WallMarket than I can count and I'm starting to work with Proud Clod as of this week.  Amazing tools.
« Last Edit: 2014-05-13 03:58:50 by MYTHOS »

nfitc1

  • *
  • Posts: 3013
  • I just don't know what went wrong.
    • View Profile
    • WM/PrC Blog
Re: Multi-Command Materia
« Reply #10 on: 2014-05-13 13:43:09 »
I got to test the changes you posted above and it seems to be working great.  I tried out several triple command variations with no issues at all.  It even had the added benefit of separating the Coin/Throw commands when only one of the two were present on the materia.  I thought I would need to split the commands to do this, like I had seen done for x2cut/x4cut in another post you had made.
Coin should always alternate between coin and throw when in battle. Does it actually not do that with this change? That's interesting. In any case it's good to know this change works as intended.

Having the variables defined definitely helped me understand it a *little* more.  I do a small amount of object-oriented MEL and Python for work, nothing close to this, rigging stuff mostly.  The basic syntax made sense but I was clueless to the variables.  I'm learning slowly, but still trying to grasp the basics.
More is almost always preferable to less especially with technical information on this scale. I try to be as verbose yet succinct as possible when describing what's changing.

When you post two offsets, for example: "0x5CEC85 (0x1CE085)" are these for PSX (PC), respectively?
My offsets are always the second, and I've seen a few other posts where an offset is given that is not present in my exe file.  This one in particular: I wanted to ask, but didn't want to necro that thread.  My assumption is, based on your post, it is an offset for PSX.  That particular hex code only shows up twice (I think) so it's pretty easy to test, but I was curious for future reference if there was a method to convert PSX offsets to PC offsets.
This is virtual and real address offsets. It really only depends on how you're looking at the code. The real offset is the one in parentheses and where you'll find the bytes in a hex editor. The virtual addresses are memory offsets when the program is running in memory and is more helpful in advanced situations. I include both for ease of use for future reference.

I can't stress how much I appreciate your contributions to the forum and your help.  Just browsing your posting history is a tutorial session.
That is exactly why I post the way I do. :)

I've spent more hours in WallMarket than I can count and I'm starting to work with Proud Clod as of this week.  Amazing tools.
Good to know. PrC is still a bit buggy and WM still has one pending version (nothing major, mostly aesthetic).

MYTHOS

  • *
  • Posts: 5
    • View Profile
Re: Multi-Command Materia
« Reply #11 on: 2014-05-14 04:45:29 »
Does it actually not do that with this change?
Let me clarify that.  I'm pretty sure it's all working as intended.
  • The issue I was having was with the Throw command still alternating to Coin when the level two command was unlocked, even if I did not place Coin on the materia in question.  The last edit you posted resolved that issue.
  • The Coin command still alternates, the Throw command does not.
  • If Coin and Throw are on the same character they will be listed separate and Coin will alternate, while Throw will not.

This is virtual and real address offsets. It really only depends on how you're looking at the code. The real offset is the one in parentheses and where you'll find the bytes in a hex editor.
Is there a standard offset from the virtual to real address?  Meaning, can I take a virtual address I see posted and offset it by a set amount to always arrive at the real address? 
I see some of your posts that just give the virtual address and I'm trying to find a way to convert those.


The virtual addresses are memory offsets when the program is running in memory...
I use HxD and it seems to only display the real address.  I thought after reading this I might be able to see the virtual address if I opened the ff7.exe while I had the game running, but it still displayed the real address.  Feel free to laugh at me if that was ridiculous.  ;D 
« Last Edit: 2014-05-14 09:00:08 by MYTHOS »

nfitc1

  • *
  • Posts: 3013
  • I just don't know what went wrong.
    • View Profile
    • WM/PrC Blog
Re: Multi-Command Materia
« Reply #12 on: 2014-05-15 13:40:44 »
I thought I already replied to this. Guess not.
Is there a standard offset from the virtual to real address?  Meaning, can I take a virtual address I see posted and offset it by a set amount to always arrive at the real address? 
I see some of your posts that just give the virtual address and I'm trying to find a way to convert those.
Not exactly. Between each exe it will be the same offset for virtual to real. I do my "work" on a debugger attached to the 98 exe so the offset is 0x401000. The debugger gives me both, but for most people's purposes, the real is all they'd need. I provide the virtual in the rare instance where the offset is different. I think the Steam binary uses a different offset.

I use HxD and it seems to only display the real address.  I thought after reading this I might be able to see the virtual address if I opened the ff7.exe while I had the game running, but it still displayed the real address.  Feel free to laugh at me if that was ridiculous.  ;D
If you were using a debugger you might see the virtual addresses. They come into play while in memory (not storage) and when making method calls.