[FF8] Engine reverse engineering

  • Thread starter Thread starter Halfer
  • Start date Start date
Status
Not open for further replies.
Hehe, looks nice! Now you can deal all of the damage in the world :D

Update to the Monster structure:
Note, the offsets listed are for the first struct in the array, they are usually referenced with address + (208*monster_id) - the unknown padding is mostly in sizes of 8 so it's easy to replace it when I find out what some values are.
Code: [Select]
Code:
//0x1D27B10#pragma pack(push, 1)struct Character{ BYTE **monster_info; //0x1D27B10 - could just be used for the name but points to section 7 of a loaded dat file BYTE unk[8]; //0x1D27B14 BYTE status; //0x1D27B1C - MSB - reflect / shell / protect / regen / stop / slow / haste / ? - LSB BYTE unk1[3]; //0x1D27B1D DWORD unkdword1D27B20; //0x1D27B20 - used in opcode 0x24 DWORD unkdword1D27B24; //0x1D27B24 - used in opcode 0x24 DWORD currentHP; //0x1D27B28 DWORD maxHP; //0x1D27B2C BYTE unk2_0[4]; //0x1D27B30 DWORD localVars[8]; //0x1D27B34 - DC to E3 - base address used is 0x1D277C4 WORD unkwordarr1D27B54[6]; //0x1D27B54 at least 6 items, changed by opcode 2D BYTE unk3_0[4]; //0x1D27B60 WORD unkword1D27B64[16]; //0x1D27B64 DWORD unkdword1D27B84[3]; //0x1D27B84 BYTE status1; //0x1D27B90 MSB - ? / zombie / berserk / ? / ? / ? / ? / ? - LSB BYTE unk4[7]; //0x1D27B91 BYTE lastAttacker; //0x1D27B98 - used in opcode 0x0E case 0xCB - 0, 1 or 2 for SeeD 3+ for monsters BYTE unk5_0[7]; //0x1D27B99 - this whole section of unknowns looks to be status resistances BYTE unk5_1[8]; //0x1D27BA0 BYTE unk5_2[8]; //0x1D27BA8 BYTE unk5_3[8]; //0x1D27BB0 BYTE unk5_4[8]; //0x1D27BB8 BYTE unk5_5[8]; //0x1D27BC0 BYTE unkbyte1D27BC8; //0x1D27BC8 used in case 0x2A BYTE unk6[3]; //0x1D27BC9 BYTE lvl; //0x1D27BCB BYTE str; //0x1D27BCC BYTE vit; //0x1D27BCD BYTE mag; //0x1D27BCE BYTE spr; //0x1D27BCF BYTE spd; //0x1D27BD0 BYTE luck; //0x1D27BD1 BYTE eva; //0x1D27BD2 BYTE unk7[12];};#pragma pack(pop)
I'd imagine that the struct above is referenced all over the battle code, so I'm trying to decipher as much of it as I can so that understanding what other battle functions do will be a lot easier.
I've found that generally the ID of the monsters is 3, 4 and 5 (no idea what happens with 8 monster battles yet), so the first monster you fight will have its parameters at 0x1D27D80 rather than 0x1D27B10. It looks like it stores most of the parameters for the monsters that you're fighting, all I need now is to finish decoding it :D.
There's a bunch of interesting things I didn't know about the AI code, you have to be careful with some opcodes because you can override bits of memory that you shouldn't - which could lead to some random crashes.
opcode 0x0E is used to set a variable as mentioned by random_npc, there's a special case where the immediate is 0xCB which causes the variable to be assigned the value of last attacker instead of the immediate - it appears that 0xCB is treated as a special case in quite a few opcodes.
After further investigation, it seems there are 2 sets of variables DC-E3 (which are stored in the struct above) and 60-67 (which are stored separately - I assume these are global for the battle).
It looks like bad things would happen if you used opcode 0x0E to write outside the range DC-E3 but there's no constraint checking!

The 71 byte structure I mentioned before contains a series of multipliers for stats (str, mag etc.) which default to 10 (1x multiplier) among some other things that I haven't identified.

