Increasing draw distance in psobb.exe 12513


First off, let me apologize for previously necroing an old thread, i got a little hyper focused, and didnt even think about the last post being from 4 years ago. Whoops!!! Moving on...

I went ahead and patched draw distance for item drops/maseta in psobb.exe, given that the VirtualAddress for it was posted on these forums, 0x005C4099, which just so happens to be PsoBB.exe+1C4099
Using CFF Explorer (or your favorite PE explorer), can see that its in the .text section, which starts at VirtualAddress 0x1000, and has an RawAddress offset of 0x400 in the actuall EXE. Cool. 0x1C4099 - 0x1000 VirtualAddress space start offset + 0x400 RAW file address = 0x1c3499
The data in the EXE is a float 00004843 hex, 200 dec. I udpated that to 0000d243 hex, or 420 decimal.
Item boxes and maseta now show up a little more than twice as far away. great!

I tried to find the default values for NPCs for a while on pioneer2, dropping a maseta next to the npc and moving far enough away for the npc to un-draw. then i would edit ram for the draw distance of the maseta that was right next to the npc until it was be right on the verge of drawing / undrawing, to guage the distance to the npc. then i tried to find that distance in ram. nothing paid off using that method.

so i gave up and moved down to ragol to try monsters, searching for floats between 250 and 350, as it seemed like a good guestimate distance.

i realized that monster draw distance is different per monster, or at least grouped by type. and not all of it is in .text program address space, at least some if not all is in .data!

for example wolf monster in forest is:
RAM - PsoBB.exe+521684, address 0x00921684
this puts it in the .data section of psobb.exe, which has a Virtual Address space at 0x004f8000, and a Raw Address offset 0x004F6C00 in the executable file.
so 521684 - 4f8000 = 29684, +4f6c00 = 520284
The 520284 offset in psobb.exe contains 00009b43 hex, which is 310 decimal, the default draw distance for wolf.

I dont mind spending the time going through and finding each and every monster, but theres got to be some way to at least know the draw distance to look for, otherwise im just hunting around in RAM blind with no target.

Any suggestions? Would very much appreciate any ideas/help/pointers that any of the VERY talented ASM hackers here could offer :)


Staff member
Rather than trying to patch each enemy's draw distance, you should rather patch the function that determines if an enemy should be drawn instead. Then you only need to patch one thing and be done with it.

Use a debugger to see where an enemy's draw distance value is used to find the function for checking to see if an enemy should be visible/drawn (Cheat Engine works just fine for this), then patch it to multiply the value as it's used in that function. (This would let you make a modifier value that adjusts all enemies simultaneously and the same thing we do here.)


yeah, i figured that would be the route it'd end up going when i started down this rabbit hole. i'm assuming you had to JMP out to an "empty" space in the exe to fit the new multiplier ASM? 3 opcodes, assuming static multiplier, yeah?

Oh, any chance you want to share the offset for boxes, or at least its default draw distance so i can find it myself? or is a box an enemy that doesnt move and has a different drop mechanic?

I was also using cheat engine for debugger. i'd seen some of Soly's screenshots that include little snips of all the various addresses collected in his CT file. You guys have all seriously done your research. Im jealous :)

okay, so my ia32 asm is a little rusty (minor edits over the years, nothing major since college 20 years ago).
Debugger has this accessing the address for wolf draw distance:
0051E575 - 8B CE  - mov ecx,esi
0051E577 - 8B 06  - mov eax,[esi]
0051E579 - FF 35 84169200  - push [PsoBB.exe+521684] <<
0051E57F - FF 35 B02EA700  - push [PsoBB.exe+672EB0]
0051E585 - FF 50 20  - call dword ptr [eax+20]


So thats MOVE ecx into esi, then a MOVE of eax into esi? assume the brackets mean something other than "just go ahead and overwrite the move we just did"?

Then we push the wolf draw distance memory address variable (but not its content right? this isnt an indirect ASM call, its direct, right?) and push another address, whose value is 155.0f (curiously half the wolfs draw distance)
finally we jump out to a function at EAX+20, which in this case is at 0xb00280:
PsoBB.exe+700280 - 38 A6 7B0068A4 - cmp [esi-5B97FF85],ah
PsoBB.exe+700286 - 7B 00 - jnp PsoBB.exe+700288
PsoBB.exe+700288 - D0 79 78 - sar byte ptr [ecx+78],1
and so on.

i scrolled QUITE a way, and never did see a RETurn jump. Is that now how its done anymore. CALLs get associated RETs to return to the last pushed stack address? honestly i get REAL lost in that function call underneath this.

