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

Pages: 1 2 [3] 4 5 6 7 8 ... 67
51
Completely Unrelated / Re: Post Your Avatar!
« on: 2014-05-21 20:26:05 »
Clearly!

52
How did you trace / find this? I was wondering if it might be worth writing a PSOne implementation.

53
I think I understand - you're saying the PAL version has twelve empty padding bytes at 0x4700, and that these need to be removed before editing (and reinserted on build).

54
Team Avalanche / Re: [HD Remake] WIP Sector 5 slums
« on: 2014-05-07 20:45:09 »
OK - I'm impressed. Particularly by the PSX model.

Really great to see such attention to detail and faithfulness to the original's aesthetic.

55
I've split this post into a new, separate topic. I've also removed the post on the Hojo thread; please don't double post.

Anyway, to answer your question: How are you reinserting the files into the ISO exactly?

56
Gameplay / Re: How to change the IA in Proud Clod
« on: 2014-04-28 19:17:07 »
Quote
I want to explain why I wrote it the way I did, NFITC1. From my own experience, the Wiki is quite heavy on technical terms which can be tough to follow for folk like me who don't have a background in programming

The thing is, AI scripting is programming, it must demand some grasp of technical concepts; asking for a "programming tutorial for non-programmers" is like asking for a photography course for the blind. You can't really hide the details and the caveats of it, because as soon as your reader tries to riff from your tutorial's procedure, they're going to run into trouble. Tutorials should be springboards, not recipes, so we have to equip readers to start understanding the foundations of what we're doing - not choose ambiguous analogies just for the sake of simplicity. That's why your definition of '92: closes the attack part' is problematic, because it's going to cause someone trouble as soon as they want to go beyond a basic script and choose from multiple attacks.

OP : Proud Clod's help files contain a solid, if slightly sparse, introduction to FFVII AI scripting. It's a good resource; I would begin there. It will take a little time to get up to speed, but once you've grasped AI editing, you'll have a lot of power at your disposal. Good luck.

57
What uses that follow-up action stuff? I'm assuming all attacks with the 'follow with attack X' additional effect, but does anything else? Where are the critical 'yeah!' flags stored?

58
FF7 Tools / Re: [REL 1.5.0/FINAL] Proud Clod
« on: 2014-04-21 17:42:53 »
Interesting. In what scene was the enemy you sync'ed? If we can isolate criteria for replicating the bug, we can fix it much more easily.

59
I do think that Square-Enix is in its sunset days.

60
FF7 Tools / Re: [REL 1.5.0/FINAL] Proud Clod
« on: 2014-04-15 20:47:24 »
The enemy sync functionality merely syncs stats. It shouldn't cause enemies to be copied to new scenes, or for formation data to change.

I do remember some builds of PC breaking formation data from time to time; it caused me a lot of issues with Rebirth. It's fixed in more recent releases, though.

61
Reading your earlier post, it sounds like you might have really messed up your KERNEL.BIN (and possibly SCENE).

You could try restoring the original files and only applying the patches that affect enemies, battle mechanics, equipment and materia, but it might be less risky just to start again. This time, you might be wise to back up your SCENE and KERNEL at certain intervals.

As for the original problem, if I had to guess, I would assume that two mods are trying to apply simple binary diff patches to compressed data. This would corrupt that data. Or it could be something entirely different.

62
Apparently, fixing the problems that caused is not as simple as re-running PC with the .dll in the same directory.

No, it is not. In any case, now that you've got Proud Clod running, you should be able to regenerate your KERNEL.BIN scene look-up index without any problems.

63
Did you install all the prerequisites for Proud Clod?

64
If you need to add a large scene.bin to a PSX ISO, search the forum for my old Disc Extension Patch. It should support scene files up to 2 Meg in length.

66
I've no plans to write an editing tool. If you don't like CDMage, you could always use cdpatch (the author distributes his source code, too).

If you wanted to write one yourself, my understanding is that PSX discs are effectively written in Mode-2 XA, meaning that they are built of 2352 sectors written to disc in a raw fashion, but including portions of their own XA-like ECC data (maybe the videos are written without ECC data; I don't know much about them). These blocks have 2048 bytes of data, 4 bytes of error-detection CRC and 276 bytes error correction data.

You would presumably just need to serialize your source file into 2048 byte blocks and insert them into the disc image. If you're playing on an emulator, you probably wouldn't even need to bother regenerating the ECCs.

67
No. I'm not sure what open-source alternatives there are. Gemini wrote a file insertion lib as part of his translation tools, and there's loads of MIPS disassemblers out there. As for CDMage, I don't actually know what's so special about its reimport functionality. Maybe other ISO editors don't understand that the files are CD-ROM XA and stamp on ECC data / sector headers as a result. If that's all, you could probably write your own file inserter yourself.

68
If you've ever flirted with the idea of modifying the PSX FFVII executable, you've probably struggled to find much info on exactly how to do it. I know I did. That's why I'd like to post a brief how-to on the procedure for performing assembly edits on the PSX release.

Understanding the executable

Unlike FFVII PC, the PSX does not have a singular 'executable'. It is made up of overlays, representing the different parts of the engine (field, battle, menu, minigame etc.) and a small kernel storing state shared between the overlays. Overlays are so-called because they are 'painted over' memory space as they are loaded. So you are not going to edit 'the executable', but rather the particular overlay relevant to the behaviour you'd like to hack.

Overlays sit in their own individual files, and may even be themselves separated further still. For example, whilst the battle engine is simply BATTLE\BATTLE.X, the menu module is split into multiple .MNU files defining behaviours for different aspects of party management logic (SHOPMENU.MNU for shops; EQIPMENU.MNU for equipment; etc.). I don't know all the files for all the logic; I've only ever really taken an interest in BATTLE.X

Extracting and inserting the files on disc

The easiest way to do this is to use CD Mage beta 5. Hit the 'export file...' and 'import file...' dialogs to extract and insert your executable files.

Turning a .X file into readable assembler

FFVII executables are compressed, so you can't just run them straight through a disassembler. You have to unpack them first. You can do this by removing some header bytes, then treating the file as a gzip archive (.gz). You will need a hex editor (I like Frhed; it has quite a few features and it's freeware) and a utility for unpacking gzipped files (7-zip can do this for you, and it's open source)

Here's the process:
  • Using the hex editor, remove the first eight bytes from the file (store them in a document somewhere; you'll be reinserting them later). 'Remove' means remove, not 'zero out'.
  • Save your edited file. If you save with the extension .gz, 7-zip should be able to pick up that it's in gzip format.
  • The output of the gzip is a plain file which contains your executable binary
Disassembling the file

A disassembler will let you view an executable binary as a sequence of assembly opcodes - so you can read the code. I like to use LemASM for this job. Remember that the files are little-endian in both bytes and words, so you will need to use LemASM's 'swap bytes' and 'swap word' functions to view the file properly. You will also need to hit 'MIPS disassembly' under the File menu.

Reversing the assembler

I can't really provide a guide to this. The best reference for the PSOne's opcodes and registers is Halkun's own "Everything you wanted to know about the PlayStation but were afraid to ask". Otherwise, take a look at this reference. Remember that quite a few MIPS opcodes have a one-instruction delay, so when you're trying to read the logic around 'lw' (load word) or branch instructions, remember that they don't take effect until the next opcode has been executed.

Writing new assembler

I would recommend using ARMIPS for this job. You give it a file which contains its own insertion instructions (e.g. BATTLE.BIN 0x800AB00), and it'll encode your assembler for you (it'll handle the endianness for you, too). You can use labelled jumps, you can use macros, and you can make it spit exceptions if your assembler is larger than the area you want to replace. It's a very handy tool.

Re-packing your executable file

This is basically the decompression step in reverse, but because you're usually trying to avoid file size increases (unless you fancy updating file lookups), it's a tad more complicated. You are going to need the Unix gzip (or some gzip utility with the same functionality). If you're on Linux or OS X you should be able to just call that from bash; if you're on Windows, you're probably going to want a Cygwin-compiled version like the one that comes with FF7dec.exe.

The procedure is as follows:
  • Turn your updated assembly file into a .gz by calling, at the command line, gzip -n -9 . The -n switch stops gzip inserting the file's name and compression timestamp into the archive, and -9 forces gzip to compress at tightly as it can, even if it means performing the compression slowly. This helps stop the filesize from increasing
  • Reinsert the eight bytes you originally removed from the .X file into your .gz file. 'Reinsert' means prepend, not 'overwrite'. Save with the ending .X, .MNU, or whatever the original was.
  • Reinsert your file using CDMage Beta
And that should be enough to get playing.

69
Q-Gears / Re: Q Gears Mobile Port
« on: 2014-03-04 21:26:57 »
Q-Gears is still very incomplete, and making it run on either iOS or Android would be problematic. I believe you can wrap native executables for running on Android using the NDK (then call the application with a very thin JNI client), but to my knowledge, there's no such thing for iOS.

I don't know how Q-Gears renders stuff on screen, so I don't know what interfaces it could use to render graphics on Android.

I also don't practically know how you'd make the controls work on touch.

70
If you want to do something other than modify a value (i.e. add new behaviour), then you're going to have to implement it either by finding an AI hack (which I don't think is possible in this case), or modifying the executable. You do that by either getting to grips with assembler and the toolchain for modifying the executable, or hoping that someone else will write it for you out of the goodness of their hearts (they might; they might not). If you can write FFVII AI scripts confidently, you should be able to learn x86 assembler (or MIPS for the PSX) without massive amounts of trouble.

