DCFFVII Research Thread


別のDISCが挿入されています。​
ダージュ オブ ケルベロス​
-ファイナルファンタジーVII-​
のDISCを入れてください。​
Corresponding English text entry:​
Another disc is currently inserted.​
Please insert the​
DIRGE of CERBERUS -FINAL FANTASY VII-​
disc and close the disc tray.​


I'm surprised that the first sentence says that "Another disc" has been inserted when clearly this is not the case. The JP and ENG text is found in the KelStr 1.1 file, where basic menu text can be accessed from any point in the game.

I look forward to getting my second copy of J-1.0 so I can test and see if the problem is my PS2 laser or the game disc. Either way the result will be interesting.

Whenever this problem occurs the background music goes away. I think some sound effects go away too. All 3D models remain intact though. The game will freeze and get stuck on the error message before any more dramatic degradation of gameplay is allowed to take place.


Let me just say that playing the Chapter 2 gun turret section was AWFUL with the mouse in JORG. The rubber-band effect with the sight aim is heavily felt in this section.
 
- In the fight against Azul at the end of the Chapter 4 there are two item cases in the corners. In the JORG version there is a bug that makes these item cases invisible. What I did not know until now is that there is a particular condition for this to occur: The item cases will be invisible if you enter the battle from the checkpoint menu (Chapter 4-4). However if you enter Chapter 4-3, which is the battle against Shelke, and play up until the battle against Azul then the item cases will be visible! The same is true if you play the chapter from its start. Neat.


- I put away my modded PS2 and brought out my Japanese PS2 model SCPH-50000. So far it's playing my old copy of Dirge J-1.0 without problems but I need more time to be confident that no disc reading errors will pop up. One of the reasons I'm insisting on continuing to play is because I'm investigating my corrupt JP save file. As has been mentioned before, corrupt JORG save files lead to checkpoint erasure. Curiously, when I began a new playthrough in this save file one of the checkpoints was restored. I'm playing through the game to see if any more checkpoints are restored or removed as I play.

Checkpoint 9-2 restored:


The other documented JP case of save file corruption I have is for Chapter 4, where only the first out of four checkpoints remain. I don't have this save file preserved though. What seems to be an amusing coincidence is that both Chapter 4 and Chapter 9 end with you fighting Azul. JORG has a tendency to corrupt your save after defeating Arch Azul in Chapter 9 and apparently there is a risk for this when defeating Azul in Chapter 4 as well. What is it about Azul and his tendency to moderately wreck your save file? :wacky:


- I am running experiments with the external hard disk drive for my PS2 model SCPH-50000. So far everything indicates that it can't be used to reduce load times for Dirge of Cerberus but I need to run some more tests before I can be certain. (EDIT: It's likely that unofficial methods are available to reduce loading times, such as placing the whole game on your HDD and playing the game from there, but for now I'm only considering the official methods.) One thing I was able to determine though was a natural variation in the game's loading times.

If you take the average loading time for any given loading zone of the game, there is a variation of ±10 video frames (or 1/3 of a second). So if you're lucky you get the lowest amount of loading time, minus 0.33 seconds the average, and if you're unlucky you get a loading time of plus 0.33 seconds the average.

For those who don't remember (or weren't around for it) I bought this Japanese PS2 + HDD specifically so that I could click on the "PlayOnline" option in the original Japanese version of DCFFVII and finally get to see that PlayOnline Viewer installation screen with my own eyes.
 
Last edited:
So I was having fun learning to navigate the BB Navigator and even booting up the original Japanese release of Final Fantasy X when my voltage converter decides to overheat and shatter. Now I can't use my Japanese PS2 and the FFX disc is locked into the console because I can't get power to it. Gosh darn my European voltages.

If all goes well I should have a new voltage converter sometime by Wednesday - Friday but man this sure is annoying.
 
With my new- and seemingly higher quality voltage converter I can continue this Final Fantasy X detour as I explore the PS2 technology.

Older versions of the PlayStation 2 had an Expansion Bay in which you could insert a hard disk drive. Far more Japanese games than English ones had HDD support. Often the hard disk drive was used to decrease loading times in games. Typically this would happen by installing a large file onto the HDD for the game to access.

The Japanese PS2 releases of FFX had HDD support for the purpose of diminishing loading times. Luck has it I own the original JP release of FFX which means I can test this out. No idea though why I own this copy of FFX. :monster:



ニューゲーム​
ロード​
インストール​
New Game​
Load​
Install​


Installing the file takes 10 minutes and 30 seconds with my setup. For easier viewing I sped up the footage for when the download was at 5% - 96%. You can of course easier enjoy the video by using YouTube's own play speed manipulator. Oddly enough nothing stops you from reinstalling the file after you've installed it once, as you can see by the end of the video.

When selecting New Game (and presumably when selecting Load, though I never tried this) you get the option to play with- or without the HDD.



ハードディスクドライブを使用しますか?​
はい​
いいえ​
Do you use a hard disk drive?​
Yes​
No​

Select Yes to enjoy the decreased loading times. I did make sure to play the game once after selecting "No" just to check that the HDD wasn't accessed and indeed the HDD file is not used when you select negative.

I recorded the first forty minutes of play both with- and without the HDD file installed and created a 6-minute montage from it.


As you can tell, transitions are consistently and considerably faster when you have the HDD file installed.


BONUS: Showing the HDD folder in the BB Navigator, first without the FFX file and then with the file installed.


EDIT: The message at 1:53 says the following.

このゲームは起動時にディスクが必要です。​
ディスクを挿入してください。​
This game requires a disc at startup.​
Please insert a disc.​

The only way for you to play the game directly from the HDD, without a disc, is to use mods.

For those who don't remember, the BB Navigator is like the standard PS2 Browser/Interface but on steroids and with tons more options. BBN supports mouse, keyboard and even remote. If you're using the standard PS2 browser then you have to use a normal PS2 controller to navigate, which naturally annoyed me when I wanted to copy Dirge of Cerberus save files and I only had the mouse- and keyboard plugged in.

Sadly though the BBN takes a long time to load. I show about 30 seconds of loading at the beginning of the video to share my pain and yet I skipped about 10 seconds of loading. BB Navigator is cool but it takes a long time to boot.

The file here is 1792 MB, contrary to the number on the wiki which reads 1664 MB. Maybe 1664 MB is the file size for the FFX International version?

BB Navigator was only officially released in Japanese and for JP consoles, though you can install an English mod.
 
Last edited:
As mentioned earlier, I have a JORG save where the game save is corrupted which causes checkpoint erasure. When starting a Normal mode playthrough, one checkpoint got restored immediately. Now, upon clearing Chapter 9 all in one go...


The error message that notifies "your save is corrupted" no longer pops up. This is an interesting development. I do not know if the fresh playthrough was necessary in order for the un-corruption to work or if the save might get re-corrupted as I complete Chapters 10 through 12.

Still, it's interesting to have at least ONE example of a save corruption being undone.

***EDIT: Worthy of note is that I haven't received a single disc-reading error while playing my old copy of DCFFVII JORG on my Japanese PS2. In other words the disc-reading error I'm receiving on my modded PS2 is unique to that modded console's laser (probably).

Maybe it's unable to retrieve the proper region-confirming data and when it can't detect the Japanese disc the game decides to say "you've got the wrong disc inserted". But that's just my wild speculation.***



Having confirmed that Dirge of Cerberus does not make use of the HDD to reduce loading times, my attention turns to the homebrew applications that I've never dared delve into before: HD Loader and Open PS2 Loader.

As it turns out, my Free McBoot memory card contains the Open PS2 Loader application.



Once I muster the focus and courage I will read up on this application and see if I can at all use it to reduce loading times in Dirge of Cerberus.
 
Last edited:
Cleared JORG in Normal mode using keyboard+mouse.

The frame-drop issue when using the mouse aim in J-1.0 is far more frequent (and perhaps even more pronounced) than in later releases. Sections like the obligatory gun turret section in Chapter 10-3 or the battle against Weiss in Chapter 11-6 become almost unplayable due the lowered precision that results from the frame drops. AND THIS WAS IN NORMAL MODE! The unfairness of poor controls due to frame drops would definitely become even more pronounced in Hard mode.

If you switch to the PS2 controller you may still experience some frame-drops in gameplay during resource-heavy sections but the sight aim with the analog stick will remain steady and precise. It's fascinating how there can be such a huge difference between the mouse and the PS2 controller (or keyboard) here, even though the game's resource management SHOULD be equivalent for both setups. In other words the real issue isn't so much that the game's framerate drops but the fact that the sight aim is programmed far worse for the mouse than with everything else. It is as though the mouse is directly linked to the game's overall performance in a way that the keyboard- and PS2 controller aren't.

Why the issue is less frequent in the post-JORG versions I do not know. They definitely improved the design by removing the rubber-band effect with the mouse in post-JORG releases, meaning there was some conscious thought put into the controls between releases. Perhaps the improved controls is a remnant from an update made for the online multiplayer. Admittedly that is just my speculation.

***Note to self: Check that the mouse aim issues in JORG are the same even on my modded PS2 if I can get J-1.0 working 100% on that console again. There is the tiniest possibility that the observed difference is due to my modded PS2 simply being more powerful than the official Japanese PS2 I'm playing on.***