i agree multiplying your incoming argument is the easiest way to do it, and im okay with multiplying just by a static x2 or x4 (shame you cant Arithmatic Shift Left a float), but where this code is, its only being fired off for wolves. i tried to back trace the code up to the point where the incoming enemy distance and enemy type were used as arguments/compares, but i got list REAL bad :D

sadly, im just enough out of my league here that i guess i look stupid and dont know where to start.

at this point, i think i'd need some real help understanding whats going on in this section of ASM.

Maybe i should bail on monsters and just try boxes again?

Also, i tried the same approach on the items/meseta draw distance, but nothing ever showed up in cheat engine that accesses that draw distance function. How does THAT even happen?
Last edited:


Staff member
What you're going to need to do is a few things here:

1. Learn more x86 assembly language.
2. Learn how floating point operations work.
3. Modify your client to load an external DLL so that you can JMP or CALL your own code of any length to modify your client.

All that said, I'll show you how our floor item draw distance modifier works.

First we modify the x86 at 5C5267h to call our own adjustFloorItemDraw procedure.


005C5267: 8B 54 24 14        mov         edx,dword ptr [esp+14h]

New C++ DLL code:

NOPSpace(0x05C5267, 0x08);  // This actually puts 8 NOPS in the existing code, it NOPS out the "fld dword ptr [esp+10h]" as well...
addrpatch = ((long)&adjustFloorItemDraw - 0x05C5267) - 5; // Offset between our function and the code we want to patch...
*(unsigned char*)0x05C5267 = 0xE8; // x86 "CALL"
*(long*)0x05C5268 = addrpatch;
// Calculated offset above

This effectively makes that line something along the lines of:

005C5267: E8 XX XX XX XX      call        ephineaDLL.adjustFloorItemDraw

Our adjustFloorItemDraw function is a code of ASM that looks like this:

void __declspec(naked) adjustFloorItemDraw()
	__asm {
		mov edx, [esp + 18h];
		fld dword ptr[drawModifier]; // Ephinea's own value for draw distance
		fld dword ptr[esp + 14h]; // Draw distance
		fmulp st(1), st(0);

FLD loads a floating point into the floating point register st(0), while also moving the current st(0) to st(1) and so on down the line...
FMULP multiplies floating points.

We use the __declspec(naked) to make sure that the C++ compiler doesn't try to modify or save any registers on it's own. Basically, making this a pure code block without any compiler interference like adjusting esp, ebp, pushes, pops, unless we explicitly do so.

Since we used a call for our function, we had to adjust esp by 4 because of pushing the return address to the stack. RET will pop the address and return to where we called from.

Hopefully this is some help to you.

You should be able to make your own procedures for adjusting enemy, object, player item and fade.
Last edited:


1. Yeah, that has become very evident in the last couple of days lol!
2. Also yeah, any of the ASM i actually do understand does not at all include floats.
3. That would eventually be the way to handle it, instead of finding large blocks of NOP to squeeze code into.

At this point, i think im going to concede defeat :( It would have been nice to get at least box / object draw distance hardcoded a little higher, but the amount of learning i am facing versus the level of reward is a bit too much to ask of my time and talent, sadly.

Thank you again for the suggestions and information though! At the VERY least it was illuminating :)


If it serves anything, we have a public DLL project (that is still work in progress).
You could use it so you don't have to make the whole DLL stuff and just add the code soda exemplified....

I might not accept a PR unless you make the stuff similar to changes we already have there, but even then it works for you to practice and mess around, if you are up for it.


I'll certainly take a look! I know that would be the "more right" way to do it, instead of patching around in the exe manually.
Or goodness forbid just cramming it all in the nearest 909090909090909090 NOP block i can find :D lol.

Soda is 100% correct in his assesment though, my ASM skills are....lacking would be generous. Scrublord might be more accurate.

Thank you for the link!

Also, just noting the patch location for item box view. i found inspiration by looking at alan ives old Gamecube code, which has a repeated section of writes ever 0x18 bytes, and then a single write WAAAAY the heck in a different area of ram on the gamecube. tried a few AOB scans with different wildcards, and started narrowing it down. Also of note, you have to pipe/reload the stage for box draw to be affected, i guess its only loaded once since boxes are stationary? and dont rotate like items?

RAM - PsoBB.exe+24E053 - 0064E053 - box / crate view
Default 300 float, 00009643
mod to 800, 00004844
exe address/offset 24d453

RAM - PsoBB.exe+24E007 - 0064E007 - box / crate view - caves specificly?
Default 400 float, 0000c843
mod to 800, 00004844
exe address/offset 24d407

need to test 24d41b as well, but its late, and its been a hell of a day.
Last edited: