Still haven't been working on this much recently, trying to keep that PSO2 translation up to date and play that game in the ~10 days it's available has kinda taken its toll on what I'd do with this at the moment. But... here's an example of what goes into the exe editing part of this process, if anyone's interested in the technical side of things.
Here's the subroutine that gets the animation data for a given weapon in pre-supplemental update PSU (so the US/EU online and all offline versions):
- Code: Select all
004E81E0 - 0FB6 48 01 - movzx ecx,byte ptr [eax+01]
004E81E4 - 0FB6 50 02 - movzx edx,byte ptr [eax+02]
004E81E8 - 53 - push ebx
004E81E9 - 56 - push esi
004E81EA - 0FB6 70 03 - movzx esi,byte ptr [eax+03]
004E81EE - 0FB6 00 - movzx eax,byte ptr [eax]
004E81F1 - 57 - push edi
004E81F2 - 8B F9 - mov edi,ecx
004E81F4 - C1 E7 08 - shl edi,08
004E81F7 - 0B FA - or edi,edx
004E81F9 - C1 E7 08 - shl edi,08
004E81FC - 0B FE - or edi,esi
004E81FE - 8B D8 - mov ebx,eax
004E8200 - 83 E3 01 - and ebx,01
004E8203 - 81 E7 00001A01 - and edi,011A0000
004E8209 - C1 E3 18 - shl ebx,18
004E820C - 0B FB - or edi,ebx
004E820E - 81 FF 00001A01 - cmp edi,011A0000
004E8214 - 75 09 - jne 004E821F
004E8216 - 5F - pop edi
004E8217 - 5E - pop esi
004E8218 - B8 0C1E8B00 - mov eax,008B1E0C : [00000000]
004E821D - 5B - pop ebx
004E821E - C3 - ret
004E821F - C1 E0 08 - shl eax,08
004E8222 - 0B C1 - or eax,ecx
004E8224 - C1 E0 08 - shl eax,08
004E8227 - 0B C2 - or eax,edx
004E8229 - C1 E0 08 - shl eax,08
004E822C - 0B C6 - or eax,esi
004E822E - 8B C8 - mov ecx,eax
004E8230 - B8 B87A8800 - mov eax,00887AB8 : [010B0503]
004E8235 - 39 08 - cmp [eax],ecx
004E8237 - 74 0C - je 004E8245
004E8239 - 83 C0 08 - add eax,08
004E823C - 3D 807B8800 - cmp eax,00887B80 : [0000006B]
004E8241 - 72 F2 - jb 004E8235
004E8243 - 33 C0 - xor eax,eax
004E8245 - 5F - pop edi
004E8246 - 5E - pop esi
004E8247 - 5B - pop ebx
004E8248 - C3 - ret
Translated very roughly into something resembling C (because I'm out of practice with it, ha):
- Code: Select all
int get_index(/*struct*/ weapon* current_weapon) // "weapon" structure is an inventory weapon.
{
int cmp_madoog = (current_weapon->weapon_category << 16) | (current_weapon->weapon_index << 8);
cmp_madoog = cmp_madoog & 0x011A0000;
cmp_madoog = cmp_madoog | (current_weapon->item_category << 24);
if(cmp_madoog == 0x011A0000) //Realistically, these last four lines were one statement, either HORRIFIC coding practices or a compiler optimization.
return (madoog_anim_data);
int weapon_number = (current_weapon->item_category << 24) | (current_weapon->weapon_category << 16) | (current_weapon->weapon_index << 8) | (current_weapon->manufacturer);
/*struct*/ anim_data* list_entry = anim_list; //Where "anim_list" is an array of anim_data.
while(list_entry < anim_list_end)
{
if(list_entry->weapon_number == weapon_number)
return list_entry; //Returns the current list entry because it found what it wanted.
}
return standard_anim; //Used for stuff like Rappy daggers.
}
Here's the current version of the same:
- Code: Select all
004F0F90 - 8A 08 - mov cl,[eax]
004F0F92 - 80 F9 1A - cmp cl,1A
004F0F95 - 75 06 - jne 004F0F9D
004F0F97 - B8 98CD8C00 - mov eax,008CCD98 : [00000000]
004F0F9C - C3 - ret
004F0F9D - 0FBE 50 02 - movsx edx,byte ptr [eax+02]
004F0FA1 - 0FBE 40 01 - movsx eax,byte ptr [eax+01]
004F0FA5 - 0FBE C9 - movsx ecx,cl
004F0FA8 - 81 C9 00010000 - or ecx,00000100
004F0FAE - C1 E1 08 - shl ecx,08
004F0FB1 - 0B CA - or ecx,edx
004F0FB3 - C1 E1 08 - shl ecx,08
004F0FB6 - 0B C8 - or ecx,eax
004F0FB8 - B8 B8EF8900 - mov eax,0089EFB8 : [010B0903]
004F0FBD - 8D 49 00 - lea ecx,[ecx+00]
004F0FC0 - 39 08 - cmp [eax],ecx
004F0FC2 - 74 0C - je 004F0FD0
004F0FC4 - 83 C0 0C - add eax,0C
004F0FC7 - 3D F0F68900 - cmp eax,0089F6F0 : [00010000]
004F0FCC - 72 F2 - jb 004F0FC0
004F0FCE - 33 C0 - xor eax,eax
004F0FD0 - C3 - ret
If you notice nothing else, notice that it's
only two-thirds as long.
For reference, this is what it'd be in C(...ish):
- Code: Select all
int get_index(weapon_model_num* current_weapon)
{
if(current_weapon->weapon_category == 26)
return (madoog_anim_data);
int weapon_number = 1 << 24 | (current_weapon->weapon_category << 16) | (current_weapon->weapon_index << 8) | (current_weapon->manufacturer);
/*struct*/ anim_data* list_entry = anim_list; //Where "anim_list" is an array of anim_data.
while(list_entry < anim_list_end)
{
if(list_entry->weapon_number == weapon_number)
return list_entry; //Returns the current list entry because it found what it wanted.
}
return standard_anim; //Used for stuff like Rappy daggers.
}
Now, there's a few things here:
1. The current version takes a _model_ number, not a weapon number. If you remember on EGS public test back in the beginning, when you used the machinegun in certain situations, it would use the Germinus Gun model but would constantly be playing the "expand" animation, unless you modified its item number to be the Germinus Gun one. This is fixed on the Japanese version (meaning they wouldn't need to do an exe update in order to add for instance Demolition Comet+).
2. Replaced the horribly inefficient (I say "horribly" despite that it's all of probably about 20 cycles wasted on a fairly uncommon basis) madoog check (all those bitshifts use cycles, and including a value only to set it to 0 one instruction later is wasteful) with a quicker and simpler one.
3. They're ignoring the first byte of the item/model number now. Saves a register (meaning another two instructions saving/restoring its value).
4. They changed the animation format a bit (the old version was 8 bytes per entry, the new one's 12).
So, with all that in mind, the new subroutine I wrote (with various values not filled in yet) is as follows:
- Code: Select all
004E81E0 - 0FB6 48 01 - movzx ecx,byte ptr [eax+01]
004E81E4 - 80 F9 1A - cmp cl,1A
004E81E7 - 75 06 - jne 004E81EF
004E81E9 - B8 0C1E8B00 - mov eax,008B1E0C : [00000000]
004E81EE - C3 - ret
004E81EF - A1 6C33D500 - mov eax,[00D5336C] : [00000000]
004E81F4 - 8B 80 0C010000 - mov eax,[eax+0000010C]
004E81FA - 05 EA000000 - add eax,000000EA
004E81FF - 90 - nop
004E8200 - 0FB6 50 10 - movzx edx,byte ptr [eax+10]
004E8204 - 0FB6 40 01 - movzx eax,byte ptr [eax+01]
004E8208 - 81 C9 00010000 - or ecx,00000100
004E820E - C1 E1 08 - shl ecx,08
004E8211 - 09 D1 - or ecx,edx
004E8213 - C1 E1 08 - shl ecx,08
004E8216 - 09 C1 - or ecx,eax
004E8218 - B8 B87A8800 - mov eax,00887AB8 : [010B0503]
004E821D - 39 08 - cmp [eax],ecx
004E821F - 74 0C - je 004E822D
004E8221 - 83 C0 08 - add eax,08
004E8224 - 3D 807B8800 - cmp eax,00887B80 : [0000006B]
004E8229 - 72 F2 - jb 004E821D
004E822B - 31 C0 - xor eax,eax
004E822D - C3 - ret
This new subroutine manages to find the model number in memory (it's not even stored in the structure passed to the subroutine), then find the index, and still save 27 bytes and multiple registers compared to the old version (not that I'd know what to do with them, ha). It means that if I copy the current animation data over, I just need to find empty space and correct a few values (the pointer and the length of the entry), then... make the actual animation handler use it properly, ha.
It'd have to be repointed, anyway, there's nowhere near enough space to fit something like 30 extra animated weapons in the space it's stored in now even if I kept the format the same. I don't intend to have extra weapons reusing previous models unless a given weapon type ends up sorely underrepresented, but it's good to have the infrastructure in place juuuuust in case it becomes important in the future.
If there's interest, I can do more of these. I like being able to talk about what I do (information makes the world go 'round!), just... don't see a purpose in wasting the space if nobody cares.