Notes on opcode 0x04 - Targeting:
the final form of this in the function is a bit mask to represent which enemies are targeted, looking at the code I can see the following:
0xC8: 0000 0000 0000 1000 //self (it just shifts 1 left by the monster id - this represents and id of 3)
0xC9: //random enemy - probably one of the first 3 bits is set
0xCA: //??
0xCB: //last attacker - does 1 << the value in it's struct (see struct above)
0xCC: 1000 0000 0000 0111 //all enemies
0xCD: 1000 0000 1111 1000 //all allies
0xCE: 1000 0000 1111 1111 //everyone?
0xCF: //random ally
0xD0: 1010 0000 0000 0111 //something to do with enemies
0xD1: //?? does 1 << the value in 0x1D28DFB
0xDC-0xE3: //does 1 << the value in the corresponding variable
 
Last edited:
Thanks JWP for your contribution! <3

Okay. This one is cool! :3
I documented wm2field.tbl file.
http://wiki.qhimm.com/view/FF8/Main_wm2
There are 72 warp points on the world map (Sic!). It's not possible, so I tested it a bit and copied Balamb warp to 72 entry in wm2field.tbl
I was warped to world map screen. It looks like forgotten debug field (it's not accesible from debug room btw). See here:
debug.jpg

BTW> What's wrong with Quistis hair?

EDIT: You are warped to unavailable places on field. For Example you can run over rescue pod...

UPDATE2: http://wiki.qhimm.com/view/FF8/FileFormat_b0wave is now fully documented
 
Last edited:
Battle stages milestone:
I really couldn't believe it at first. Many weeks of thinking over it and I made a theory, that paths to every battle stage are hardcoded in EXE. NOW I CAN PROVE IT!

1. 0050E3C0 is a giant switch with... 163 cases. Guess how many battle stages we have? 163.
2. Every switch points to OWN INDEPENDENT function that... guess what? Adds to location of battle stage needed value to point to camera data. This means, that there are >>163<< functions, that every just adds different number. So, we have 163 functions less to reverse. :3
3. Every independent level function has those +0x5D4 or 0x5D8  ADD and also logic AND to convert variable to uint8.

Having all the BattleStage parsing functions I'll be able to move on with the re-parser software to convert 3D models into FF8 Battle stages (I was stuck because of those hardcoded pointers).
I still don't know if it's possible to put more detailed battle stages without touching the engine. I found also TIM texture pointer, but haven't inspected if it also have hardcoded pointers yet.

OMG... It also have additional pointers...
EDIT3: WHAT THE ACTUAL F... It has MAJORITY of predefined data for EVERY stage... Even some sort of freaking hidden TIM files for battle stage 03 and 06:  b00300.tim ...

There's 95% probability, that the data before camera is indeed unused. Dear Square, what's the purpouse of using pointers inside camera data, if you just jump to geometry section via hardcoded numbers? :O

What is "BDlinkTask"? The only result for this is my ASCII rip on Pastebin. xD

EDIT4: If they did it all in own functions, then my theory that every GF has it's own function is true, just needs to be proven.

EDIT5: Renzokuken magic ID is 336; Witch spawn magic ID is 208

EDIT6: Stage 137 (Witch stage at time compression) has a check for 01D98B64 (I called this BS_EffectState). If it's equal 8, then anything goes normal. If not, then the code for stage deformation is called. (The function double checks if the state is not normal and to be sure if it's exact 2. Then deformation applies. If you change it to 8, then deformation is stopped. You can toogle it. Spawning and changing levels is called by magic (as stated by some user here, forgot who... ;c)

01D98B60 operates the speed of sky rotation.
 
Last edited:
Nice work! That seems like a crazy amount of functions o_0

Here's my latest information on the battle stuff:
Code: [Select]
Code:
struct Character{ BYTE **infoSection; //0x1D27B10 - points to section 7 of a loaded dat file - NULL for SeeDs BYTE **aiSection; //0x1D27B14 -  NULL for SeeDs DWORD status1D27B18; //0x1D27B18 0x27 BYTE status; //0x1D27B1C - MSB - reflect / shell / protect / regen / stop / slow / haste / sleep - LSB BYTE unk1[3]; //0x1D27B1D DWORD ATBmax; //0x1D27B20 DWORD ATBcur; //0x1D27B24 DWORD currentHP; //0x1D27B28 DWORD maxHP; //0x1D27B2C BYTE unk2_0[4]; //0x1D27B30 DWORD localVars[8]; //0x1D27B34 - DC to E3 - base address used is 0x1D277C4 WORD elemRes[8]; //0x1D27B54 - 500 = very weak, 800 = normal, 1000 = fully absorb - 0. Fire, 1. Ice, 2. Thunder, 3. Earth, 4. Poison, 5. Wind, 6. Water, 7. Holy WORD timers[16]; //0x1D27B64 - status timers DWORD unkdword1D27B84; //0x1D27B84 DWORD unkdword1D27B88; //0x1D27B88 DWORD unkdword1D27B8C; //0x1D27B8C - edited by function 0x48C5C0 WORD status1; //0x1D27B90 MSB - ? / zombie / berserk / silence / blind / petrify / ? / death - LSB WORD unkword1D27B92; //0x1D27B92 WORD unkword1D27B94; //0x1D27B94 ????? 0x2E, 0x29, 0x06,  WORD unkword1D27B96; //0x1D27B96 ????? BYTE lastAttacker; //0x1D27B98 - used in opcode 0x0E case 0xCB BYTE unk5_0[7]; //0x1D27B99 BYTE mentalRes[40]; //0x1D27BA0 - Mental resistances - 0. Death, 1. Poison, 2. Petrify, 3. Darkness, 4. Silence, 5. Berserk, 6. Zombie, 8. Sleep, 9. Haste, 10. Slow, 11. Stop, 12. Regen, 15. Reflect, 18. Doom, 20. Petrifying, 21. Float, 22. Confuse, 23. Drain, 24. Expulsion, rest are always 100 for monsters BYTE unkbyte1D27BC8; //0x1D27BC8 used in case 0x2A  - edited by function 0x48C5C0 BYTE unkbyte1D27BC9; //0x1D27BC9 - edited by function 0x48C5C0 BYTE unkbyte1D27BCA; //0x1D27BCA BYTE unkbyte1D27BCB; //0x1D27BCB - edited by function 0x48C5C0 BYTE lvl; //0x1D27BCC BYTE str; //0x1D27BCD BYTE vit; //0x1D27BCE BYTE mag; //0x1D27BCF BYTE spr; //0x1D27BD0 BYTE spd; //0x1D27BD1 BYTE luck; //0x1D27BD2 BYTE eva; //0x1D27BD3 BYTE hit; //0x1D27BD4 BYTE unk7[5]; //0x1D27BD5 BYTE crisisLevel; //0x1D27BDA BYTE unkbyte1D27BDB; //0x1D27BDB WORD unkword1D27BDC; //0x1D27BDC BYTE unk8[2]; //0x1D27BDE};
vars 60-67:
Code: [Select]
Code:
DWORD * const vars = (DWORD*)0x1D28D98; //- 60 to 67 - base address used is 0x1D28C18 - array of size 8
and a few functions (note that parameter signs/sizes might not be accurate):

Code: [Select]
Code:
int(*count_valid_targets)() = (int(*)())0x4860A0; //0xFF if no valid targets - counts SeeDs that are not petrified or deadint(*getStat)(int level, BYTE *datfile, int stat) = (int(*)(int, BYTE*, int))0x48C3F0; //gets str, vit, mag, spr, spd, eva from dat fileBYTE(*get_random_number)() = (BYTE(*)())0x48F020;
EDIT: see section 2 of  http://www.gamefaqs.com/ps/197343-final-fantasy-viii/faqs/58936 for how the RNG works

the start of the AI function mentioned before goes something like this:
Code: [Select]
Code:
 if (init_done && (character_info[id].status1 & 0x20) != 0) { //if berserk  if (count_valid_targets() == 0xFF) {   target = 0; //set no target   next_ai_byte_1 = 0; //make sure to skip AI code on next loop   //00487E6B | .BE 1DA2D201   MOV ESI, OFFSET 01D2A21D   goto lbl489804; //jump to attack code in switch?  }  BYTE randomTarget;  do {   randomTarget = get_random_number() % 3;  } while (character_info[randomTarget].status1 & 0x01 != 0); //check target isn't dead  next_ai_byte_1 = 0; //make sure to skip AI code on next loop  target = 1 << randomTarget;  //00487E6B | .BE 1DA2D201   MOV ESI, OFFSET 01D2A21D  goto lbl489804; //jump to attack code in switch? }
so there are a couple of interesting things...
There appear to be 40 bytes used for status resistance stuff but only 19 are actually loaded from dat files, the rest are just set to 100 during loading... so the rest are a mystery - could be The End, Vit0, unused...
The first status byte seems to contain timed statuses, so I wonder where the timers for these are.
Also I believe opcode 0x0F is used to set global vars (60-67) and 0x0E to set local ones (DC-E3) you can write outside those variable ranges but:
a) you'll probably be writing into areas of memory that you probably shouldn't (overriding stats etc.)
b) the test opcode (0x02) will not test values outside of those ranges
opcode 0x12 is for adding to local vars.
opcode 0x13 is for adding to global vars.
opcode 0x15 also do addition of some sort but I haven't discovered what to yet.
opcode 0x24 fills the ATB gauge.
opcode 0x2D is for changing elemental resistances (e.g. 2D 00 F4 01 sets fire resistance to 500).
opcode 0x36 disables Odin and enables Gilgamesh

Expanding on what random_npc said about 02 02 being probability:
The next byte is used as a modulus and the comparison is done as normal e.g.
02 02 03 01 02 00 XX XX
is basically:
if (rand() % 3 < 2) { //should be 2/3 probability
    do stuff;
}

EDIT: realized that I screwed the padding up at some point and all the addresses were out of alignment, should be fixed now.
EDIT1: this: http://wiki.qhimm.com/view/FF8/GameSaveFormat is located at 0x1CFDC58 in memory, I noticed some checks for stuff in there in the battle code.
 
Last edited:
I'll post roughly what I said to Callisto in a PM since I can't actually read what I sent him.
in this part:
Code: [Select]
Code:
BYTE mentalRes[40]; //0x1D27BA0
offset 0x20 of that array seems to be checked when using meltdown (i.e. vit0).
So the idea behind this post is to implement a way to make some monsters vit0 resistant without getting rid of vit0 entirely.
The following code changes in the exe load the unused 20th status byte in the dat file into that position instead of it being set to 100:

!!!--- make a backup if you're going to do this ---!!!
Also make sure you check the from bytes, since I'm not sure if this will work with other versions of FF8 (I'm using the English Steam version).

FF8_EN.exe:
Code: [Select]
Code:
from: 0x8BEE8: B90A 0A0A 0Ato:   0x8BEE8: E9A8 0000 00from: 0x8BF95: 9090 9090 9090 9090to:   0x8BF95: 8A87 7B01 0000 EB77from: 0x8C014: 9090 9090 9090 9090 9090 90to:   0x8C014: 8886 C07B D201 E912 0100 00from: 0x8C131: 9090 9090 9090 9090 9090to:   0x8C131: B90A 0A0A 0AE9 B2FD FFFF
it's basically a bunch of ASM code that bounces around the place.
The problem is that the jump table doesn't go anywhere near the value needed and there's no space for code to change one status without having a knock-on effect on the others or overriding code, so I had to resort to doing crazy amounts of jumps and using the NOP space between functions.
Anyway, I tested it and it appeared to stop things getting vit0 status - if they had the 20th byte as 0xFF anyway.
It'd probably be a lot easier to do something like this in a mod with an injected DLL - since it wouldn't involve so much code jumping and it wouldn't be permanent.
You could also test it by adding 0x400000 to those addresses and editing the memory of the program.

For those interested, this is the ASM code - note that register EAX is unused until its next modification (otherwise modifying AL like I have without backing it up would have unintended consequences):
Code: [Select]
Code:
0x48BEE8: JMP 0048BF95 ; jump to unused code section...0x48BF95: MOV AL, BYTE PTR DS:[EDI+17B] ; load 20th byte into AL (EDI points to the start of section 7 of a DAT file)0x48BF9B: JMP SHORT 0048C014 ; jump to unused code section...0x48C014: MOV BYTE PTR DS:[ESI+1D27BC0],AL ; move 20th byte into the monster data in memory at the vit0 resistance point (ESI is 208 * monster_id)0x48C01A: JMP 0048C131 ; jump to unused code section...0x48C131: MOV ECX,0A0A0A0A ; do overwritten instruction0x48C136: JMP 0048BEED ; jump back to where we started
EDIT: was accidentally using the wrong byte, should be fixed now... it looks like that byte isn't usually loaded into memory at all - I screwed my numbering up when converting from hex to dec and fixed it in my previous post.
Basically it ended up using the byte before instead (info + 0x17A instead of info + 0x17B).
 
Last edited:
Amazing work JWP! Just tried this myself and it seems to work perfectly. By making these changes, it is very simple to adjust Vit 0 resistance for each enemy individually, especially in conjunction with Ifrit enemy editor. Almost like a dream becoming true.. Can finally get back to work now. Thanks a ton! :-D
 
No problem :). Btw, here's all the stuff you were after in https://www.ff7catalog.com/threads/11446/:

2. Damage formulas for Kamikaze and Darkside abilities
Kamikaze:
Code: [Select]
Code:
CPU DisasmAddress   Hex dump               Command                                      Comments00492D6C  |.  8B81 2C7BD201      MOV EAX,DWORD PTR DS:[ECX+1D27B2C]           ; EAX = caster max HP00492D72  |.  8D0480             LEA EAX,[EAX*4+EAX]                          ; EAX = EAX*5
Some sites say that the damage multiplier is 6 for kamikaze, so either it's been changed or the code for critting is elsewhere.

Darkside:
Code: [Select]
Code:
CPU DisasmAddress   Hex dump               Command                                      Comments00491069  |> \8D3476             LEA ESI,[ESI*2+ESI]                          ; ESI = ESI * 3 - darkside multiplier
3. Angel Wing damage multiplier
Code: [Select]
Code:
CPU DisasmAddress   Hex dump               Command                                      Comments00491085  |.  8D34B6             LEA ESI,[ESI*4+ESI]                          ; ESI = ESI * 5 - angel wing multiplier
6. Changing character base stats and starting level, also giving Squall, Zell and Quistis some default spells at the beginning of the game
Most of the stuff looks like it's loaded from init.out in main.fi, I'd imagine it's a similar format to sections of: http://wiki.qhimm.com/view/FF8/GameSaveFormat

Looks like init.out starts at the GF data and the character data starts at 0x440 of init.out - the level looks like it's determined by the XP (level = 1+(XP/1000)) and the magic + stats you can change too - note the stats listed in the save file are bonuses and are added to the usual level calculated stat.
The HP stat for each of the characters is set to 9999 and then capped to the max after loading - the max being calculated from the level-calculated HP + the HP bonus (I think it's HP bonus rather than the max HP that the wiki says).
The parameters for the formula that controls the level curve for each character are located in section 7 of kernel.bin, see https://www.ff7catalog.com/posts/220257/
EDIT: does anyone know where the calculation of crisis level for limit breaks is? - it'd be pretty useful for some of my investigation stuff
EDIT1: Callisto helped me find the function, it's at 0x4941F0
 
Last edited:
So much data... Nice! <3 I need to update database and wiki with this. JWP, do you have wiki account?

@topic:
I investigated the harata.cnf file. I came up with another theory.

Battle module has rich debug data code written, but it's destroyed/unusable

From the beginning: I traced all the way harata.cnf is loaded (the myserious file that looks like debug loader for battle programmer). Keep note battle is one module that has no DebugOutput strings. I didn't really find anything, it's loaded and that's kinda all. It's loaded by SmPcRead function before main menu shows along with font and namedic.bin and two hardcoded paths to Y:/work/battle/batwave.dat (Programmer loaded file independently to jumpover archive process). I tried to find the file in memory and see if there are any refferences, however I found the words that were made to recognize harata.cnf file like: 'start' 'manual' 'bdprint' 'pinch' and extreme amount of others that even harata.cnf consist. They ARE used, bad thing is their code is never used (I mean no function calls it- only jump, but it's impossible case due to battle state system overwriting update function for checking states).

Example for displaying/outputing/writing to log file (most probably) for showing current EncounterID from Scene.out:
indeks.jpg

47FCEE pushes this mysterious "SCENE " (Many of them further have the %s when pushing)
47FCF8 This is missing from final game. Did the programmer delete the "StreamToLogFile" like function? This looks like the programmer commented out the function before final release
47FD11 Puts EncounterID (01CFF8B8 ; unsigned __int16 EncounterID if you want :) )
I don't understand this though:
push    1F800000h (and I think we all won't understand, since the function is null now.... )

The scheme for above example is like this:
mov     edx, dword ptr EncounterID                -Get Encounter ID to edx (Encounter ID is uint16 !!! )
and     edx, 0FFFFh - Force EDX to be 16 bit by doing the bitwise operation
push    edx - Push EncounterID
push    1F800000h - Push mysterious something??
call    nullsub_7 - deleted output function

It's complete mess.
Any other data (that is used for writing log file) is obtained from dword_1CFFA28, the only instruction that writes it is 0047F0F9.
There's whole function for this. The function that consists jump to this unused section is: 0047EEF0
Well... the problem is it's fired, when battle state is == 4 (the only case when it's equal to 4 is BattleResultScreen). Simple? Nope. When the game goes into BattleState==4 it's automatically stopped, and the parent function reroutes the state to BattleResult screen, therefore the code for state 4 is never fired (it's no more called by update function). That way the code remain 'unused'. There's a way to force battleState = 4 by memory hacking, but the game crashes (After unlocking user from endless loop at 0047EF09) (the script also loads btitle.ovl file [this file doesn't exist])

Getting out of the loop and stepping over (to avoid instant crash, but to see all the logic) we find those variables are beign written for the first time (It's unknown size byte array):
unk_1CFFB98; unk_1D13C10; unk_1CFFBF4; unk_1D13C6C
We again get into endless loop at 0047F073 (the conditional jump to beginning of function without again testing variables makes it impossible case, till something bad happens). Let's break out of it. Finally we get into core unused sub-routine that directly manages the unused battle debug data.
The software crashes at 'mov     ds:1F800000h, edx' because 1F800000h is unallocated.

Sad...

I found this function in FFVIII Demo version. It's decompilable there. There's pseudocode fragment:
Code: [Select]
Code:
 v1F800000 = dword_CD2868 + 16496;  v1F800004 = 17;  v1F800006 = EncounterID;  v1F800008 = 1;  v1F80000C = &off_5FD158;  nullsub_7(528482304, (unsigned __int16)EncounterID_0, 0, 0);  v1F800000 = dword_CD2868 + 16496;  v1F800004 = 3;  v1F800006 = 00CFAACA + 1;  v1F800008 = v45;  v1F80000C = aTime;  nullsub_7(528482304, 0, 0, 0);  v1F800000 = dword_CD2868 + 16496;  v1F800004 = 17;  v1F800006 = 00CFAACA + 1;  v1F800008 = 1;  v1F80000C = &off_5FD164;  nullsub_7(528482304, dword_CD1944, 0, 0);  v1F800000 = dword_CD2868 + 16496;  v1F800004 = 3;  v1F800006 = 00CFAACA + 2;  v1F800008 = v46;  v1F80000C = aRate100;  nullsub_7(528482304, 0, 0, 0);
Looks now like it outputs Encounter data (only for this fragment)
Does anyone understand the 1F800000 phenomenon?
 
Last edited:
This is all artifacts of lack of whole program optimization by old (<=MSVC 6.0 C/C++) compilers. They would have used a #define to control the debug stuff, but because the compiler couldn't prove if some functions where used or not indirectly it had to leave them in.

The 1F800000 stuff is writing directly to a PSX memory address, probably another function that should have been compiled out.
 
JWP, do you have wiki account?
I'm afraid not. I'm not really sure how I would go about getting one.
I've updated the list of magic IDs to include all the function pointers (690 of them!), I'll probably add the texture names at some point if I get around to it.

EDIT: They don't all load .TIM files as I had originally thought, for example:
Code: [Select]
Code:
0x0006--0x00B58050--0x00B58080--Leviathan Summon (Tsunami)
loads "mag005_b.00" and "mag005_b.01"

Code: [Select]
Code:
0x008D--0x0061DE50--0x0061DE70--Renzokuken - 5 Hits
loads "mag140-158-159-258-331-332.tim"

Code: [Select]
Code:
0x0074--0x006C3560--0x006C3550--Quezacotl Summon (Thunder Storm)
loads "mag115.tim"

it seems that to find any associated files, you subtract 1 from the magic ID, convert it to decimal and any files with that number in it tend to get loaded.
It looks like those 2 functions are all that are needed, since I made magic ID 0xE0 turn into the cure/fire animations and assigned that ID to the fire spell.
 
Last edited:
I wish you guys would use github pages to document stuff, then anyone can download a copy or fork it and edit it.
 
I'm not very familiar with GitHub. How could github help us collect research? As a big notepad or? So far I know github is used to store source code and as source control. Paul, please lend some tips. :)
 
Github pages uses a git repo for displaying a website, and since its a git repo you can fork/edit/push back changes. Instead of source code text its wiki page text :P
 
"
One... Two... Three...
Teach me how to GitHub" - kid to Tidus, Zanarkand 1000 years ago

A notes page that everyone can edit sounds terrific. I'll make sure to create one today.
:)
 
