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 - JWP

Pages: [1] 2 3 ... 8
1
A lot of the camera animations are read using this, I'm not sure if it also applies to the field camera:
http://forums.qhimm.com/index.php?topic=15906.msg261844#msg261844
might help with some of the structure analysis.

2
Seems fine to me.
Code: [Select]
default for Squall:
_HP[0] = 44
_HP[1] = 255
_HP[2] = 179
((magic_J_val * magic_count + stat_bonus + lvl * _HP[0] - (10 * lvl ^ 2) / _HP[1] + _HP[2]) * percent_mod) / 100;
part1 = magic_J_val * magic_count + stat_bonus = 0
part2 = lvl * _HP[0] = 8 * 44 = 352
part3 = (10 * lvl ^ 2) / _HP[1] = (10 * 64)/255 = 640/255 = 2 (truncated because of integer arithmetic)
percent_mod = 100
((0 + 352 - 2 + 179)*100)/100 = 529

3
I can tell you that the game uses integers and there's a little more info here: http://forums.qhimm.com/index.php?topic=16923.msg240609#msg240609

I can take another look when I get some time.

4
Sure, here you go:
Code: [Select]
0x483D67 - does the lookup
from: 8D 0C C5 00 00 00 00 BA 20 00 00 00 2B C8 B3 40 8D 34 88 C1 E6 04 81 C6 00 F0 CF 01 33 FF 8D 8E 82
to:   E8 B4 B2 00 00 25 FF 00 00 00 31 DB 31 C9 31 D2 8A 9A 88 3D 48 00 01 D9 42 39 C1 7E F3 B3 40 EB 70

0x483D88 - spell table
from:
00 00 00 8A 01 84 C0 74 11 25
FF 00 00 00 6B C0 3C 84 98 6E
40 CF 01 74 01 47 83 C1 05 4A
75 E3 85 FF 75 07 B8 FF 00 00
00 EB 47 E8 68 B2 00 00 25 FF
00 00 00 8B C8 81
to:
00 00 0B 00 00 0B 00 00 0A 06
00 06 06 30 30 10 20 20 12 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 06 00 00 00 06 00
00 00 00 00 00 00

0x483DC0 - tests for angel wing and skips inventory check if true
from: E1 1F 00 00 80 79 05 49 83 C9 E0 41 8D 54 8E 68 8A 44 11 1A 84 C0 74 10 25 FF 00 00 00 6B C0 3C
to:   05 82 F0 CF 01 8D 2C 52 8D 2C AA C1 E5 04 F6 85 1B 7B D2 01 02 0f 85 65 9A 00 00 E9 27 9A 00 00

0x48D802 - jumps to angel wing test from start of inventory check
from: 05 82 F0 CF 01
to:   E9 B9 65 FF FF

You'll likely run into an issue with the memory offset for the lookup table in the code being wrong (the "88 3D 48 00" bytes in the first section), I think the rest is relative, so you might be all right with the jumps.

5
I think it's using Level instead of stock; so to get the full stat boost from a junctioned spell the character needs to be lv.100.
Correct, normally the boost is (magic_amount * stat_boost)/100 but the patches just cause it to use level instead of the magic amount.

6
As far as I'm aware, no. The most reliable source is: https://gamefaqs.gamespot.com/ps/197343-final-fantasy-viii/faqs/58936 as it looks like it was compiled from reverse engineering.
I'd probably give Rinoa a 1/256 chance of casting "The End" for entertainment :P.

7
Good idea but it didn't seem to work.
Selphie's slots uses attack type 0x10 instead of 0x02 (Magic), I tried changing the attack type and it cast the spell successfully but it soft locked after it finished :(.
You can change the numbers but just make sure they add up to 256 or there's a chance that the game could load an invalid spell.

Also you don't actually need that jump patch since the condition is never true anyway.

If you're curious, the patched code looks like this:

Code: [Select]
00483D67 | E8 B4B20000              | call <ff8_en.battle_random_number>                              | eax = random number [0..255]
00483D6C | 25 FF000000              | and eax,FF                                                      |
00483D71 | 31DB                     | xor ebx,ebx                                                     | ebx = 0
00483D73 | 31C9                     | xor ecx,ecx                                                     | ecx = 0 - used to store running total
00483D75 | 31D2                     | xor edx,edx                                                     | edx = 0 - used to store magic id
label:
00483D77 | 8A9A 883D4800            | mov bl,byte ptr ds:[edx+483D88]                                 | load byte from table to bl (ebx)
00483D7D | 01D9                     | add ecx,ebx                                                     | add byte from table to running total
00483D7F | 42                       | inc edx                                                         |
00483D80 | 39C1                     | cmp ecx,eax                                                     |
00483D82 | 7E F3                    | jle ff8_en.483D77                                               | jump to label if total <= random number
00483D84 | B3 40                    | mov bl,40                                                       | bl is used later to test targeting
00483D86 | EB 70                    | jmp ff8_en.483DF8                                               | jump past table to resume testing targeting stuff