The save file remains "officially" uncorrupted, but a new bug has manifested. When you play through the obligatory lose-battle against Weiss the Immaculate, followed by cutscenes and then followed by a battle against Weiss Empowered, the start/pause button and the menu button DO NOT REGISTER! This is regardless of your input setup: Controller, keyboard and/or mouse. I am forced to watch the cutscenes and I can't pause anything or customize my equipment. Only by accessing the latter boss battle from the checkpoints menu (or restarting after a game over) will the start button and menu button work again!

The bug keeps appearing even though I've defeated Nero a total of three times to check if this bug just randomly manifests after the Nero battles. This makes me think that the bug is unique to this save file, perhaps due to its corruption history.

What a mess. Oh well. Time to set my eyes on the Open PS2 Loader...
 
Last edited:

Radigar

Pro Adventurer
AKA
Radigar
Probably isn't a great discovery, but I wanted to share it with you and especially with @Shademp . On March 25, 2006, a special event called "Play Online Festa 2006" was announced by Square-Enix itself was held in one of the Akihabara stores called Necca.

Those who attended apparently were able to play the DoC multiplayer version and a wonderful present is prepared for those who participated. (It is not clear what kind of gift was).

Some event photos:





Image sources:
https://game.watch.impress.co.jp/docs/20060325/polfes.htm
https://dengekionline.com/data/news/2006/3/25/8697dc272d92ce2b10f8a0de825e46c5.html
 
Open PS2 Loader (OPL) - USB



After buying a Kingston 32GB USB I tested out Open PS2 Loader's USB function, playing Dirge of Cerberus via this homebrew method on my Japanese PS2.

RESULT: Gameplay-wise it works fine but you'll get longer loading times on USB compared to playing with the game disc.

Commonly, loading gameplay and cutscenes will mean an additional 3-6 seconds of loading time with the OPL-USB method. At the most you might find that sometimes Extra Features menus will load slightly faster on USB (from 1/3 of a second up to one whole second faster) but this still leaves the majority of loading sessions having you wait 3-6 seconds longer than normal. Consider also that booting up the game takes longer, even when you don't count the time it takes to enter the OPL program and select your game.

Keep in mind I played Dirge of Cerberus with default USB settings in OPL. There are so many different settings to choose from that trying to find the perfect configuration would be extremely time-consuming. Currently I do not have the patience to explore this.


^Apologies for the poor Elgato capture quality.

There is also a general downside with USB to which there is no solution: Pre-rendered movies (in pretty much all PS2 games) stutter extremely when playing from USB. This makes any slow-downs you might have experienced in the PCSX2 emulator look like nothing. That's just how slowed down the FMVs are when PS2 games are played using the OPL-USB method. 1 times out of 10 I also experienced that OPL-USB simply wouldn't load the game, so I had to reset the console and try again.

Open PS2 Loader (OPL) still has the advantage that if you don't want to use a game disc and/or if your PS2 laser is malfunctioning, you can still play the games digitally off a USB. It also circumvents region-locks nicely. I can play North American and European games easily on my Japanese PS2 even though the console itself isn't modded at all. You can also use Virtual Memory Cards, giving you another venue to back-up and use save files. I have not tried out VMC though.


Future experiments I aim to do with OPL-USB:

- Attach a USB-splitter to my PS2. The console only has two USB ports, so when I'm using OPL-USB I don't have the two slots I need for keyboard + mouse gameplay. I'm highly skeptical of the PS2 accepting a USB-splitter in this fashion but at some point I want to test and see.

- Play DCFF7 JORG on my modded PS2 Slim and see if I can avoid game freezes. As I've documented earlier, this console of mine will at times refuse to read the game disc for the original Japanese release of Dirge. If the problem *is* in the laser (yet somehow still not affecting any other games) then playing the game via USB should lead to zero freezes.

- Play with virtual memory cards. The game-freeze test would be a good opportunity for this.


The main tutorial I used before testing out OPL-USB:


Keep in mind that if you have to change the formatting of your USB, you may lose any data on the stick in the formatting process. So if your USB isn't already formatted to FAT32 make sure you don't have anything precious on the USB stick already when you do format it.

I also experienced that when transferring the game ISOs to my USB via a USB-3.0 port, OPL wouldn't read the game due to a supposed fragmentation issue. When I transferred the ISOs using my USB-2.0 ports however, everything worked fine. I believe there's a solution to the fragmentation issue so that you won't need a 2.0 port, but I never looked into this.


I'm thankful to OPL for highlighting a matter that I never paid attention to earlier but which in hindsight is very obvious: The DCFF7 Beta is a CD and not a DVD. The disc is only 433 MB so it definitely fits on a CD and it was surely less expensive to print these CDs for online beta testing than to print DVDs.

What this means for OPL-USB is that if for whatever reason you want to load the DCFF7 Beta, you need to place it in the CD folder on your USB and not in the DVD folder. If this "game" is in the wrong folder then OPL can't play it.


Chances are higher that when using OPL with an HDD that loading times will equal to- or be shorter than those when playing from the game disc. Setting up the HDD is a far more complicated process than setting up a USB however so it may take some time until I try out this aspect of PS2 homebrew technology.
 
Last edited:
Playing with USB hub

I bought a USB hub that splits one of the PS2's USB ports into four ports. This way I had enough ports to play with mouse, keyboard and USB flash drive inserted. The way I ran this experiment was to insert the mouse and keyboard into the hub, while the flash drive occupied the normal PS2 USB port.

My main curiosity was if this would work at all and/or if there would be a noticeable latency with the mouse and keyboard inputs due to this setup clearly not being intended with the PS2 console. Fortunately it worked and if there is any latency it's so small that I don't notice it.

The only problem I experienced was that the keyboard sometimes would disconnect, though I suspect this may have more to do with the keyboard's USB cable being damaged or the USB hub not agreeing with the keyboard.

In conclusion: Even if you choose to play Dirge of Cerberus via the OPL-USB method you can still enjoy the keyboard+mouse experience as well.


Persistent game freeze glitch

Playing OPL-USB on my modded PS2 Slim (specifically, it is a modded PS2 with a Matrix Infinity v1.93 chip) I was astounded to experience a moment where the game froze. It was only temporary but it was in the same vein as might happen when I play the physical JORG disc on my PS2 slim. Barely less than an hour earlier I also confirmed that even my new physical copy of DCFF7 will freeze almost instantly when I play it on my modded console, though I did notice now that the disc looked fairly scratched.

I was convinced that playing via OPL-USB would liberate my console from the freezing error with JORG, but not so. Due to the unpredictable nature of this error I'm honestly wondering if it could happen with the other versions of Dirge as well, even though I accumulated so many play hours on those versions (and in recent times, even) without any freezes.

Error message while starting a new playthrough using my new physical copy of DCFF7 J-1.0 (JORG)


ディスクトレイが開いています。​
ダージュ オブ ケルベロス​
-ファイナルファンタジーVII-​
のDISCを入れて、​
ディスクトレイを閉じてください。​

Corresponding English text entry:
The disc tray is open. Please insert the​
DIRGE of CERBERUS -FINAL FANTASY VII- disc and close the disc tray to proceed.​


Different error message compared to the last one I experienced. Definitely replacing the laser (or whatever needs replacing) the next time I strive towards figuring out where the error truly lies with my modded console.


OPL-USB: Virtual Memory Cards

Just as playing a PS2 game via USB comes with increased loading times, so does playing with Virtual Memory Cards (naturally featured in Open PS2 Loader) on USB add yet longer loading times. The one advantage is that you can easily create just as many memory cards as you like, which means you can create multiple save files for the same version of Dirge of Cerberus no problem. However I am yet to find a way to convert Virtual Memory Card saves into normal "physical memory card" saves. If there isn't some solution on the official Free MCBoot forums then my only choice would be to extract the save with the help of a hex editor (which would be quite finicky and likely to fail).

So how dramatic are the differences in loading times when comparing Physical Memory Card (PMC) and Virtual Memory Card (VMC) ?

- Creating the Dirge of Cerberus save upon a first playthrough
PMC: 38.5 seconds
VMC: 2 min 15.67 seconds

By far the most dramatic difference. 97 seconds longer to create the save file when you are using a virtual memory card!


- Creating a Tempsave
PMC: 12.5 seconds
VMC: 44 seconds

The load status bar fills to completeness at the same time for both PMC and VMC, but the game stays loading in VMC for over 30 seconds before the Tempsave is finally completed.


- Loading the Tempsave
PMC: 3.17 seconds
VMC: 8.95 seconds

Just below 6 seconds longer on VMC.


- Transitioning from Chapter 1 Checkpoint 1 to Checkpoint 2:
PMC: 2.58 seconds
VMC: 7.69 seconds

5.1 seconds longer in VMC.


- Shooting a memory capsule: Length of time Memory Card icon is present
PMC: 2.25 seconds
VMC: 7.58 seconds

This is the sort of loading time that doesn't actually pause the game or interfere with gameplay. The same general "loading time" applies to when changing settings in the Config menu. When changing the button configuration, the memory card icon at the top right corner of the screen is present for 2.34 seconds with PMC, compared to 8.22 seconds with VMC. The same loading times apply when changing a keyboard configuration.


I have not gone out of my way to test if the increased loading times with VMC could lead to glitches such as one change to the memory card not registering because it's being interrupted by another process that just entered the cue. It would not surprise me though if this was possible.



I probably won't play around much more with OPL-USB. On the side I've also played with installing Free MCBoot on a second memory card and during that process I've tested three different versions of Open PS2 Loader. Configuration-wise they remain largely the same but the graphics change quite a bit. But the most exciting testing remains: Playing Dirge of Cerberus via the OPL-HDD method. Just today I ordered the two components I think I need in order to hook my old Sony "PS2" HDD up to my computer and I should receive these items within a week or so.
 
Last edited:
Definitely going the difficult route by insisting on using my 40GB Sony HDD for Open PS2 Loader. It would make more practical sense to just buy a modern HDD that is hooked up with SATA cables and that has way higher storage- and RPM capacity. But no, I feel committed to using my IDE 3.5" hard disk drive from 2003. :wacky:

To refresh the reader's mind, here is what the HDD looks like and how it's hooked up to your fat-model PlayStation 2.


My problem are the arms that are supposed to hold the network adapter in place (see 0:25 in the video).

- Photo of IDE-USB adapter partially inserted into the HDD

The arms are in the way no matter how I try to insert the IDE-USB adapter. I simply can't connect the adapter to my HDD completely. So I have to remove the arms by unscrewing them. But I don't have the tools to unscrew them. Add to that I'm uncomfortable with picking this HDD apart in a way that it was probably never intended to.

**EDIT: Removed a section of this post where I talked about a power cord that I thought didn't fit in to my IDE-USB adapter, but it actually turns out all I had to do was use a bit of force. :monster: **


While you're all waiting for me to clear this challenge, here's a great video about the history of PS2 modding.

 
Last edited:
Now I'm grumpy. Also, I am a fool.

So I bought the tools to unscrew the holders for the network adapter. I learned two things while unscrewing.

#1: The screws are glued at the bottom. Meaning that it requires a huge amount of force to start getting the screw undone. When you do, you'll hear a "plop" sound and then you'll realize that you've physically changed your HDD and that there was a reason the label on the HDD said "WARNING: REMOVAL OF LABEL, COVER OR TOP SCREWS VOIDS WARRANTY ID"

While I think you'll be able to get the screws back on firmly enough, the HDD will never be the same since you've popped the screws from the glue.

#2: Only AFTER I had removed all three screws did I notice a stupid error. I accidentally bent one of the arms out of shape. The arm here is supposed to be bent 90 degrees.



I was so focused on getting the screws undone that when I balanced the HDD in a stupid way I didn't notice I was also bending this arm. If I can't bend it back perfectly then the Network Adapter can't be reattached.


There's a risk that I may also have damaged the chips and/or circuitry, since while I was being so rough with removing the screws I accidentally banged the HDD against the furniture at one point. Here's praying that these components weren't damaged.



After all of that, you'd think I could at least power up the HDD? Wrong.

Here is a pic of the power cable inserted (the unused end to the left goes into the IDE-USB adapter, with some force). When everything was inserted the way it was seemingly supposed to, I still couldn't get the HDD to spin up. The problem really is that both ends of the power cable never gives any feedback on when they've been inserted properly, and in particular the larger end is of a massively poor design.

- Observe the silver slots

These slots move about several millimetres as the red, black and yellow cables behind them are moved around. In other words I'm never sure if I've inserted this power cable properly or if one of the slots are misaligned.


So not only have I damaged my HDD but the IDE-USB adapter kit I've bought is looking more and more useless. That's 350 SEK ($36.5 or 32.4 euros) down the drain. There's also another component I bought for 215 SEK but that I didn't realize was incompatible with this scheme, so that's wasted money as well. Unfortunately there's one thing I hate more than wasting money: Trying to return items that I've bought. It takes a lot for me to overcome that stubbornness of mine.



There is at least one person reading this who is considering to use the exact same type of HDD with OPL. Learn from my mistake: Don't order adapters that you *think* might work and don't try to brute force your way into connecting the HDD. Ask an expert instead who actually used a Sony 40GB HDD with OPL and who did so in a non-invasive manner. Once I've collected myself I'll be asking around on the PS2 modding forum for solid advice.


 
In the wastelands in Chapter 2 there is a sign that I pretty much never paid attention to before.



The sign is easy to miss since you are on a moving car while staying focused on the guard hounds. Plus the dull colors of the environment are not exactly helping, particularly when playing on console.

Using hacks I tried to get a clean look at the sign. Increasing brightness and contrast with photoshop this is what I get.



NEXT 60km
WELLCOME TO
(C)ITY CENTER
(ED)GE TOWN

*EDIT: Added JBedford's observation about "CITY CENTER".*

The way that the Japanese misspell "Welcome" seems so prevalent that I'm starting to wonder if it's an intentional meme. :wacky:

What I've transcribed as "TO" looks more "YO", but I'm assuming it looks that way because of how smudged the letters are. Similarly, I wouldn't be surprised if "60km" is in fact "600m", due to how distorted the text is. Also I'm assuming that the full name "EDGE" is meant to be on the sign but that the first two letters got erased. Wouldn't surprise me if the two rows of smaller letters at the bottom are names from the developer staff but I can't make much out with certainty.


Recently I posted my most pointless Dirge of Cerberus video yet. In this one I show that if Vincent reaches the goal point in a mission when the timer reaches zero, Vincent will collapse but then get resurrected and the mission will count as a success.

 
Last edited:
Recently I've been studying the files that each DoC save folder consists of. Here is what I've learned so far, along with some reasonable speculations.

The example is DCFFVII International since I've been studying that one the most: Save folder BISLPM-66629000


Code:
Bytes - File Name

270848 BISLPM-66629000
    64 BISLPM-66629001
  3008 cfg000
   964 icon.sys
 75664 kel.ico
 14256 scene000
 14256 scene001
 14256 scene002
 14256 scene003
 14256 scene004
 14256 scene005
 14256 scene006
 14256 scene007
 14256 scene008
 14256 scene009
 14256 scene010
172280 scr000

Total file size: 679644 bytes

icon.sys & kel.ico
Both these files are unencrypted and identical for each save file of DCFFVII: International that is ever created.
"icon.sys" contains the name of the save file as viewed in the PS2 browser which in this case is DC-FFVII-, although it is stored in a Japanese text table as "DC -FFVII-".
"kel.ico" is the 3D Cerberus model icon used for the save. "kel" is shorthand for "Cerberus".



***FUN FACT: There is actually a kel.ico file on the disc called "kel_hdd.ico". Perhaps this is a 3D icon intended to represent the online-mode data on your PS2's hard disk drive? Or perhaps it was intended for a file that would reduce loading times, same as what exists for the JP version of FFX?
Unfortunately I have not been able to unlock the graphics of kel_hdd.ico for viewing.***


All other files in the save folder are encrypted using a variation of our good ol' friend the T4-encryption. I have not completely reverse-engineered it yet but it looks simple enough. Some save data files in our study *might* not be using the exact same encryption-decryption algorithm as cfg000 but on first impressions they look identical.


cfg000
Manages the settings of the configuration menu (buttons, camera settings etc), indicates if a Tempsave does- or does not exist plus manages all the Extra Features (and by extension all the capsules).

I have actively observed cfg000 in RAM and mapped a great deal of which bits are responsible for which aspect of the game. Typically cfg000 exists in the RAM in an unencrypted state. Only when a change happens, like changing a button configuration or shooting a Memory Capsule, will cfg000 become briefly encrypted in RAM and then decrypted again. Definitely the easiest of all these save data files to observe and map thus far.

Mapping example:
In offset 0xAB0 of cfg000, these are the Extra Features that each individual bit in the byte unlock.
Code:
7th bit - Character Viewer: Omega
6th bit - Character Viewer: Tsviets
5th bit - Character Viewer: Shinra
4th bit - Character Viewer: Bosses
3rd bit - Character Viewer: Deepground
2nd bit - Character Viewer: Monsters
1st bit - Character Viewer: The WRO
0th bit - Character Viewer: Vincent
cfg000, and all other files that are typically in an encrypted state on the memory card, employ what I'm going to refer to as a "checksum". The algorithm in cfg000 is simple: In its unencrypted state, the value of every 4th byte is added. The sum of this value is pasted onto the very end of the cfg000 file. If the calculated checksum value doesn't match the value pasted onto the end of the file, you will get an error message in the main Dirge of Cerberus menu that reads "Load failed. It is possible that some data files may have been corrupted."

I tested making an "unauthorized" change to cfg000 but without updating the checksum and this unlocked the error message. However upon making a normal change in cfg000 (changing a button configuration) the file seemed to repair itself. Since cfg000 is the only file here I've studied in its unencrypted state I have not confirmed if every file uses the exact same "add value of every 4th byte" check.


scene000 - scene010
Each scene0XX file is divided into six regions, each region being 2376 bytes large. Each region of 2376 bytes represent one of the checkpoints in the story mode (i.e. the "Single Player" mode). I have to assume then that each region stores the current data like Vincent's stats, equipment, the results of the "64 Global Flag Addresses", time stamp of checkpoint progression etc.

When a fresh Dirge of Cerberus playthrough starts, each region of all eleven scene0XX files are identical. I do not know what this template contains, if anything. This naturally changes as you progress through the game and each corresponding 2376-bytes-region gets updated.

If you extract the text for the checkpoint menu, you will find a few unused checkpoints under the placeholder name "Something:Somewhere".

0: Prologue - Meteorfall:Midgar
0:Chapter 1 - A City Under Ambush:Kalm
0:Chapter 1 - The Flames of Kalm:Kalm
0:Chapter 1 - A Place of Meeting:Kalm
0:Chapter 1 - The WRO:Kalm
0:Chapter 1 - Battle in the Courtyard:Kalm
0:Chapter 1 - Something:Somewhere
1:Chapter 2 - Westland:Wastelands
1:Chapter 2 - Starving Beasts:Wastelands
1:Chapter 2 - Swarming Beasts:Wastelands
1:Chapter 2 - Over the Wastes:Wastelands
1:Chapter 2 - Riders on the Storm:Wastelands
1:Chapter 2 - Something:Somewhere
2:Chapter 3 - A Silent City:Edge
2:Chapter 3 - Little Survivor:Edge
2:Chapter 3 - Warehouse on the Edge:Edge
2:Chapter 3 - Armored Concerto:Edge
3:Chapter 4 - Prelude to Mayhem:WRO Headquarters
3:Chapter 4 - WRO Assault:WRO Headquarters
3:Chapter 4 - Shelke:WRO Headquarters
3:Chapter 4 - Azul the Cerulean:WRO Headquarters
3:Chapter 4 - Something:Somewhere
4:Chapter 5 - From the Eldritch Depths:Nibelheim Sewers
4:Chapter 5 - Solid Cait:Mako Reactor 0
4:Chapter 5 - A Manor Unchanged:Shinra Manor
4:Chapter 5 - Rosso the Crimson:Shinra Manor
4:Chapter 5 - Something:Somewhere
5:Chapter 6 - The Single Rose of Wutai:Shadowfox
5:Chapter 6 - Season of Survival:Mountain Pass
5:Chapter 6 - Beyond Repair:WRO Headquarters
5:Chapter 6 - Beneath the Pain:WRO Headquarters
5:Chapter 6 - Something:Somewhere
6:Chapter 7 - Shera in the Clouds:The Shera
6:Chapter 7 - Calm Before the Storm:The Shera
6:Chapter 7 - Something:Somewhere
7:Chapter 8 - Cemetery of Steel:Train Graveyard
7:Chapter 8 - The Trainyard:Train Graveyard
7:Chapter 8 - Visitors from Above:Train Graveyard
7:Chapter 8 - Spiraling Tower:Central Complex
7:Chapter 8 - Warzone:Central Complex
7:Chapter 8 - Crimson Shockwave:Central Complex
8:Chapter 9 - An Omen of Chaos:Shinra Building
8:Chapter 9 - Footsteps to Darkness:Shinra Building
8:Chapter 9 - Twins:Shinra Building
8:Chapter 9 - Party of Three:Shinra Building
8:Chapter 9 - Cerulean Abyss:Shinra Building - C Lift
9:Chapter 10 - A Daily Dose of Death: Deepground
9:Chapter 10 - Substation: Deepground
9:Chapter 10 - Possession: Deepground
9:Chapter 10 - Lure of the Shadows: Deepground
9:Chapter 10 - Nero the Sable: Deepground
9:Chapter 10 - Something:Somewhere
10:Chapter 11 - The Beginning:Mako Reactor 0
10:Chapter 11 - Encircling Doom:Mako Reactor 0
10:Chapter 11 - Aerial Beasts:Mako Reactor 0
10:Chapter 11 - Weiss's Secret:Mako Reactor 0
10:Chapter 11 - Weiss's Pulse:Mako Reactor 0
10:Chapter 11 - Chaos Rising:Mako Reactor 0
11:Final Chapter - Omega Awakes:Mako Reactor 0
11:Final Chapter - Advent Chaos:Midgar
11:Final Chapter - Innerspace:Inside Omega
11:Final Chapter - The Last Movement: Omega
11:Final Chapter - A Finale Chaotic: Omega
11:Final Chapter - Zenith:Memory Fragments

Much to my pleasure, these unused checkpoints line up with unused regions of the scene0XX files.

Code:
Checkpoint - scene0XX file - File Region

Ch1-1    scene000    Region1
Ch1-2    scene000    Region2
Ch1-3    scene000    Region3
Ch1-4    scene000    Region4
Ch1-5    scene000    Region5
Ch1-6    scene000    Region6
         scene001    Region1 *UNUSED*
Ch2-1    scene001    Region2
Ch2-2    scene001    Region3
Ch2-3    scene001    Region4
Ch2-4    scene001    Region5
Ch2-5    scene001    Region6
         scene002    Region1 *UNUSED*
Ch3-1    scene002    Region2
Ch3-2    scene002    Region3
Ch3-3    scene002    Region4
Ch3-4    scene002    Region5
Ch4-1    scene002    Region6
Ch4-2    scene003    Region1
Ch4-3    scene003    Region2
Ch4-4    scene003    Region3
         scene003    Region4 *UNUSED*
Ch5-1    scene003    Region5
Ch5-2    scene003    Region6
Ch5-3    scene004    Region1
Ch5-4    scene004    Region2
         scene004    Region3 *UNUSED*
Ch6-1    scene004    Region4
Ch6-2    scene004    Region5
Ch6-3    scene004    Region6
Ch6-4    scene005    Region1
         scene005    Region2 *UNUSED*
Ch7-1    scene005    Region3
Ch7-2    scene005    Region4
         scene005    Region5 *UNUSED*
Ch8-1    scene005    Region6
Ch8-2    scene006    Region1
Ch8-3    scene006    Region2
Ch8-4    scene006    Region3
Ch8-5    scene006    Region4
Ch8-6    scene006    Region5
Ch9-1    scene006    Region6
Ch9-2    scene007    Region1
Ch9-3    scene007    Region2
Ch9-4    scene007    Region3
Ch9-5    scene007    Region4
Ch10-1   scene007    Region5
Ch10-2   scene007    Region6
Ch10-3   scene008    Region1
Ch10-4   scene008    Region2
Ch10-5   scene008    Region3
         scene008    Region4 *UNUSED*
Ch11-1   scene008    Region5
Ch11-2   scene008    Region6
Ch11-3   scene009    Region1
Ch11-4   scene009    Region2
Ch11-5   scene009    Region3
Ch11-6   scene009    Region4
Ch12-1   scene009    Region5
Ch12-2   scene009    Region6
Ch12-3   scene010    Region1
Ch12-4   scene010    Region2
Ch12-5   scene010    Region3
Ch12-6   scene010    Region4
Region1 of scene000 (Checkpoint 1-1) remains untouched throughout your whole playthrough. Either this one is also unused or it's a template for the equipment and stats Vincent start off with in a Normal- and Hard playthrough.

Post-JORG there is no longer a Ch12-6 checkpoint to be accessed in the menu, but as I noticed it was still updated in DCFFVII: International when you beat the final boss I'm speculating that this is the region used to determine what equipment is granted to you in Ex Hard (New Game+) and what equipment you have for the Extra Missions.

Region5 and Region6 of scene010 are completely unused and don't even have corresponding, unused checkpoint text entries.


BISLPM-66629000 & scr000
These rather large files are only changed when a Tempsave is created. Going by the name alone, it would make sense if "scr000" represents the screenshot that is taken for each Tempsave.

Each of these two files have some series of bytes that are unique to each new save of Dirge of Cerberus. This may just be a time stamp or some other unique identifier.

Perhaps of greatest interest is the fact that even when you have "used up" a Tempsave and assume it to be destroyed, BISLPM-66629000 and scr000 remain unchanged! The only thing that changes is the boolean indicator in cfg000 that asks if a Tempsave exists or not. In other words it should be easy to restore your last tempsave indefinitely but I have not actually tested this out yet.


BISLPM-66629001
Like the two files described earlier this one also has a unique series of bytes for each save. Same as earlier, this may just be a "time of creation" stamp or some other identifier.



And that's roughly the state of the research right now. The next step is to fully reverse-engineer the T4-encryption used for cfg000 and write a program so I can play around with editing all the values correctly without having to play the game. Because I'm incredibly lazy when it comes to actual programming this day will come later rather than sooner but it is definitely a project of an acceptable difficulty level.
 
Last edited:

I have written a proof-of-concept, command line version of a Dirge of Cerberus save editor. I am calling it "McDirge".


The program works by having a cfg000 file in the appropriate folder. This file is decoded (and a copy of this decoded version is created) and then you get to enter the values at the addresses of your choosing. When you don't want to change any more values the file is re-encoded and the program exits.

Naturally this is not a user-friendly application, since you need the full list of which offset does what and which values will have a particular result. I'll write some more about that in my next post.


Here is my C++ code. The environment I work in is Code::Blocks, using a GNU Compiler with the compiler flag set to C++11 though I'm pretty sure C++14 works just as well.

Code:
///WELCOME TO MCDIRGE: COMMAND LINE EDITION VERSION 0.1
///Currently only tested and confirmed with file 'cfg000'

#include <iostream>
#include <fstream>

using namespace std;


///DECLARING THE KEY BLOCKS IN GLOBAL SPACE TO BE AVAILABLE EVERYWHERE

uint8_t KeyBlocksArray[32][8] =
{
{0x45, 0x48, 0x79, 0xEC, 0x35, 0x82, 0x1B, 0xC6},
{0x59, 0x69, 0x5E, 0x9E, 0x0D, 0x8B, 0x89, 0xDE},
{0xBD, 0x0E, 0xD8, 0x17, 0x44, 0xB7, 0xAF, 0x58},
{0xB1, 0x49, 0x38, 0x77, 0x54, 0x94, 0x6E, 0xBB},
{0x75, 0x70, 0x19, 0x54, 0xA6, 0xE5, 0x28, 0xA9},
{0x49, 0x32, 0x7F, 0xA4, 0x3F, 0x7C, 0xCC, 0x4D},
{0x6D, 0xFB, 0x7B, 0x36, 0x3E, 0x6D, 0xFE, 0x84},
{0x21, 0xE9, 0x6B, 0x10, 0x37, 0x22, 0xF8, 0x98},
{0xA5, 0x8D, 0x1B, 0x52, 0x13, 0xAB, 0xD8, 0xFC},
{0x39, 0xC4, 0x89, 0x9A, 0x60, 0x57, 0x3B, 0xF0},
{0x1D, 0xD5, 0xB0, 0x04, 0xE3, 0xB4, 0x28, 0xB1},
{0x91, 0x29, 0x74, 0x17, 0x6F, 0x88, 0xCB, 0x75},
{0xD5, 0xCF, 0x44, 0x75, 0x2B, 0xAA, 0xF9, 0x4C},
{0x29, 0x0F, 0x58, 0x4A, 0xD9, 0x52, 0xE0, 0x80},
{0xCD, 0x4B, 0xB8, 0x73, 0x3E, 0x9E, 0x61, 0x84},
{0x01, 0x7B, 0x99, 0x42, 0x38, 0x17, 0xE8, 0x95},
{0x05, 0x67, 0xFF, 0x4C, 0x19, 0x74, 0x88, 0xED},
{0x19, 0x03, 0xFD, 0x80, 0x7E, 0x44, 0xAA, 0xA3},
{0x7D, 0x0F, 0xF1, 0x84, 0x78, 0x56, 0x53, 0x32},
{0x71, 0x4D, 0xB5, 0x98, 0x5A, 0xB0, 0xA0, 0xFB},
{0x35, 0x83, 0x8A, 0xFB, 0xC4, 0x71, 0x23, 0xEA},
{0x09, 0x90, 0xB4, 0xE9, 0xD8, 0x38, 0xB1, 0x92},
{0x2D, 0xD0, 0x86, 0x90, 0x3C, 0x1C, 0x76, 0xDD},
{0xE1, 0x10, 0xA2, 0xD2, 0x2E, 0x8D, 0x4E, 0x53},
{0x65, 0x54, 0x2A, 0x1D, 0xEA, 0xC1, 0x88, 0xA0},
{0xF9, 0xA5, 0xD3, 0x91, 0x92, 0xC9, 0xAB, 0x22},
{0xDD, 0x3D, 0x22, 0xD9, 0xDC, 0xEF, 0x5A, 0xAD},
{0x51, 0x35, 0xAB, 0x3D, 0x50, 0xAF, 0xC6, 0x62},
{0x95, 0x0A, 0x58, 0x34, 0x91, 0x6C, 0xE1, 0xED},
{0xE9, 0x34, 0xB8, 0x05, 0xD6, 0x1E, 0x67, 0xA5},
{0x8D, 0x08, 0x99, 0x1C, 0x2E, 0x9A, 0x03, 0x3B},
{0xC1, 0x2A, 0xFD, 0x8E, 0xE6, 0x02, 0x12, 0x27},
};


///Prototyping smaller functions.
uint32_t LittleEndianToBigEndian (char Byte1, char Byte2, char Byte3, char Byte4);
uint32_t LittleEndianToBigEndian_unsignedchar (uint8_t Byte1, uint8_t Byte2, uint8_t Byte3, uint8_t Byte4);


///DECODER
void OpenDecodeAndCopyFile (string Filename)
{


///OPENING ENCODED FILE AND COPYING CONTENTS INTO EncodeToDecodeMemBlock
    streampos size;
    char *EncodeToDecodeMemBlock;

    ifstream ReadingEncodedFile;
    ReadingEncodedFile.open (Filename, ios::in | ios::binary | ios::ate);
    size = ReadingEncodedFile.tellg();
    ReadingEncodedFile.seekg(0, ios::beg);
    EncodeToDecodeMemBlock = new char [size];
    ReadingEncodedFile.read (EncodeToDecodeMemBlock, size);
    ReadingEncodedFile.close();

///CONTENTS ARE NOW COPIED ONTO EncodeToDecodeMemBlock

    cout << std::hex << std::uppercase << "All 0x" << size << " bytes of " << Filename << " are now in the memory block.\n" << endl;


///DECODING THE ENCODED INFORMATION NOW IN EncodeToDecodeMemBlock

    static uint32_t ByteCounter, BlockCounter, KeyBlockCtr;
    static uint32_t Gear1, Gear2;
    static uint32_t TBlockA, TBlockB, KBlockA, KBlockB;
    static bool CarryFlag1, CarryFlag2;
    static uint8_t IntermediateCarrier;
    static uint8_t OldMemblockValue;



///OUTERMOST LOOP OF THE DECODER

for ( ; ByteCounter < size; BlockCounter++, KeyBlockCtr++)
    {

        if(KeyBlockCtr > 31)
            KeyBlockCtr = 0;

    Gear1 = (ByteCounter << 0x14) | (ByteCounter << 0x0A) | ByteCounter;
        if (Gear1 > ~0xA1652347)
            CarryFlag1 = 1;
        else
            CarryFlag1 = 0;
    Gear1 = Gear1 + 0xA1652347;
    Gear2 = BlockCounter*2+CarryFlag1;


///THE INNER LOOP OF THE DECODER

    for(int iterate(0), BlockwiseByteCounter(0); BlockwiseByteCounter < 8; )
    {
        if(iterate==0 && BlockwiseByteCounter==0)
            {
            OldMemblockValue = EncodeToDecodeMemBlock[ByteCounter];
            EncodeToDecodeMemBlock[ByteCounter] = 0x45 ^ BlockCounter ^ EncodeToDecodeMemBlock[ByteCounter];
            iterate++;
            }
        else if(iterate==0 && BlockwiseByteCounter < 8)
            {
            IntermediateCarrier = EncodeToDecodeMemBlock[ByteCounter] ^ OldMemblockValue;
            OldMemblockValue = EncodeToDecodeMemBlock[ByteCounter];
            EncodeToDecodeMemBlock[ByteCounter] = IntermediateCarrier;
            iterate++;
            }
        else if(iterate < 9 && BlockwiseByteCounter < 8)
            {EncodeToDecodeMemBlock[ByteCounter] = 0x78 + EncodeToDecodeMemBlock[ByteCounter] - KeyBlocksArray[KeyBlockCtr][iterate-1];
            iterate++;}
        else if(iterate==9)
            {iterate = 0;
            ByteCounter++;
            BlockwiseByteCounter++;}
    }
///EXITING THE INNER LOOP OF THE DECOER


///RESUMING THE OUTER LOOP

    ByteCounter -=8;

    TBlockA = LittleEndianToBigEndian (EncodeToDecodeMemBlock[ByteCounter], EncodeToDecodeMemBlock[ByteCounter+1], EncodeToDecodeMemBlock[ByteCounter+2], EncodeToDecodeMemBlock[ByteCounter+3]);
    TBlockB = LittleEndianToBigEndian (EncodeToDecodeMemBlock[ByteCounter+4], EncodeToDecodeMemBlock[ByteCounter+5], EncodeToDecodeMemBlock[ByteCounter+6], EncodeToDecodeMemBlock[ByteCounter+7]);

    KBlockA = LittleEndianToBigEndian_unsignedchar (KeyBlocksArray[KeyBlockCtr][0], KeyBlocksArray[KeyBlockCtr][1], KeyBlocksArray[KeyBlockCtr][2], KeyBlocksArray[KeyBlockCtr][3]);
    KBlockB = LittleEndianToBigEndian_unsignedchar (KeyBlocksArray[KeyBlockCtr][4], KeyBlocksArray[KeyBlockCtr][5], KeyBlocksArray[KeyBlockCtr][6], KeyBlocksArray[KeyBlockCtr][7]);

    if (TBlockA < KBlockA)
        CarryFlag2 = 1;
    else
        CarryFlag2 = 0;
    TBlockA = TBlockA - KBlockA;
    TBlockB = TBlockB - KBlockB - CarryFlag2;

    TBlockA = TBlockA ^ Gear1;
    TBlockB = TBlockB ^ Gear2;

    TBlockA = KBlockA ^ TBlockA;
    TBlockB = KBlockB ^ TBlockB;

    EncodeToDecodeMemBlock[ByteCounter] =   (TBlockB & 0x000000FF);
    EncodeToDecodeMemBlock[ByteCounter+1] = (TBlockB & 0x0000FF00) >> 8;
    EncodeToDecodeMemBlock[ByteCounter+2] = (TBlockB & 0x00FF0000) >> 16;
    EncodeToDecodeMemBlock[ByteCounter+3] = (TBlockB & 0xFF000000) >> 24;
    EncodeToDecodeMemBlock[ByteCounter+4] = (TBlockA & 0x000000FF);
    EncodeToDecodeMemBlock[ByteCounter+5] = (TBlockA & 0x0000FF00) >> 8;
    EncodeToDecodeMemBlock[ByteCounter+6] = (TBlockA & 0x00FF0000) >> 16;
    EncodeToDecodeMemBlock[ByteCounter+7] = (TBlockA & 0xFF000000) >> 24;

    ByteCounter +=8;

    }

///EXITING THE OUTER LOOP. cfg000 HAS NOW BEEN FULLY DECODED.

///CREATING A FILE COPY OF THE DECODED INFORMATION FOR USE IN OTHER FUNCTIONS

    string Filecopy = Filename + "_decoded";
    ofstream CopyingDecodedFile;
    CopyingDecodedFile.open (Filecopy, ios::out | ios::trunc | ios::binary);
    CopyingDecodedFile.write (EncodeToDecodeMemBlock, size);
    CopyingDecodedFile.close();
    delete[] EncodeToDecodeMemBlock;

}