You can't just replace the accuracy check with a damage transformation, because at the point the accuracy check is run, base damage hasn't been calculated. You're going to have to add a call to your fury function after base damage calculation. Your fury function will probably operate in a similar way to the sadness function, yes. Where the calls go depends on which damage equations you want to affect.

If it were me, I would be lazy and just add the fury damage multiplier to all physical attacks. I'd probably just insert a call to my own function in the space I freed up by making the back row check smaller. I would check how the berserk function looks up attacker statuses, then use that to look up the fury flag instead. From there, I'd do whatever maths I needed to with the current damage register, then jump back to the next sub. I suppose you could hardcode the jumps rather than making a proper function if you wanted to make this as easy as possible. I could only tell you where these subs are in the PSX version, though.

71
You won't be able to 'replace' the fury accuracy check with a damage change, as accuracy is considered before base damage, but you could add a fury check to whichever damage formulae you wanted to affect. You could add a sub in an empty part of the executable (I know there's a big sea of nops in the PSX battle overlay) and add calls wherever necessary. The function bodies don't have gaps between them, though, so you would need to either move stuff around and update lookups or do some optimization to make your caller functions smaller, so the extra calls will fit.

The other thing you could do is replace an existing damage sub. If you're getting rid of frog, for example, you could probably replace it with a status check of your own.

On PSX the current damage is passed around subs on the register R4. Check out the q-gears source for a good reverse of that whole section.

As for shifting, a right shift by N places will divide the number by 2 to the power of N. A left shift will do the opposite. If you want to null the limit gain I assume you could just set the factor to zero.

72
I've seen the accuracy function for the PSX, though as I'm typing on a phone it's a bit tricky for me to point you to to it. The accuracy probably won't be applied as a percentage though. Those maths operations will have gone through an optimising compiler and usually come out at the end very fast but not very flexible (they will use bitshifts as much as possible). At least that's how it is on PSX, and I've no reason to think the PC build will be any different.

You'll likely need to patch the assembly rather than change a single value, but it's really not as hard as people make out.

73
Releases / [FF7PSX NTSC-U] Enemy long range attack mod
« on: 2014-02-12 22:07:20 »
You might not be aware of this, but in the vanilla FFVII, all enemy attacks are treated as short range. This includes attacks that use the 'magical' upper formula and attacks that lack the 'short range' flag. If it's an enemy attack (command type 0x20) and it uses the X1 formula, it's always treated as range-sensitive, with halved damage if either actor or target is in the back.

This might not be desirable. If you're creating a 'rebalance' mod that relies on a few enemy attacks being able to counter the use of the back row, it won't work as you expect. This was the problem I faced for my own PSX rebalance, Rebirth.

As such, and following the discussion here, I've written a little ASM hack to fix this behaviour. As I imagine most users will be modders themselves, I've chosen to distribute this as both a binary patch for the BATTLE.X file, and the assembler itself (for use with ARMIPS). You can download the BATTLE patch here.

Source

The assembler itself is as follows:

Code: [Select]
.open "BATTLE",0x800A0000
.psx

.org 0x800ADA28

.area $9C

//check_long_range_attack
   lw   v1, $0050(a1)
   nop
   andi   v1, v1, $0020
   bgtz   v1, check_self_backrow ; if short range attack, check self/target backrow
   nop
   j   0x800ADAC8 ; else skip to next sub

check_self_backrow:
   lw   v0, $0000(a1)
   nop
   sll   v1, v0, 1
   addu   v1, v1, v0
   sll   v1, v1, 2
   addu   v1, v1, v0
   sll   v1, v1, 3
   lui   at, $8010
   addu   at, at, v1
   lw   v0, $83E4(at)
   lw   v1, $0208(a1) ; start loading word for check_target_backrow (save space)
   andi   v0, v0, $0040 ;v0 now contains self.isBackRow

//check_target_backrow   
   sll   at, v1, 1
   addu   at, at, v1
   sll   at, at, 2
   addu   at, at, v1
   sll   at, at, 3
   lui   v1, $8010
   addu   v1, v1, at ;v1 contains address for lookup
   lw   at, $83E4(v1)
   nop
   andi   v1, at, $0040 ;v1 now contains target.isBackRow

//do_comparison
   or   at, v0, v1
   bgtz   at, reduceDmg ; if target.isBackRow || self.isBackRow, go to reduceDmg branch
   nop
   j   0x000ADAC8 ;skip to next sub
   nop

reduceDmg:
   j   0x000ADABC ; sends to damage reduction subfunction
   nop

.endarea

.close

You will need to use ARMIPS to compile this with a decompressed BATTLE.X, then you'll need to repack with gizp compression and re-add the header bytes to create an X file. The procedure is detailed elsewhere (I'm about to post a thread on it, in fact).

This file was made with the NTSC version, but as I believe the European PAL version uses the same BATTLE.X, it should work fine. I will need to investigate.

I have tested this patch myself, but it's always possible I missed something. If you have any issues, let me know in the thread below.

74
Bump for new information.

So I've been investigating the procedure at length with LemASM and Halkun's PSX guide and I think I have a fix.

Firstly, it looks like my earlier information about the position of the opcode was incorrect. The instruction at DB00 is actually part of the 'isDefending' check, which is probably why messing around with it quartered my damage. No, the procedure for checking back-row-ness starts at 800ADA28 (DA28) and terminates at DAC4. As NFITC1 says, it has a flaw, namely that if an attack is an enemy action, the branch for a long range attack is effectively exited. Here's my own low-level reverse (this took a while to get the logic right; I didn't realize jump and branch opcodes had a one-instruction delay):

Code: [Select]
// Start at DA28
// R4 contains result of first damage equation

R3 = load word from [r5 + 208] // gets value of offset 208 from temporary scenario array stored in R5
R2 = R3 * 2
R2 = R2 + R3
R2 = R2 * 4
R2 = R2 + R3
R2 = R2 * 8
R1 = 8010 0000
R1 = R1 + R2
R2 = load word from R1 + 83E4
// this seems to get the target unit flags specified at http://sourceforge.net/p/q-gears/code/ci/default/tree/reversing/ffvii/ffvii_battle/ffvii_address.txt#l655
// I *think* these are flags for the target rather than the actor
R3 = load word from [R5 + 0050] // get attack target flags
R2 = R2 && 0040 // R2 = target.isBackRow
R3 = R3 && 0020 // R3 = attack.isShortRange
R6 = (0 < R2) // reducedDamageFlag = target.isInBackRow
IF R3 != 0, BRANCH TO DA74

// DA64
R3 = load word from [r5 + 28] // get attack type data
R2 = 0 || 20 // 'enemy attack' command
IF R3 != R2, BRANCH TO DAB4

// DA74

R2 = load word from [r5 + 0]
R3 = R2 * 2
R3 = R2 + R3
R3 = R3 * 4
R3 = R3 + R2
R3 = R3 * 8
R1 = 8010 0000
R1 = R1 + R3
R2 = load word from [R1 + 83E4]
// seems to be unit flags for actor
R2 = R2 && 0040 // R2 = self.isBackRow
IF R2 = 0, BRANCH TO DAB8

R6 = 1 // reducedDamageFlag = true
JUMP TO DAB8

// DAB4
R6 = 0

// DAB8
R2 = R4 >> 1F
// right shift R4 - current damage - by 31 places, leaving upper bit
IF R6 = 0, BRANCH TO DAC8
R2 = R2 + R4
// add upper bit to get negative damage to bitshift divide properly?
R4 = R2 / 2

// DAC8
// Seems to be start of ‘target defend’ check

This is a bit hard to follow. Here's a digested version:

Code: [Select]
applyDamageReduction = target.isBackRow;
if (attack.shortRange) {
    checkActorRow();
}
else {
    // if attack is long range
    if (attack.enemyCommand == false) {
        applyDamageReduction = false;
    }
    else {
        checkActorRow();
    }
}

function checkActorRow() {
    if (actor.isBackRow) {
        applyDamageReduction = true;
    }
}

if (applyDamageReduction) {
    divideCurrentDamageByTwo();
}


Basically, if the attack is long range and is an enemy attack, the flag is not cleared, and the actor's row is still checked regardless of the fact the attack shouldn't care about rows.


This won't do - as it means enemy attacks are having their long-range status ignored. What we actually want is this:



My fix

This is the fix I'm trying, at a high level. It's pretty basic:
  • Get attack target data; if long range, skip to defend check script (DAC8)
  • Store self.backRow in R1
  • Store target.backRow in R2
  • If R1 || R2 = false, skip to defend check script
  • Apply damage reduction to R4
There's a bit of redundancy here, but this is my first ASM patch, so I really don't care about a few wasted cycles.

Here's how I think I can write the assembler:

Code: [Select]
// Check for long range attack

LW R1, $0028 (R5)      ;load R5+28 (target flags?) into R1
ORI R2, R0, $0020      ;don't know why the original code used this method, but I'll preserve it
BNE R1, R2, $0000DAC8 ;goto defend script
NOP                            ;do I need to include these after jumps?

// Load self.backRow into R1
LW R1 $0000 (R5)     ;load R5+0 (self unit flags?) into R1
NOP                           ;apparently loads are delayed by one cycle
SLL R2, R1, $1
ADDU R2, R2, R1
SLL R2, R2, $2
ADDU R2, R2, R1
SLL R2, R2, $3
LW R1 $83E4 (R2)     ;get offset and load
NOP
ANDI R1, R1, $0040  ;this should put the AND of R1 && 0x0040 into R1

// Load target.backRow into R2
LW R2 $0208 (R5)   ; load R5+208 (target unit flags?) into R2
NOP
SLL R3, R2, $1
ADDU R3, R3, R2
SLL R3, R3, $2
ADDU R3, R3, R2
SLL R3, R3, $3
LW R2 $83E4 (R3)      ;get offset and load
NOP
ANDI R2, R2, $0040      ;this should put the AND of R2 && 0x0040 into R2

// Do comparison
// If either self or target are back row, their register should contain 0x0040
OR R3, R2, R1           ;will contain 0x0040 if either party in back row, should contain 0x0000 if not
BLEZ R3, $0000DAC8     ;skip to defending script if zero

// Continue with existing 'reduce damage' implementation, ignoring test for R6 != 0

I'll try the above this afternoon. I'll double check, but I think this should be right. My only hope is that I don't make the procedure longer; I'd rather not mess around moving the file. I think it should be about the same, though. I assume ARMIPS will just overwrite from the address I specify, so I won't need to update any other jumps in the procedure? In terms of lines, it'll certainly make things smaller. Might be an idea for me to fill in any unused space with NOPs though.

I should probably also double check that enemy attacks get their target flags copied the same way too...

One final question: if I write branches, jumps or any other instruction-delayed opcodes in my assembly and pass it to ARMIPS, will the assembler insert the NOPs automatically or do I need to do this myself?

Edit

Excellent! I was able to compile my assembler, and it looks as though it was written to the file just fine. Had to make a couple of changes here and there (I didn't realize that branches had a reach limit, for example), but it seems to compile without trouble. Here's the actual script that I used with ARMIPS:

Code: [Select]
.open "BATTLE",0x800A0000
.psx

.org 0x800ADA28

.area $9C

//check_long_range_attack
   lw   v1, $0050(a1)
   nop
   andi   v1, v1, $0020
   bgtz   v1, check_self_backrow ; if short range attack, check self/target backrow
   nop
   j   0x800ADAC8 ; else skip to next sub

check_self_backrow:
   lw   v0, $0000(a1)
   nop
   sll   v1, v0, 1
   addu   v1, v1, v0
   sll   v1, v1, 2
   addu   v1, v1, v0
   sll   v1, v1, 3
   lui   at, $8010
   addu   at, at, v1
   lw   v0, $83E4(at)
   lw   v1, $0208(a1) ; start loading word for check_target_backrow (save space)
   andi   v0, v0, $0040 ;v0 now contains self.isBackRow

//check_target_backrow   
   sll   at, v1, 1
   addu   at, at, v1
   sll   at, at, 2
   addu   at, at, v1
   sll   at, at, 3
   lui   v1, $8010
   addu   v1, v1, at ;v1 contains address for lookup
   lw   at, $83E4(v1)
   nop
   andi   v1, at, $0040 ;v1 now contains target.isBackRow

//do_comparison
   or   at, v0, v1
   bgtz   at, reduceDmg ; if target.isBackRow || self.isBackRow, go to reduceDmg branch
   nop
   j   0x000ADAC8 ;skip to next sub
   nop

reduceDmg:
   j   0x000ADABC ; sends to damage reduction subfunction
   nop

.endarea

.close

The endarea tests for the size of the overwrite (quite a handy feature). It looks as though my writeup is actually the same size.

Unfortunately, I haven't been able to test it in battle yet, as I'm having trouble reinserting the file. The game doesn't seem to like my gzipped insert; starting a battle freezes the game and looking in memory for the updated assembler suggests the decompression has gone *badly* wrong. Anyone have any ideas?

Edit again: I fixed the issue with the file inserts (I was _overwriting_ the first 8 bytes of the gzipped file with the x file header, rather than _inserting_ the original 8 bytes back in again). It's now working, except the logic seems to be off. I think I got the address wrong in one case - looks like R5+0050 is what gets the targeting flags, whereas R5+0028 gets the command type. Changing my script makes things work better, but now it looks like everything is being treated as long range...I will trace and report on this soon.

Edit2: I have fixed the issue using the updated code above. I have raised a new thread about this fix (http://forums.qhimm.com/index.php?topic=14998.0). I'll also share an end-to-end guide to how I performed this hack, so others wondering about PSX assembly edits can get some much-needed information.

75
Hmm. This doesn't look like a _horribly_ hard rewrite given that I now know what the values represent. So long as I use the same registers and leave them in the same state I think I can do this, albeit with a lot of references to the instruction set docs. Famous last words, though.

The bigger question, though, is why my edit made the attack deal 1/4 damage rather than 1/2.

Pages: 1 2 [3] 4 5 6 7 8 ... 67