Let me know if you do and I'll add a bunch of stuff to it :). I've just finished documenting all of the character section of kernel.bin in this post
 
Because I pretty much control the wiki, and there hasn't been a lit of demand for people to gain access. If you PM me your username, email address, and password. I can add you to the qhimm wiki
 
Looks like this:
https://github.com/MaKiPL/FF8_Reverse

I'm confused what now. xD
I'll copy all my notes of files there.

EDIT: I'm really... really confused...
EDIT2: Ahh... The wiki page: https://github.com/MaKiPL/FF8_Reverse/wiki
EDIT3: No, really. Maybe I'm just stupid, but I don't understand how github is better than this thread and wiki here.
You need to make a branch called gh-pages and set it as the default branch name. For example https://github.com/munificent/wren/tree/gh-pages

Then your URL is something like username.repo.github.io

Edit: The github wiki isn't the same as github pages, its a normal wiki that sucks since you have to manually add people like on qhimm wiki and no one and easily grab a whole backup of the wiki.

gh-pages docs: https://help.github.com/articles/what-are-github-pages/
 
Last edited:
i dont really understand what i just read but i think you could increase the damage cap and also change music lets say for example make seifer battle music same as edea battle music that would be epic we already know how to change damage and levels and abilities of enemy and gfs and magic damage and affect on enemies and junction ,we only need to change the stupid easy enemy ai (just to add more twist and strategy in battle -seymour and two guado guards- seifer and two elite guards taking damage from seifer and healing him would be nice we know that biggs heal wedge in the communication tower but the condition is hard to met its easly done if we know how to read enemy ai, lastly if you guys can put all this info into a working program like ifrit or mystre save editor and make modifing easier . all the power to you one day we can make the perfect ff8 remake just like ff7 .   :lol:
 
Amazing work JWP! Just tried this myself and it seems to work perfectly. By making these changes, it is very simple to adjust Vit 0 resistance for each enemy individually, especially in conjunction with Ifrit enemy editor. Almost like a dream becoming true.. Can finally get back to work now. Thanks a ton! :-D
Wait, how are you changing Vit0 resistance with Ifrit? I just looked again, and Ifrit doesn't have the Vit0 status byte to edit (the last one available is the byte for the unused Percent spell). So even by using JWPs code changes in the .exe, you'd still have to edit the Vit0 byte in each enemy file with a hex editor, or am I missing something obvious here? Sorry if this is a dumb question.
 
Status
Not open for further replies.
Back
Top