///ENCODER

void ChangeValuesAndEncodeFile (string Filename)
{

///USER INPUT: EDIT VALUE OF PARTICULAR ADDRESSES
///ENCODER


///OPENING THE DECODED FILE AND COPYING IT INTO MEMBLOCK
    string Filecopy = Filename + "_decoded";
    char *DecodeToEncodeMemBlock;
    static uint32_t FileAddressToEdit;
    static uint16_t AddressValuetoEdit;
    streampos size;

    ifstream ReadingDecodedFile;
    ReadingDecodedFile.open (Filecopy, ios::in | ios::binary | ios::ate);
    size = ReadingDecodedFile.tellg();
    ReadingDecodedFile.seekg(0, ios::beg);
    DecodeToEncodeMemBlock = new char [size];
    ReadingDecodedFile.read (DecodeToEncodeMemBlock, size);
    ReadingDecodedFile.close();

///THE DECODED DATA IS NOW IN MEMBLOCK

string YesOrNo;

loop:
cout << std::hex << std::uppercase << "\nWhich address do you wish to change the value of?" << endl;
cout << "\t[Enter a hex value in the range of 0x0 to 0x" << size - 9 << "]" << endl;

cin >> std::hex >> FileAddressToEdit;

cout << "What value do you want 0x" << FileAddressToEdit << " to have?" << endl;
cout << "\t[Enter a hex value in the range 0x0 to 0xFF]" << endl;

cin >> std::hex >> AddressValuetoEdit;

DecodeToEncodeMemBlock[FileAddressToEdit] = AddressValuetoEdit;


cout << "\nDo you wish to change another offset? (Y/N)" << endl;
cin >> YesOrNo;
    if (YesOrNo == "Y" || YesOrNo == "y" || YesOrNo == "1") goto loop;


///CHECKSUM CALCULATOR

cout << "Values of the given addresses have been changed. Updating checksum and re-encoding " << Filename << "." << endl;

static uint32_t Checksum, MemBlockConverter;

    for (int iterate(0); iterate < (size-8); iterate+=4)
    {
        MemBlockConverter = DecodeToEncodeMemBlock[iterate];
        if(MemBlockConverter > 0x7F)
            MemBlockConverter = MemBlockConverter & 0x000000FF;
        Checksum = Checksum + MemBlockConverter;
    }
///CHECKSUM CALCULATED


///INSERTING CHECKSUM INTO END PORTION OF FILE

    DecodeToEncodeMemBlock[size-4] = (Checksum & 0x000000FF);
    DecodeToEncodeMemBlock[size-3] = (Checksum & 0x0000FF00) >> 8;
    DecodeToEncodeMemBlock[size-2] = (Checksum & 0x00FF0000) >> 16;
    DecodeToEncodeMemBlock[size-1] = (Checksum & 0xFF000000) >> 24;

///CHECKSUM INSERTED


///ENCODE the file, now that all the changes have been made and the checksum has been updated.

    static uint32_t ByteCounter, BlockCounter, KeyBlockCtr;
    static uint32_t Gear1, Gear2, Gear3;
    static uint32_t TBlockA, TBlockB, KBlockA, KBlockB;
    static bool CarryFlag1, CarryFlag2;
    static uint8_t OldMemblockValue;



///OUTERMOST LOOP OF THE ENCODER

for ( ; ByteCounter < size; BlockCounter++, KeyBlockCtr++)
    {


        if(KeyBlockCtr > 31)
            KeyBlockCtr = 0;

    Gear1 = (ByteCounter << 0x14) | (ByteCounter << 0x0A) | ByteCounter;
        if (Gear1 > ~0xA1652347)
            CarryFlag1 = 1;
        else
            CarryFlag1 = 0;
    Gear1 = Gear1 + 0xA1652347;
    Gear2 = BlockCounter*2+CarryFlag1;

    TBlockB = LittleEndianToBigEndian (DecodeToEncodeMemBlock[ByteCounter], DecodeToEncodeMemBlock[ByteCounter+1], DecodeToEncodeMemBlock[ByteCounter+2], DecodeToEncodeMemBlock[ByteCounter+3]);
    TBlockA = LittleEndianToBigEndian (DecodeToEncodeMemBlock[ByteCounter+4], DecodeToEncodeMemBlock[ByteCounter+5], DecodeToEncodeMemBlock[ByteCounter+6], DecodeToEncodeMemBlock[ByteCounter+7]);

    KBlockA = LittleEndianToBigEndian_unsignedchar (KeyBlocksArray[KeyBlockCtr][0], KeyBlocksArray[KeyBlockCtr][1], KeyBlocksArray[KeyBlockCtr][2], KeyBlocksArray[KeyBlockCtr][3]);
    KBlockB = LittleEndianToBigEndian_unsignedchar (KeyBlocksArray[KeyBlockCtr][4], KeyBlocksArray[KeyBlockCtr][5], KeyBlocksArray[KeyBlockCtr][6], KeyBlocksArray[KeyBlockCtr][7]);

    TBlockB = KBlockB ^ TBlockB;
    TBlockA = KBlockA ^ TBlockA;

    TBlockB = TBlockB ^ Gear2;
    TBlockA = TBlockA ^ Gear1;

    if (TBlockA > ~KBlockA)  ///Reverse of TBlockA < KBlockA from the Decoder.
        CarryFlag2 = 1;
    else
        CarryFlag2 = 0;
    /// /// /// ///

    TBlockB = TBlockB + KBlockB + CarryFlag2;       ///Reversed from subtraction to addition.
    TBlockA = TBlockA + KBlockA;                    ///Reversed from subtraction to addition.



    DecodeToEncodeMemBlock[ByteCounter] =   (TBlockA & 0x000000FF);
    DecodeToEncodeMemBlock[ByteCounter+1] = (TBlockA & 0x0000FF00) >> 8;
    DecodeToEncodeMemBlock[ByteCounter+2] = (TBlockA & 0x00FF0000) >> 16;
    DecodeToEncodeMemBlock[ByteCounter+3] = (TBlockA & 0xFF000000) >> 24;
    DecodeToEncodeMemBlock[ByteCounter+4] = (TBlockB & 0x000000FF);
    DecodeToEncodeMemBlock[ByteCounter+5] = (TBlockB & 0x0000FF00) >> 8;
    DecodeToEncodeMemBlock[ByteCounter+6] = (TBlockB & 0x00FF0000) >> 16;
    DecodeToEncodeMemBlock[ByteCounter+7] = (TBlockB & 0xFF000000) >> 24;



///INNER LOOP OF ENCODER

    for(int iterate(8), BlockwiseByteCounter(0); BlockwiseByteCounter < 8; )
    {
         if(iterate != 0 && BlockwiseByteCounter < 8)
            {DecodeToEncodeMemBlock[ByteCounter] = DecodeToEncodeMemBlock[ByteCounter] + KeyBlocksArray[KeyBlockCtr][iterate-1] - 0x78;
            iterate--;}
         else if(iterate == 0 && BlockwiseByteCounter==0)
            {
            DecodeToEncodeMemBlock[ByteCounter] = 0x45 ^ BlockCounter ^ DecodeToEncodeMemBlock[ByteCounter];
            OldMemblockValue = DecodeToEncodeMemBlock[ByteCounter];
            BlockwiseByteCounter++;
            ByteCounter++;
            iterate = 8;
            }
        else if(iterate == 0 && BlockwiseByteCounter < 8)
            {
            DecodeToEncodeMemBlock[ByteCounter] = DecodeToEncodeMemBlock[ByteCounter] ^ OldMemblockValue;
            OldMemblockValue = DecodeToEncodeMemBlock[ByteCounter];
            iterate = 8;
            BlockwiseByteCounter++;
            ByteCounter++;
            }

    }

///EXITING INNER LOOP OF ENCODER

    }
///EXITING OUTER LOOP

///ENCODING FINISHED



///ENTERING RE-ENCODED DATA INTO THE FILE

    ofstream SavingEncodedFile;
    SavingEncodedFile.open (Filename, ios::out | ios::trunc | ios::binary);
    SavingEncodedFile.write (DecodeToEncodeMemBlock, size);
    SavingEncodedFile.close();
    delete[] DecodeToEncodeMemBlock;

///FINISHED ENTERING RE-ENCODED DATA INTO THE FILE

}





int main()
{

    string YesOrNo;
    string filename;

    cout << "\n Welcome to the prototype of McDirge: The Dirge of Cerberus save editor." << endl;
    cout << " Command line version 0.1\n\t Open file cfg000? <Y/N>" << endl;

    cin >> YesOrNo;

    if (YesOrNo == "N" || YesOrNo == "n" || YesOrNo == "NO" || YesOrNo == "no" || YesOrNo == "0")
        {cout << "\ You have selected to not open cfg000. Exiting program." << endl;
        return 0;}
    else
        {
        filename = "cfg000";
        OpenDecodeAndCopyFile (filename);
        cout << filename << " has now been decoded and a copy named '" << filename << "_decoded' has been created." << endl;
        ChangeValuesAndEncodeFile (filename);
        cout << "\nAll changes have been saved and '" << filename << "' has been re-encoded." << endl;
        cout << " Thank you for using McDirge: The Dirge of Cerberus save editor!\n Exiting program." << endl;
        return 0;
        }

    return 0;
}



///FUNCTIONS FOR BYTE CONVERSION FROM 4-BYTE BLOCKS. FUNCTIONS PROTOTYPED AT THE TOP OF THE PROGRAM.

uint32_t LittleEndianToBigEndian (char Byte1, char Byte2, char Byte3, char Byte4)
{
    static uint32_t BigEndianBlock, ConvertByte4, ConvertByte3, ConvertByte2, ConvertByte1;
    ConvertByte4 = (Byte4 << 24) & 0xFF000000;
    ConvertByte3 = (Byte3 << 16) & 0x00FF0000;
    ConvertByte2 = (Byte2 << 8)  & 0x0000FF00;
    ConvertByte1 =  Byte1       & 0x000000FF;

    BigEndianBlock = ConvertByte4 + ConvertByte3 + ConvertByte2 + ConvertByte1;
    return BigEndianBlock;
}

uint32_t LittleEndianToBigEndian_unsignedchar (uint8_t Byte1, uint8_t Byte2, uint8_t Byte3, uint8_t Byte4)
{
    static uint32_t BigEndianBlock, ConvertByte4, ConvertByte3, ConvertByte2, ConvertByte1;
    ConvertByte4 = Byte4 << 24;
    ConvertByte3 = Byte3 << 16;
    ConvertByte2 = Byte2 << 8;
    ConvertByte1 = Byte1;

    BigEndianBlock = ConvertByte4 + ConvertByte3 + ConvertByte2 + ConvertByte1;
    return BigEndianBlock;
}
 
Last edited:
When I was observing the save file data in RAM, using Cheat Engine, I had not found the proper addresses to make any change of my choosing to save files like cfg000. All I could do was make lists of data changes as you played the game normally.

With McDirge I can go beyond this boundary.


By editing the save file of the memory card I have here unlocked all 46 Extra Missions. Video recorded from my PS2 because I wanted the joy of benefitting from my little "cheat program" on real PS2 hardware.

Normally these missions are unlocked sequentially as you clear each mission, with the first mission being unlocked after you clear the main game. Because I have not cleared the main game in this save file, none of Vincent's equipment has carried over which is why the current inventory is so limited. No doubt, one of the scene0XX files would have to be updated in order to grant Vincent some better equipment.

Notice that each mission lacks a Best Time in the menu. Having all the missions unlocked this way is impossible in normal gameplay. We also spot a bug: Items occupy the Scope slot in the Customization menu (for all three guns, even). This never happens on a normal save file. I experienced this problem with a ton of items, though the Cardkey didn't seem to exhibit this trait. I believe this bug will go away if, once again, the proper scene0XX file gets updated.


I have confirmed that YES, you can actually restore your most recent Tempsave! Even after loading a Tempsave and seemingly deleting it, you can restore it by changing offset 0x4 to have a value of 1 (naturally this only applies to cfg000 in its decrypted state). This tells the game that the Tempsave still exists and so it retrieves data from BISLPM-66629000 and scr000.


Naturally, you can edit other config settings if you know where to look in cfg000.

Offset (in hex) - Feature
0x04 TEMPSAVE Y/N
0x41 Vibration
0x43 Sight Speed
0x44 Camera Speed
0x46 Mouse Speed
0x48 Camera - Vertical
0x49 Camera - Horizontal
0x4A Sight - Vertical
0x4B Sight - Horizontal
0x4C Sound Output
0x4D Subtitles
0x4E Speaker's Name
0x50 Keyboard Usage
0x5A Gamma Adjustment
0x5E Sight Support
0x5F Screen Position: X axis
0x60 Screen Position: Y axis


Observe the option at offset 0x50, "Keyboard Usage". This is how the JORG-exclusive config option was translated but never shown. The choices are translated as well and they read "Chat Only" and "General Controls" respectively.

Since the post-JORG versions never had online multiplayer, the in-game value is always set to "General Controls" (a value of 1) in those versions. Using McDirge I can force the option "Chat Only" (value 0) and confirm that this switch still works in post-JORG: The keyboard becomes unable to control Vincent, since it is now reserved for the chat...which we can't reach.

I have never been so happy to see my keyboard NOT functioning as when I confirmed that the Keyboard Usage switch still works in the post-JORG versions.
 
Last edited:
McDirge now properly works with all the encrypted files in the save folder. In other words it can decode and encode the following files:
BISLPM-66629000​
BISLPM-66629001​
cfg000​
scene000​
scene001​
scene002​
scene003​
scene004​
scene005​
scene006​
scene007​
scene008​
scene009​
scene010​

I am busy mapping what each byte does and indeed this will occupy me for a long, long time.

Offset 0x10 in each region of the scene0XX files determines the preview images and text entry used for a given checkpoint. Remember, each scene0XX file consists of six regions and each region corresponds to a checkpoint.

Changing the value of address 0x10 I can unlock the preview images for the unused checkpoints.



Only the unused checkpoint for Chapter 1 contains this lovely Cait Sith placeholder image. The juxtaposition of Cait Sith's body language and the checkpoint being called "Something:Somewhere" just has me giggling with delight.

Chapters 2, 4, 5, 6, 7 and 10 also have unused checkpoints with a text entry that reads "Something:Somewhere" but all of them simply use the Dirge of Cerberus logo as their placeholder image.



File scene010 contains two regions/checkpoints that have no text entries and their preview images are, unsurprisingly, depictions of polar bears snorting cocaine in a blizzard.




Exclusive to JORG, clearing the game unlocked checkpoint 12-6 which acted as that version's gateway to the Event Viewer. I can finally confirm that in post-JORG the image for checkpoint 12-6 still exists.

 
Trivia (and some speculations) from my time mapping the bytes for cfg000. May post later about scene0XX.


- As described in an earlier post, content in the Extra Features is controlled with bit flags.

Offset 0xAB0 in cfg000:
Code:
7th bit - Character Viewer: Omega
6th bit - Character Viewer: Tsviets
5th bit - Character Viewer: Shinra
4th bit - Character Viewer: Bosses
3rd bit - Character Viewer: Deepground
2nd bit - Character Viewer: Monsters
1st bit - Character Viewer: The WRO
0th bit - Character Viewer: Vincent
The bit flag also controls the corresponding capsule that unlocks the feature. So if you set the 7th bit to 1 and thus unlock Omega in the Character Viewer, the capsule in Extra Mission #44 ("Deepground") is disabled automatically.


- Each cutscene's presence, or lack thereof, in the Event Viewer is controlled via bit flags.
Offset 0xA81 in cfg000:
Code:
7th bit - Rosso in Edge & Scene 1 (Antecedents)
6th bit - More to Come
5th bit - Death of the Dragonfly
4th bit - Return of the Dragonfly
3rd bit - A Cait in Reeve's clothing
2nd bit - Remodeling
1st bit - Enter Shelke
0th bit - Dragonfly Destroyed?
Every Antecedents cutscene share a bit flag with a cutscene from the single player, meaning in this example that you can't unlock "Scene 1" without also unlocking "Rosso in Edge".


- Most memory capsules unlock two cutscenes, but only one of these bit flags also disable the corresponding memory capsule.

So in the case of the memory capsule that unlocks the following cutscenes...
"Enter Shelke"​
"Remodeling"​
...the memory capsule is disabled if you unlock "Enter Shelke", but the capsule remains if you only unlock "Remodeling". In other words you can make it so that you've unlocked the Event Viewer to only about 50% completion, yet have all- or none of the memory capsules disabled.


- Offset 0x4F in cfg000 is ALWAYS set to the value "3". This offset is in a region devoted to the very basic config settings. My speculation is that this is the default setting for how many rows are displayed in the log window (which was also the chat log) in the online mode. See this unused configuration description found in KelStr1:

"Adjusts the maximum number of lines displayed in the log window during battle."​

I have no way to confirm my theory until I find a way to unlock the chat window. It seems less intuitive to me that this description would be referring to the item pick-up "log" that is also present in the single player, plus that one is not limited to three rows.


Additionally, KelStr1 has this unused configuration setting:

Reload
Automatic
Manual
"While set on Automatic, weapons will reload automatically once the magazine is emptied."​

By default, all weapons in the final game reload automatically once the magazine is emptied. I have not found a functional switch in the game to change it to "Manual". The switch may have been removed for the final game or I just haven't looked hard enough.


- Clearing Extra Mission #45 ("Stronghold Impervious") sets the 0th bit in offset 0xAA0 to 1. I HAVE NO IDEA WHAT THIS DOES! Tested a variety of theories but so far I've turned up empty. It is entirely possible that this bit represents an unused switch. Or maybe it's for something obscure like activating an insignificant item case in the mission. I just don't know.


- The bit flags that set Extra Missions to "cleared/not-cleared" and "unlocked/locked" respectively are all very messy, with many unused bits in each byte.

Code:
0xAC9:
7th bit - Mission #35 cleared when bit is set to 1
6th bit - Mission #42 cleared when bit is set to 1
5th bit - UNUSED
4th bit - UNUSED
3rd bit - Mission #04 cleared when bit is set to 1
2nd bit - Mission #14 cleared when bit is set to 1
1st bit - UNUSED
0th bit - Mission #27 cleared when bit is set to 1


0xACA:
7th bit - Mission #26 cleared when bit is set to 1
6th bit - Mission #31 cleared when bit is set to 1
5th bit - UNUSED
4th bit - Mission #43 cleared when bit is set to 1
3rd bit - UNUSED
2nd bit - Mission #12 cleared when bit is set to 1
1st bit - Mission #30 cleared when bit is set to 1
0th bit - Mission #33 cleared when bit is set to 1


0xACB:
7th bit - UNUSED
6th bit - Mission #02 cleared when bit is set to 1
5th bit - Mission #36 cleared when bit is set to 1
4th bit - Mission #15 cleared when bit is set to 1
3rd bit - UNUSED
2nd bit - Mission #39 cleared when bit is set to 1
1st bit - Mission #44 cleared when bit is set to 1
0th bit - Mission #21 cleared when bit is set to 1


0xACC:
7th bit - Mission #29 cleared when bit is set to 1
6th bit - Mission #45 cleared when bit is set to 1
5th bit - UNUSED
4th bit - UNUSED
3rd bit - UNUSED
2nd bit - UNUSED
1st bit - UNUSED
0th bit - UNUSED
We could speculate wildly why this is the case. Is it because the list of bit flags was derived from the online mode which had a ton of more missions? Maybe. Or maybe these bit flags became messy regardless of any online mode origin. Speaking of the online mode...


- The memory capsules from the multiplayer actually set unique bit flags in cfg000!

Code:
0xA95:
7th bit - Set to 1 when online mode capsule in "Front of Mako Reactor" area is shot (z214)
6th bit - Set to 1 when online mode capsule in "Battle Site" is shot (z231)
5th bit - Set to 1 when online mode capsule in "Large Fault" is shot (z233) *Capsule inside house*
4th bit - Set to 1 when online mode capsule in "Large Fault" is shot (z233) *Capsule on rock structure*
3rd bit - UNKNOWN
2nd bit - Set to 1 when online mode capsule in "(Kalm) Church" is shot (z208)
1st bit - UNKNOWN
0th bit - UNKNOWN


0xA96:
7th bit - UNKNOWN
6th bit - Set to 1 when online mode capsule in "Huge Facility" is shot (z230)
5th bit - Set to 1 when online mode capsule in Warehouse is shot (z209)
4th bit - Set to 1 when online mode capsule in Weiss' Throne Room is shot. (z238)
3rd bit - UNKNOWN
2nd bit - Set to 1 when online mode capsule in "Processing Plant" (Deep Labyrinth area) is shot (z220)
1st bit - Set to 1 when online mode capsule in "Plateau" is shot (z235)
0th bit - Set to 1 when online mode capsule in Shinra Manor is shot (z211)
Two memory capsules are unaccounted for here since the maps in which they existed ("City" and "Snowy Mountain") are not present on the game disc. I do not know to what extent that the multiplayer utilized the PS2 memory card.

I find it a bit amusing that these two bytes, already reserved for unlocking the "Antecedents" in the online mode, went unused and instead bit flags for single player cutscenes got to play double duty in the final release.


- The PAL version of Dirge has the exclusive configuration option to set the screen position. While the text for this option exists in the International version, changing the values of the corresponding offsets (0x5F and 0x60) will not change the screen position in that version. I am assuming that the switches for this PAL-specific function were undone.
 
Last edited:
To study the save file data of Dirge is a pathway to many abilities, some considered to be unnatural...... So let's talk about scene0XX: The checkpoint data.

Each scene0XX file copies larger sections of RAM into itself. For example it copies the 64 Global Flag Addresses into offsets 0x80 - 0xBF. What this means is that even bytes which are not relevant for the purposes of checkpoint data are copied, such as Flag 36 that shows which Extra Mission is currently being played. In the same way, the byte that shows whether Vincent is in limit break mode is copied into scene0XX, even though you CAN'T use it (with checkpoints) to forcibly begin gameplay with Vincent in limit break mode.

So in the above example, you may only learn the full truth about the array of bytes pasted into scene0XX by studying the corresponding byte regions in live gameplay. This relationship of gameplay informing save data goes the other way too: By studying the save file data I have finally uncovered the "64 Local Flag Addresses".

Just like the Global Flags, the Local Flags are partially disguised in RAM through a randomly generated XORing table. These flags are primarily a series of booleans, being either on or off depending on whether certain cutscene- and stage mission triggers have been activated or if NPCs have been rescued.

The local flag region is placed at offset 0xC0 - 0xFF (immediately adjacent to the region with the global flags).

Here is a picture showing which offset represents which of these five WRO members in Chapter 8-2. If the value is set to 1, then the WRO member is gone and dead. By changing this value and then resetting the stage you can freely control which members are present here.



Offset 0xC0 shows the current "Story/Gameplay/Stage Mission Progression" (values mirroring what we see in Global Flags 2-12) and offset 0xC1 usually represent bit flags for minor scenes like those in Kalm where residents and WRO members are saved. With these local flags I can trigger almost any cutscene from any point in a given chapter, the only downside (albeit amusing) that this will often lead to cutscenes triggering when models and areas aren't loaded.

One time I triggered a cutscene with Reeve while Vincent was standing next to Cid. This was all fine until the game perspective returned to Vincent's position next to Cid, upon which the area had un-loaded and there was no longer any functional walkmesh to traverse.




By changing the value of offset 0xC1 in Chapter 7 you will immediately trigger the corresponding spoken monologues by a WRO member. Although I didn't uncover any unused lines, it was really cool to have this control over NPC text- and audio.


Unfortunately these local flags appear completely untouched and useless in the context of the Antecedents: I can't use these to unlock any more unseen multiplayer cutscene- or gameplay moments.


Another clear favorite among the local flags is Flag 11 (offset 0xCA in scene0XX). At any point while playing one of the Extra Missions, the mission will instantly count as a victory when I set this flag to value 1. :monster: LOVE IT! This makes my life way easier if ever again I want to clear Extra Missions in quick succession for one experiment or other.


The scene0XX files are just filled with exciting opportunities to learn more about the game. Offsets 0x70 - 0x7F are devoted to eight "Cutscene Switches", although a maximum of seven switches are only ever used. For example in Ch9-5, the final Azul battle (Neo Azul), there were two switches.

01 00 02 00 FF FF FF FF FF FF FF FF FF FF FF FF

"01 00" is switch #1 and "02 00" is switch #2.

If you replace switch #2 with "FF FF", the cutscenes immediately before- and after the Arch Azul battle are skipped. We go pretty much straight from the Neo Azul battle to the Arch Azul showdown, only to then be transported to cutscenes in the Shinra Manor.

Replacing switch #1 with "FF FF" leads to the cutscene before the Neo Azul battle being skipped, however the prompts for gameplay aren't triggered so in the end all we get is a black space with only the basic UI loaded.

Some areas of the game are completely unreliant on these cutscene switches, others have up to seven switches. These always count up from value 1 - 7 in the following manner.

01 00 02 00 03 00 04 00 05 00 06 00 07 00 FF FF

The conclusion, if it wasn't obvious already, is that the proper loading of both gameplay and cutscenes relies on a ridiculous number of flags and switches.


Ending the post here for brevity. There is just way too much exciting stuff in the scene0XX regions.
 
While mapping the bytes in cfg000 for the keyboard settings I found that certain keys are still configured for online-exclusive options. Thanks to KelStr I know what these options would be called if I unlocked them in the config menu(s).

0x2C6 - Say Channel
Keys: Ctrl + S
0x2CA - Shout Channel
Keys: Ctrl + H
0x2CE - Tell Channel
Keys: Ctrl + T
0x2D2 - Group Channel
Keys: Ctrl + G
0x2D6 - Entry Channel
Keys: Ctrl + Y
0x2DA - Team Channel
Keys: Ctrl + M
0x2DE - Reply Channel
Keys: Ctrl + R

"Group Channel" would have been used for communication exclusively with the "Unit" that you belonged to.

As far as official materials go, I have only spotted the "Reply Channel" referenced in the beta manual. Post-beta it appears to have been replaced by the "Shout Channel". A comment on Cloze's blog, during the online mode's final month, refers to Ctrl + R being used for the Tell channel, which doesn't match with any official data.


The opening post of this thread has now been updated with links to highlight posts- and content.

That's the first time in four years that I update the opening post. :monster: Have fun revisiting classic moments and epic content. To think that this thread is over five years old.
 
Top Bottom