IMPORTANT NOTE: there might be a bug where the total doesn't get to 256 because it's adding to dl rather than (e)dx, I'll have to investigate it.
EDIT: I've fixed the patch in the previous post - the spell table also had to move
EDIT1: Proper test for angel wing has been added to skip the inventory check - see previous post.

8
From your post, it looks like you want the following weightings:
Code: [Select]
Firaga - 11
Blizzaga - 11
Thundaga - 10
Water - 6
Bio - 6
Pain - 6
Meltdown - 6
Demi - 6
Tornado - 32
Quake - 32
Flare - 48
Holy - 48
Meteor - 16
Ultima - 18

here is a patch that should do the trick:
Code: [Select]
0x483D67 - does the lookup
E8 B4 B2 00 00 25 FF 00 00 00 31 DB 31 C9 31 D2 8A 9A 88 3D 48 00 01 D9 42 39 C1 7E F3 B3 40 EB 70

0x483D88 - spell table
00 00 0B 00 00 0B 00 00 0A 06
00 06 06 30 30 10 20 20 12 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 06 00 00 00 06 00
00 00 00 00 00 00

0x483DC0 - tests for angel wing and skips inventory check if true
05 82 F0 CF 01 8D 2C 52 8D 2C AA C1 E5 04 F6 85 1B 7B D2 01 02 0f 85 65 9A 00 00 E9 27 9A 00 00

0x48D802 - jumps to angel wing test from start of inventory check
E9 B9 65 FF FF

not 100% sure I got the table right but give it a shot.

9
Hmm... so I've managed to get a patch table working as expected, the only problem is that if Rinoa doesn't have the spell in stock, she jumps forward and the spell name appears but nothing is cast.
There must be some sort of other check elsewhere :(.

EDIT:
found where it is and did a hacky patch but I'm not sure the best way to fix it.

10
I'm not sure where these other places are getting the probabilities from but I see no indication of any magic specific weighting.
The function counts the number of valid magics and if it's not zero, it generates a random number between 0 and 31.
It then selects the magic in this slot, if there is no magic in this slot or the targeting isn't valid, it keeps selecting the next slot until it finds a valid one (and loops around).
This means that if you have a lot of empty magic slots at the end, the first slot ends up being more likely than the others.

It would be possible to create a table of weights for each of the magics but you would either have to make sure that the sum of the weights are <=256 or use a different way of generating random numbers than the one usually used in the battle module.

Easiest way would probably be to make the weights for the 56 spells listed here: https://github.com/alexfilth/doomtrain/wiki/Magic-data
total 256 since it would mean you wouldn't have to worry about evening the outcomes and I could probably whip a patch up if you came up with a table.

11
The spell used under Angel Wing is decided in function 0x483D60.

12
If you want them based on level, the following patches should do the trick:

Code: [Select]
#HP
963CB = 8A 5C 24 14 90 90 90

#Primary Stats
966E5 = 8A 54 24 1C 90 90 90

#Speed & Luck
96788 = 8A 54 24 1C 90 90 90

#Hit
9688E = 8B 4C 24 04 31 C0 8A 81 B8 01 00 00

#EVA
9691C = 8B 4C 24 04 31 C0 8A 81 B8 01 00 00

#Elemental Attack
969CC = 8B 4C 24 04 31 C0 8A 81 B8 01 00 00

#Elemental Defence
96AA9 = 8B 44 24 04 31 C9 8A 88 B8 01 00 00

#Status Attack
96BBC = 8B 4C 24 04 31 C0 8A 81 B8 01 00 00

#Status Defence
96C98 = 8B 44 24 04 31 C9 8A 88 B8 01 00 00

13
FF8 Tools / Re: [PSX/PC] Field editor - Deling (0.9.1b)
« on: 2019-03-04 10:07:38 »
The dialog for the characters in battle is in a different set of files (.dat files) and there isn't currently a tool to edit them as far as I'm aware.
I'm currently modifying Ifrit to be able to edit them along with the battle AI.

14
What I said seems to match up to the position data stuff, I haven't looked deep enough into it yet to comment about the other stuff.

15
Is there any more information anywhere on the DAT animation data?

What I've figured out so far is as follows:
The first byte is the number of frames as shown on the wiki.
The main function that reads the dat animation data looks to be at 0x00508F90.
There's a fixed array at 0xB8B9F0 of 4 bytes to help with uncompressing bits.
byte[] uncompress_helper = { 0x03, 0x06, 0x09, 0x10 }
There are 2 types of reads that are done on the animation data, bit reads and compressed bit reads.

there's a structure in memory used to parse the data that looks like:
struct animatonReadHelper {
    BYTE* current_animation_byte;
    int current_bit_position;
}

for bit reads, the following takes place:
int temp = *(current_position + 2) << 12 | *(current_position + 1) << 8 | *current_position //essentially reads 3 bytes in little-endian format
short value = (temp >> current_bit_position) & ~(0xFFFFFFFF << bitsToRead)
value = (value << (16 - bitsToRead)) >> bitsToRead //This looks odd but it's done as an arithmetic right shift to sign extend the bits

current_animation_byte += (bitsToRead + current_bit_position) / 8 // increases pointer by number of bytes read
current_bit_position = (bitsToRead + current_bit_position) % 8 // sets the position in the next byte to read from

For reading compressed bits, the following happens:
2 bits are read and this is used as an index with the fixed array above i.e.
0 -> 0x03
1 -> 0x06
2 -> 0x09
3 -> 0x10

Then this amount of bits are read and sign extended as above.
The function for compressed bit reads is at 0x00509320
The function for standard bit reads is at 0x005092A0
All offsets are for the English Steam version

16
The structure that the camera animation is loaded into looks like:
Code: [Select]
struct CameraStruct {
BYTE unkbyte000; //000
BYTE unkbyte001; //001 keyframe count?
WORD control_word; //002
WORD unkword004; //004
WORD unkword006; //006
WORD unkword008; //008
WORD unkword00A; //00A
WORD unkword00C; //00C
WORD unkword00E; //00E total frame count/time?
BYTE unk[20] //010
short unkword024[32]; //024 - start frames for each key frame?
short unkword064[32]; //064
short unkword0A4[32]; //0A4
short unkword0E4[32]; //0E4
BYTE unkbyte124[32]; //124
short unkword144[32]; //144
short unkword184[32]; //184
short unkword1C4[32]; //1C4
BYTE unkbyte204[32]; //204
BYTE unkbyte224[128]; //224
BYTE unkbyte2A4[128]; //2A4
BYTE unkbyte324[128]; //324
BYTE unkbyte3A4[128]; //3A4
BYTE unkbyte424[128]; //424
BYTE unkbyte4A4[128]; //4A4
};
and the function that parses the animation into it looks something like:
Code: [Select]
short* parse_camera(short* camera_data, CameraStruct* cam) {
short* local2C;
BYTE keyframecount;
WORD totalframecount;
short* local1C;
short* local18;
short* local14;
short* local10;

short* current_position = camera_data;
if (*current_position == 0xFFFF) {
return NULL;
}

cam->control_word = *current_position;

current_position++;
totalframecount = 0;
keyframecount = 0;
switch ((cam->control_word >> 6) & 3) {
case 1:
cam->unkword004 = 0x200;
cam->unkword006 = 0x200;
break;
case 2:
cam->unkword004 = *current_position;
cam->unkword006 = *current_position;
current_position++;
break;
case 3:
cam->unkword004 = *current_position++;
cam->unkword006 = *current_position++;
break;
}

switch ((cam->control_word >> 8) & 3) {
case 0:
cam->unkword008 = ff8vars.unkword1D977A2;
cam->unkword00A = ff8vars.unkword1D977A2;
break;
case 1:
cam->unkword008 = 0;
cam->unkword00A = 0;
break;
case 2:
cam->unkword008 = *current_position;
cam->unkword00A = *current_position;
current_position++;
break;
case 3:
cam->unkword008 = *current_position++;
cam->unkword00A = *current_position++;
break;
}

switch (cam->control_word & 1) {
case 0:
if (*current_position >= 0) {
do {
cam->unkword024[keyframecount] = totalframecount;
totalframecount += *current_position++ * 16;
cam->unkbyte124[keyframecount] = *current_position++;
cam->unkword064[keyframecount] = *current_position++;
cam->unkword0A4[keyframecount] = *current_position++;
cam->unkword0E4[keyframecount] = *current_position++;
cam->unkbyte204[keyframecount] = *current_position++;
cam->unkword144[keyframecount] = *current_position++;
cam->unkword184[keyframecount] = *current_position++;
cam->unkword1C4[keyframecount] = *current_position++;
keyframecount++;
} while (*current_position >= 0);

if (keyframecount > 2) {
ff8funcs.Sub50D010(cam->unkword024, cam->unkword064, cam->unkword0A4, cam->unkword0E4, keyframecount, cam->unkbyte224, cam->unkbyte2A4, cam->unkbyte324);
ff8funcs.Sub50D010(cam->unkword024, cam->unkword144, cam->unkword184, cam->unkword1C4, keyframecount, cam->unkbyte3A4, cam->unkbyte424, cam->unkbyte4A4);
}
}
break;
case 1:
if (*current_position >= 0) {
local14 = current_position + 5;
local10 = current_position + 6;
local2C = current_position + 7;
local18 = current_position + 1;
local1C = current_position + 2;
short* ebx = current_position + 3;
do {
cam->unkword024[keyframecount] = totalframecount;
totalframecount += *current_position++ * 16;
ff8funcs.Sub503AE0(++local18, ++local1C, ++ebx, *(BYTE*)current_position, &cam->unkword064[keyframecount], &cam->unkword0A4[keyframecount], &cam->unkword0E4[keyframecount]);
ff8funcs.Sub503AE0(++local14, ++local10, ++local2C, *(BYTE*)(current_position + 4), &cam->unkword144[keyframecount], &cam->unkword184[keyframecount], &cam->unkword1C4[keyframecount]);
cam->unkbyte204[keyframecount] = 0xFB;
cam->unkbyte124[keyframecount] = 0xFB;
local1C += 8;
local18 += 8;
current_position += 8;
local2C += 8;
ebx += 8;
local10 += 8;
local14 += 8;
keyframecount++;
} while (*current_position >= 0);

if (keyframecount > 2) {
ff8funcs.Sub50D010(cam->unkword024, cam->unkword064, cam->unkword0A4, cam->unkword0E4, keyframecount, cam->unkbyte224, cam->unkbyte2A4, cam->unkbyte324);
ff8funcs.Sub50D010(cam->unkword024, cam->unkword144, cam->unkword184, cam->unkword1C4, keyframecount, cam->unkbyte3A4, cam->unkbyte424, cam->unkbyte4A4);
}
}
break;
}

if ((cam->control_word & 0x3E) == 0x1E) {
ff8funcs.Sub503300();
}

cam->unkbyte001 = keyframecount;
cam->unkword00E = totalframecount;
cam->unkword00C = 0;
return current_position + 1;
}

note: adding to a word pointer adds 2 to the value.
The size of the animation depends a lot on the control word and the amount of keyframes.
I haven't verified the code completely but it should be roughly correct with some possible minor errors.

17
Gameplay Modding / Re: [FFVIII-PCSteam] Enemy AI?
« on: 2018-08-10 17:11:27 »
There's a beta version of Ifrit that has been modified to make it possible to view/edit AI but note that it is pretty buggy at present.
see here

18
Heh, I really need to get around to fixing it but the whole AI section really needs a rewrite =/.

19
I believe the names are also in kernel.bin but you need a different tool to edit them:
Carbuncle

20
Already learned abilities are stored in the save data and there is a file in partial save game format that is initially loaded when you start a new game (init.out), you would need to edit this file to change it for new games (see this thread) and your current save if is for an existing game (using Hyne for example).
Shuffling the abilities up (so the 2 last ones are blank instead) may fix the odd black skill problem but that's just a guess.

21
It could also be to do with the constant array of files embedded in the exe:
http://wiki.ffrtt.ru/index.php/FF8/Engine_const/BattleFiles

22
Should be easy enough to do if you know how to work with ff8.

The following patches in memory would do it for the English Steam version for stats other than hit or eva:

Code: [Select]
Address: 0x004966E5
From:    8A 14 4D F9 E0 CF 01
To:      8A 54 24 1C 90 90 90

Code: [Select]
Address: 0x00496788
From:    8A 14 4D F9 E0 CF 01
To:      8A 54 24 1C 90 90 90

Code: [Select]
Address: 0x004963CB
From:    8A 1C 45 F9 E0 CF 01
To:      8A 5C 24 14 90 90 90

The way this works is that the following functions:
Code: [Select]
0x496310: GetCharacterHP (int lvl, int char_id)
0x496440: GetCharacterStat (int lvl, int char_id, int stat)

are called with the character level as a parameter and it's easy to pull this off the stack when it tries to get the value for the junctioned magic amount.

Hit and Eva are calculated in the following functions:
Code: [Select]
0x4967C0: GetCharacterHit (int char_id)
0x4968A0: GetCharacterEva (int char_id, int unk1)

it's probably possible to change these too but it's more work than I'm willing to do.

23
Gameplay Modding / Re: FF VIII How to MOD?
« on: 2017-10-29 19:29:45 »
I updated the file without changing the filename or version numbers.

24
Gameplay Modding / Re: FF VIII How to MOD?
« on: 2017-10-29 18:28:24 »
Are you using the fixed version of Ifrit above?

25
Gameplay Modding / Re: FF VIII How to MOD?
« on: 2017-10-23 21:43:12 »
that particular error was because it was gfStolen, rather than gfstolen.

Pages: [1] 2 3 ... 8