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

Pages: [1] 2 3
1
Ugh, wow, I can't believe it was all due to something as silly as running Joy2Key as Admin. I had been running Joy2Key for years without the need for that, so I overlooked that part. I'm guessing this is required here due to FF7.exe being run as admin as well.

To answer the other part, I'm running on Win7 i7-7700K with GeForce GTX 750 Ti, drivers updated within the past month. Vanilla game with Post processing and AMD SmartBloomHDR shader (as that was recommended in a couple other threads)

2
Solved Problems / Issues getting started on playing FF7-PC
« on: 2020-04-07 22:29:30 »
I just got the 1998 PC version of FF7 and I've burned 2 full days just trying to get this working and although I'm nearly there, there are a couple of things I'm unable to figure out.  I'm also using 7th Heaven 2.0 as the launcher (I'm expecting to eventually get into modding, but I'm trying to get the vanilla game up first).  I should also mention that I'm running on Win7, and no, I'm not upgrading.

1) My PS4 controller isn't allowing DPad and L2/R2 buttons as input to the game.  It seems this is a very common problem, I see many many many posts about this and I've tried just about everything suggested in those posts, but to no success.  I'd very much prefer to use Joy2Key as I'm familiar with how to use it.  I do have all the buttons mapped to what FF7 expects from the keyboard (yes, Numpad numbers vs regular numbers) yet it seems like FF7 is trying to read from the Joystick config rather than the keyboard.  I can also verify that the Joy2Key setup is correct as I see text getting typed when I hit buttons (eventually I will change it so it only sends the keystrokes to FF7.exe so I don't have to worry about sending keystrokes to other applications).  Is there any way to disable FF7's joystick detection, it seems like that is wrongfully prioritizing the joystick over keyboard input. Or maybe there is something else I need to do.

2) The sound from the game mutes when the window isn't in focus. How can I change this? I need to be able to switch to chat or OBS but not have the interruption of audio while doing other things.

3) The graphics seem a bit choppy.  I can't quite tell if it's screen tearing or general lag, but this doesn't seem to be very clean, but it's also very slight.

4) There is a black bar on the bottom of the screen, I'm not sure if the top is getting cut off too, but is this normal?  I saw the Sticky on this, but didn't really offer any solutions that solved the issue.

3
#7 I had considered making a walkmesh editor for modifying world map or field map walkable planes, but there were only crickets when I was gauging the interest for it here. I was considering simply making a tool that takes all the triangle vertices and exports it to a universal 3d file (like .obj or .u3d) that you could import it into any generic 3d editing software and modify, but it gets a bit tricky because the game applies certain attributes to each triangle that typical 3d editors don't really have a use for. But coming up with a tool to do so, is doable, but a bunch of work, and I didn't see the value in it with the little interest at the time.

4
Tbh, I've been wanting to create such a program since the dawn of time. The various nuances, from file to file, as I'm sure you're aware of are the reason I've never went down such a path. There is however, already an existing HEX editor, 010 Editor, that can "kinda" do what you've explained. You can define the schema and you can apply it to whatever file you open in the program. It does lack a certain element of "smart" features that make this pattern recognition less flexible and dynamic but it's a start.

5
Scripting and Reverse Engineering / Re: Field IDs
« on: 2019-04-25 22:25:04 »
Hmm, I think I found it. There's a file called "maplist" inside flevel.lgp. I didn't notice it before because it has the same file extension as the ~700 other field files in the same archive (i.e. no extension).
Another thing to note, as I have been primarily looking into PSX game files (not PC or Steam) which doesn't include a flevel.lgp file. How PSX manages this is the actual field map files are physically located on the game disc (or ISO) in order of ID. There is no other table or map list file that exists on PSX, which is why MR hard codes the field IDs. I had posted the same question to Myst6re myself.

6
Tbh, this topic "gauging interest" didn't really give me the large impression it was going to be a hit. I've got a number of projects on my plate so this definitely took the back seat.

7
I believe what i found earlier in the thread is that there are coordinate walkmeshes, that when entered, a script triggers and determines the field map to enter. There is an unknown parameter with a value 1 thru 4 that triggers within a walkmesh, and depending on that parameter it will go to a different area. This part I haven't investigated as to what it is exactly. For instance, the same walkmesh can bring you to the Zolom hung in a tree and also into Mythril Mines, but both have a different parameter tied to it. This you can see earlier in the thread.

8
The field map images are stored within the field map files themselves. Same as how Makou Reactor extracts the background image. The caveat is that any field models that exist, that appear to be part of the background, won't be there, and there's not any good way to display those without a TON of work.

I think I might have just used MR to mass extract all the field map images tbh.

9
Basically, I have a table that I store all known possible map jumps, even including the unreachable scripts as I have no good logical way to disregard them. Then, I create a new group and manually add any map to it, it will show the map I added as a green node (meaning it's now within the group) and it will also auto add red nodes, which are the known jumps that are possible from that map, then with a series of left and right clicks, I can make any of those red nodes green (adding to the group, and then adding more red nodes off that), and also remove nodes that are definitely not possible ways out of the group (at that moment of the game). This process is also the same for specifying whether it's bidirectional or one way.

And yes, the grouping is manually controlled, meant for segmenting it into portions that a walkthrough may have. It's possible, if I keep the groups small enough, that multiple walkthrough authors can utilize this site to show their walkthrough on, they might combine some of these groups into one paragraph, so two node groups would merge and the site would basically combine the enemy bestiary stats and what-not accordingly.

10
That's very cool, here's what I was working on before I put the project on a shelf for now. Mind you, this is a tool I made for myself to manually build graphs, not meant to be public, however, without the password you'll not be able to make changes, but you can view the map groups I have built already. Also, hovering over the nodes will give you the image of the map. It's very much unfinished but a start. Click the groups in the upper right listbox.

http://ff7.codemann8.com/mapgroups.php

11
The only issue I see with a graph like that, and I'm dealing with this same conundrum, is when optional quests come into the picture, and also when you get to the world map and there's a level of openness to it.

In a sense, we're basically describing a 4th dimension to this graph idea, because depending on your GM, the graph will look different. For instance, the inability to revisit certain parts later. This kinda complicates things a bit but not impossible. Perhaps our map consists of nodes and links, both of which have 2 values associated with them, the GM when this is first accessible, and the GM when it is no longer accessible. Nodes of course would be field maps AND WM areas. But also, some of these nodes would have to be split for cases where there are multiple but separate walkmeshes, accessible from different doorways/lines and gateways.

12
That's cool. Yeah, I also posted the summarized script as well near the end of my last post. Really I just wanted to document it generally so anyone could dive in.

But yes, my graph tho, due to its large size, I'm breaking it up into smaller manageable pieces to which it could be displayed on a webpage describing a certain area of the game, for instance, Mythril Mines would be one page. It will show the 4 field maps, all the enemies within the area, the shared attributes of them (so you can equip accordingly) and have a walkthru describing where to go, what to collect, etc.

I've already extracted most of the game base data, now it's just a matter of piecing all of it together in logical fashion, which i currently have the means of doing, just lots of time ahead...making this a rich resource to reference during runs of ANY kind.

You'd probably find it interesting to have a read thru this thread, given your interests. We'd definitely appreciate any findings not yet documented of any type. The one true thing that stands out as an unknown to me is related to DLPBs last post, his upcoming guide to understanding the mechanics of the multithreaded scripts will help me come up with a smart way to determine which scripts are unused/ not reachable, so the graph of maps can be accurate with no false positives.

13
The first question I'd have is where you're getting the text version of these scripts from? I'm assuming these are probably disassembled from ProudClod. The word of caution there is to worry about the lesser known opcodes that have a higher chance of inaccuracies, although i don't know if any of these lesser known opcodes are used for MP, not only lesser known opcodes but also special cases that maybe weren't considered.  It's possible that some of these outputs could have errors, but NFITC would be the one to comment on how confident he is with the accuracy of that output.

It also looks like there are several layers of IFs, but I don't see any closing brackets, which is important because that will determine whether they are nested or sequential.

14
Ok, now that I had a chance to sit down and unfold everything DLPB noted; I figured this out.  That was my initial thought, that these coordinates were defined and executed using WM scripts, however, I think there was some comment somewhere that led me away from searching WM scripts so I eliminated that from my search.

But here it is:

Apparently, and I don't know how THIS part is managed, but there are certain variables that the game maintains for various functionality throughout the WM, called Special Variables.  There are 20 possible variables that can be referenced, most of which are unknown, per the Wiki.  One of these variables stores the field ID that jumped to the WM; this is the "wm" field map, not the field map that jumps to the "wm" field.  This variable was previously unknown on the Wiki, but I have found it to be ID 6, this will be explained later.  There, then, is an opcode that loads up that value and uses it to determine IF and WHERE any coordinate changes should occur.  This check happens every time the WM is loaded.  That's half of what's needed, but important to note.

The other half deals with the actual coordinates that it should move your active entity to.  As DLPB alluded to earlier, it handles this in a rather funky way, but there is a method to it's madness, it actually relates to that world map coordinate image I posted earlier.  DLPB referred to 2 values which are in the EV file (which is where the WM scripts are located), 0x18 and 0x13D6.  0x18 first needs to be multiplied by 0x2000 to get 0x30000 and then added to 0x13D6, coming out to be 0x313D6 or 201686, which is the final destination X coordinate.  DLPB is correct in that they AREN'T stored in 3 or 4-byte chunks, that is because they can't.  In the WM scripts, it is stack-based and the entire WM script file is stored and referenced in increments of 2-bytes, no more and no less.  So, the game designers could've just dealt with status quo and have the WM utilize either a smaller dimension space, or drastically reduce the image quality of the WM imaging.  The workaround was to split the WM into smaller chunks (which we know as meshes) which are previously known as our X and Z coordinate system described in my earlier post with the WM coordinate image.  The 0x18 value, or 24 in decimal, is actually the mesh X coordinate, and it is to be multiplied by 0x2000 because there are 0x2000 pixels per each mesh.  If the entire WM would be restricted to 2-byte coordinates, the entire map would have to fit within an 8x8 section (about the size of the eastern continent).  The WM could theoretically be much much larger (aka better quality), however, there are likely limitations outside stuff that can be referenced inside WM scripts, but definitely something that could be looked into to create a WM HD Mod.  Getting back to DLPB's coordinates, the second number is the number of pixels within that mesh that the active entity should move to.  Putting them together, the 0x18 number will tell the game which mesh it should load (along with some of the surrounding meshes), then the 0x13D6 number tells which pixel location to put the character.

Here's the section of the WM script that pertains the part that transports to world coordinates:

Code: [Select]
00 01 'CLEARs the Stack
1B 01 06 00 'Loads SPECIAL Variable 6 value to the Stack
10 01 02 00 'Adds CONSTANT value of 2 to the Stack (this is Field ID of 2, aka wm1/Kalm)
70 00 'Consumes the 2 previous Stack values, adds boolean value (0 or 1) to the Stack if the 2 values are EQUAL
01 02 00 02 'JUMPs ahead to the next Field ID check (ID 3 @ 0x200 in the WM script) if the previous operation was false (if not equal)

00 01 'CLEARs the Stack
10 01 18 00 'Adds CONSTANT value of 24 to the Stack (this is the mesh X coordinate)
10 01 0D 00 'Adds CONSTANT value of 13 to the Stack (this is the mesh Z coordinate)
08 03 'Consumes the 2 previous Stack values, then SETs the ACTIVE ENTITY's MESH (loads the mesh, and surrounding meshes)

00 01 'CLEARs the Stack
10 01 D6 13 'Adds CONSTANT value of 5078 to the Stack (this is the X coordinate within the mesh)
10 01 20 19 'Adds CONSTANT value of 6432 to the Stack (this is the Z coordinate within the mesh)
09 03 'Consumes the 2 previous Stack values, then SETs the ACTIVE ENTITY's COORDINATES (puts character at coordinates within the current mesh)

00 01 'CLEARs the Stack
10 01 00 00 'Adds CONSTANT value of 0 to the Stack (value 0-255: this is the direction the character is facing, 0 is south)
04 03 'Consumes the previous Stack value, then SETs the ACTIVE ENTITY's DIRECTION (sets the character's direction that it's facing)

00 02 3D 08 'JUMPs ahead to section of the script that is after all the Special Variable Field ID checks (@0x83D)

So, to modify any of these is as simple as tweaking those specific values within the WM scripts, System call On WM Load (This is function type 0, function ID 0, usually the first "valid" entry in the call table).  The actual part of the script that pertains to world coordinate jumping is at 0x364 byte offset relative to the start of the function (0x398 from the start of the entire script section, 0x798 from the start of the entire EV file)

The Kalm example is the most simple example, sometimes some of these are conditional and can do to different coordinates.  Here is a copy of some pseudocode of the WM script as it pertains to transitioning from field map to world map, I got this from DynamixDJ, who got it from someone else.  Some of this I know and can fill in the blanks for, but there's just too much to do, but it should be easy to see the parts requiring modifying, it will take someone a little work to map the below logic to the binary EV file:

Code: [Select]
01d2      IF ((GetSpecial(0006) == #0001)) {
01d9        ActiveEntity.SetMeshCoordsXZ(#0016, #000f)
01df        ActiveEntity.SetCoordsInMeshXZ(#1524, #01bd)
01e3        ActiveEntity.SetDirectionAndFacing(#0000)
01e4        GOTO 083d
  }
01ec      IF ((GetSpecial(0006) == #0002)) {
01f3        ActiveEntity.SetMeshCoordsXZ(#0018, #000d)
01f9        ActiveEntity.SetCoordsInMeshXZ(#13d6, #1920)
01fd        ActiveEntity.SetDirectionAndFacing(#0000)
01fe        GOTO 083d
  }
0206      IF ((GetSpecial(0006) == #0003)) {
020b        IF (Bank0[007e].Bit(1)) {
0210          IF (Bank0[007e].Bit(0)) {
0215            LoadAndInitModel(#0004)
0216            EnterVehicle()
      }
021a          IF (Bank0[007e].Bit(2)) {
021f            LoadAndInitModel(#0013)
0220            EnterVehicle()
      }
0224          IF (Bank0[007e].Bit(3)) {
0229            LoadAndInitModel(#0013)
022a            EnterVehicle()
      }
022e          IF (Bank0[007e].Bit(4)) {
0233            LoadAndInitModel(#0013)
0234            EnterVehicle()
      }
0238          IF (Bank0[007e].Bit(5)) {
023d            LoadAndInitModel(#0013)
023e            EnterVehicle()
      }
0242          IF (Bank0[007e].Bit(6)) {
0247            LoadAndInitModel(#0013)
0248            EnterVehicle()
      }
    }
024e        ActiveEntity.SetMeshCoordsXZ(#001d, #0010)
0254        ActiveEntity.SetCoordsInMeshXZ(#0712, #1d23)
0258        ActiveEntity.SetDirectionAndFacing(#0000)
0259        GOTO 083d
  }
0261      IF ((GetSpecial(0006) == #0004)) {
0268        ActiveEntity.SetMeshCoordsXZ(#001a, #0012)
026e        ActiveEntity.SetCoordsInMeshXZ(#073d, #15ba)
0272        ActiveEntity.SetDirectionAndFacing(#0060)
0273        GOTO 083d
  }
027b      IF ((GetSpecial(0006) == #0005)) {
0282        ActiveEntity.SetMeshCoordsXZ(#0019, #0013)
0288        ActiveEntity.SetCoordsInMeshXZ(#0fdd, #095c)
028c        ActiveEntity.SetDirectionAndFacing(#00e4)
028d        GOTO 083d
  }
0295      IF ((GetSpecial(0006) == #0006)) {
029c        ActiveEntity.SetMeshCoordsXZ(#0018, #0014)
02a2        ActiveEntity.SetCoordsInMeshXZ(#1a1d, #19ff)
02a6        ActiveEntity.SetDirectionAndFacing(#0000)
02a7        GOTO 083d
  }
02af      IF ((GetSpecial(0006) == #0007)) {
02b4        IF (Bank0[007f].Bit(0)) {
02b9          IF (Bank0[007f].Bit(1)) {
02be            LoadAndInitModel(#0006)
02bf            EnterVehicle()
      }
    }
02c5        ActiveEntity.SetMeshCoordsXZ(#0014, #0011)
02cb        ActiveEntity.SetCoordsInMeshXZ(#175d, #1e0e)
02cf        ActiveEntity.SetDirectionAndFacing(#0000)
02d0        GOTO 083d
  }
02d8      IF ((GetSpecial(0006) == #0008)) {
02df        ActiveEntity.SetMeshCoordsXZ(#0014, #0016)
02e5        ActiveEntity.SetCoordsInMeshXZ(#1814, #0d4d)
02e9        ActiveEntity.SetDirectionAndFacing(#0000)
02ea        GOTO 083d
  }
02f2      IF ((GetSpecial(0006) == #0009)) {
02f9        ActiveEntity.SetMeshCoordsXZ(#0018, #0010)
02ff        ActiveEntity.SetCoordsInMeshXZ(#0a8b, #09d1)
0303        ActiveEntity.SetDirectionAndFacing(#0038)
0304        GOTO 083d
  }
030c      IF ((GetSpecial(0006) == #000a)) {
0313        ActiveEntity.SetMeshCoordsXZ(#000f, #0015)
0319        ActiveEntity.SetCoordsInMeshXZ(#1908, #07f1)
031d        ActiveEntity.SetDirectionAndFacing(#0000)
031e        GOTO 083d
  }
0326      IF ((GetSpecial(0006) == #000b)) {
032d        ActiveEntity.SetMeshCoordsXZ(#001a, #0018)
0334        IF ((Bank0_16bit[0000] >= #04ad)) {
033b          ActiveEntity.SetCoordsInMeshXZ(#1a25, #18d8)
033c          GOTO 0344
    }
0343        ActiveEntity.SetCoordsInMeshXZ(#1bd7, #153b)
0347        ActiveEntity.SetDirectionAndFacing(#0000)
0348        GOTO 083d
  }
0350      IF ((GetSpecial(0006) == #000c)) {
0357        ActiveEntity.SetMeshCoordsXZ(#0021, #0011)
035d        ActiveEntity.SetCoordsInMeshXZ(#0f64, #05e8)
0361        ActiveEntity.SetDirectionAndFacing(#0000)
0362        GOTO 083d
  }
036a      IF ((GetSpecial(0006) == #000d)) {
036f        IF (Bank0[007f].Bit(0)) {
0374          IF (Bank0[007f].Bit(1)) {
0379            LoadAndInitModel(#0006)
037a            EnterVehicle()
      }
    }
0380        ActiveEntity.SetMeshCoordsXZ(#0011, #000f)
0386        ActiveEntity.SetCoordsInMeshXZ(#0607, #0cb2)
038a        ActiveEntity.SetDirectionAndFacing(#0000)
038b        GOTO 083d
  }
0393      IF ((GetSpecial(0006) == #000e)) {
039a        ActiveEntity.SetMeshCoordsXZ(#000d, #000e)
03a0        ActiveEntity.SetCoordsInMeshXZ(#1f1d, #1aa5)
03a4        ActiveEntity.SetDirectionAndFacing(#0044)
03a5        GOTO 083d
  }
03ad      IF ((GetSpecial(0006) == #000f)) {
03b4        ActiveEntity.SetMeshCoordsXZ(#000d, #000f)
03ba        ActiveEntity.SetCoordsInMeshXZ(#0a98, #0c93)
03be        ActiveEntity.SetDirectionAndFacing(#00fa)
03bf        GOTO 083d
  }
03c7      IF ((GetSpecial(0006) == #0010)) {
03cc        IF (Bank0[007f].Bit(0)) {
03d1          IF (Bank0[007f].Bit(1)) {
03d6            LoadAndInitModel(#0006)
03d7            EnterVehicle()
      }
    }
03dd        ActiveEntity.SetMeshCoordsXZ(#000e, #0012)
03e3        ActiveEntity.SetCoordsInMeshXZ(#1615, #1e6e)
03e7        ActiveEntity.SetDirectionAndFacing(#0000)
03e8        GOTO 083d
  }
03f0      IF ((GetSpecial(0006) == #0011)) {
03f7        ActiveEntity.SetMeshCoordsXZ(#000d, #0016)
03fd        ActiveEntity.SetCoordsInMeshXZ(#18dc, #117a)
0401        ActiveEntity.SetDirectionAndFacing(#0000)
0402        GOTO 083d
  }
040a      IF ((GetSpecial(0006) == #0012)) {
0411        ActiveEntity.SetMeshCoordsXZ(#000a, #0014)
0417        ActiveEntity.SetCoordsInMeshXZ(#14d9, #1c20)
041b        ActiveEntity.SetDirectionAndFacing(#0000)
041c        GOTO 083d
  }
0424      IF ((GetSpecial(0006) == #0013)) {
042b        ActiveEntity.SetMeshCoordsXZ(#000b, #0010)
0431        ActiveEntity.SetCoordsInMeshXZ(#09f1, #17f0)
0435        ActiveEntity.SetDirectionAndFacing(#0000)
0436        GOTO 083d
  }
043e      IF ((GetSpecial(0006) == #0014)) {
0445        ActiveEntity.SetMeshCoordsXZ(#000a, #000e)
044b        ActiveEntity.SetCoordsInMeshXZ(#0741, #1a88)
044f        ActiveEntity.SetDirectionAndFacing(#0000)
0450        GOTO 083d
  }
0458      IF ((GetSpecial(0006) == #0015)) {
045f        ActiveEntity.SetMeshCoordsXZ(#000c, #0011)
0465        ActiveEntity.SetCoordsInMeshXZ(#0e5d, #094a)
0469        ActiveEntity.SetDirectionAndFacing(#0000)
046a        GOTO 083d
  }
0472      IF ((GetSpecial(0006) == #0016)) {
0479        ActiveEntity.SetMeshCoordsXZ(#000e, #000d)
047f        ActiveEntity.SetCoordsInMeshXZ(#061c, #0ce0)
0483        ActiveEntity.SetDirectionAndFacing(#0000)
0484        GOTO 083d
  }
048c      IF ((GetSpecial(0006) == #0017)) {
0493        ActiveEntity.SetMeshCoordsXZ(#0004, #000a)
0499        ActiveEntity.SetCoordsInMeshXZ(#141b, #1c3f)
049d        ActiveEntity.SetDirectionAndFacing(#0000)
049e        GOTO 083d
  }
04a6      IF ((GetSpecial(0006) == #0018)) {
04ad        ActiveEntity.SetMeshCoordsXZ(#0006, #000f)
04b3        ActiveEntity.SetCoordsInMeshXZ(#0f9f, #14e9)
04b7        ActiveEntity.SetDirectionAndFacing(#00bc)
04b8        GOTO 083d
  }
04c0      IF ((GetSpecial(0006) == #0019)) {
04c7        ActiveEntity.SetMeshCoordsXZ(#0013, #000a)
04cd        ActiveEntity.SetCoordsInMeshXZ(#03c0, #1f72)
04d1        ActiveEntity.SetDirectionAndFacing(#0000)
04d2        GOTO 083d
  }
04da      IF ((GetSpecial(0006) == #001a)) {
04e1        ActiveEntity.SetMeshCoordsXZ(#0013, #0008)
04e7        ActiveEntity.SetCoordsInMeshXZ(#0720, #171b)
04eb        ActiveEntity.SetDirectionAndFacing(#00c0)
04ec        GOTO 083d
  }
04f4      IF ((GetSpecial(0006) == #001b)) {
04fb        ActiveEntity.SetMeshCoordsXZ(#000f, #0008)
0501        ActiveEntity.SetCoordsInMeshXZ(#1817, #1d0b)
0505        ActiveEntity.SetDirectionAndFacing(#0000)
0506        GOTO 083d
  }
050e      IF ((GetSpecial(0006) == #001c)) {
0515        ActiveEntity.SetMeshCoordsXZ(#0011, #0008)
051b        ActiveEntity.SetCoordsInMeshXZ(#1cf4, #10a9)
051f        ActiveEntity.SetDirectionAndFacing(#0060)
0520        GOTO 083d
  }
0528      IF ((GetSpecial(0006) == #001d)) {
052f        ActiveEntity.SetMeshCoordsXZ(#0020, #0001)
0535        ActiveEntity.SetCoordsInMeshXZ(#0477, #16ad)
0539        ActiveEntity.SetDirectionAndFacing(#00e7)
053a        GOTO 083d
  }
0542      IF ((GetSpecial(0006) == #0020)) {
0547        IF (Bank0[007e].Bit(1)) {
054c          IF (Bank0[007e].Bit(0)) {
0551            LoadAndInitModel(#0004)
0552            EnterVehicle()
      }
0556          IF (Bank0[007e].Bit(2)) {
055b            LoadAndInitModel(#0013)
055c            EnterVehicle()
      }
0560          IF (Bank0[007e].Bit(3)) {
0565            LoadAndInitModel(#0013)
0566            EnterVehicle()
      }
056a          IF (Bank0[007e].Bit(4)) {
056f            LoadAndInitModel(#0013)
0570            EnterVehicle()
      }
0574          IF (Bank0[007e].Bit(5)) {
0579            LoadAndInitModel(#0013)
057a            EnterVehicle()
      }
057e          IF (Bank0[007e].Bit(6)) {
0583            LoadAndInitModel(#0013)
0584            EnterVehicle()
      }
    }
058a        ActiveEntity.SetMeshCoordsXZ(GetSpecial(0000), GetSpecial(0001))
0590        ActiveEntity.SetCoordsInMeshXZ(GetSpecial(0002), GetSpecial(0003))
0594        ActiveEntity.SetDirectionAndFacing(GetSpecial(0004))
0595        GOTO 083d
  }
059d      IF ((GetSpecial(0006) == #0021)) {
05a2        IF (Bank0[007f].Bit(0)) {
05a7          IF (Bank0[007f].Bit(1)) {
05ac            LoadAndInitModel(#0006)
05ad            EnterVehicle()
      }
    }
05b3        ActiveEntity.SetMeshCoordsXZ(GetSpecial(0000), GetSpecial(0001))
05b9        ActiveEntity.SetCoordsInMeshXZ(GetSpecial(0002), GetSpecial(0003))
05bd        ActiveEntity.SetDirectionAndFacing(GetSpecial(0004))
05be        GOTO 083d
  }
05c6      IF ((GetSpecial(0006) == #0022)) {
05cb        IF (Bank0[007e].Bit(1)) {
05d0          IF (Bank0[007e].Bit(0)) {
05d5            LoadAndInitModel(#0004)
05d6            EnterVehicle()
      }
05da          IF (Bank0[007e].Bit(2)) {
05df            LoadAndInitModel(#0013)
05e0            EnterVehicle()
      }
05e4          IF (Bank0[007e].Bit(3)) {
05e9            LoadAndInitModel(#0013)
05ea            EnterVehicle()
      }
05ee          IF (Bank0[007e].Bit(4)) {
05f3            LoadAndInitModel(#0013)
05f4            EnterVehicle()
      }
05f8          IF (Bank0[007e].Bit(5)) {
05fd            LoadAndInitModel(#0013)
05fe            EnterVehicle()
      }
0602          IF (Bank0[007e].Bit(6)) {
0607            LoadAndInitModel(#0013)
0608            EnterVehicle()
      }
    }
060e        ActiveEntity.SetMeshCoordsXZ(GetSpecial(0000), GetSpecial(0001))
0614        ActiveEntity.SetCoordsInMeshXZ(GetSpecial(0002), GetSpecial(0003))
0618        ActiveEntity.SetDirectionAndFacing(GetSpecial(0004))
0619        GOTO 083d
  }
0621      IF ((GetSpecial(0006) == #0024)) {
0626        LoadAndInitModel(#0008)
0627        SetCurrentEntityAsPlayerEntity()
0628        GOTO 083d
  }
0630      IF ((GetSpecial(0006) == #0025)) {
0635        LoadAndInitModel(#0008)
0636        SetCurrentEntityAsPlayerEntity()
0637        GOTO 083d
  }
063f      IF ((GetSpecial(0006) == #0026)) {
0644        LoadAndInitModel(#0008)
0645        SetCurrentEntityAsPlayerEntity()
0646        GOTO 083d
  }
064e      IF ((GetSpecial(0006) == #0027)) {
0653        LoadAndInitModel(#0008)
0654        SetCurrentEntityAsPlayerEntity()
0655        GOTO 083d
  }
065d      IF ((GetSpecial(0006) == #0028)) {
0662        IF (Bank0[007f].Bit(2)) {
0667          LoadAndInitModel(#0005)
0668          EnterVehicle()
    }
066e        ActiveEntity.SetMeshCoordsXZ(#0006, #0013)
0674        ActiveEntity.SetCoordsInMeshXZ(#1c3b, #0268)
0678        ActiveEntity.SetDirectionAndFacing(#0000)
0679        GOTO 083d
  }
0681      IF ((GetSpecial(0006) == #0029)) {
0686        IF (Bank0[007f].Bit(4)) {
068b          LoadAndInitModel(#0003)
068c          EnterVehicle()
    }
0692        ActiveEntity.SetMeshCoordsXZ(#0014, #0011)
0698        ActiveEntity.SetCoordsInMeshXZ(#11d1, #18c9)
0699        GOTO 083d
  }
06a1      IF ((GetSpecial(0006) == #002b)) {
06a8        ActiveEntity.SetMeshCoordsXZ(#000b, #0010)
06ae        ActiveEntity.SetCoordsInMeshXZ(#095a, #1074)
06b2        ActiveEntity.SetDirectionAndFacing(#0080)
06b3        GOTO 083d
  }
06bb      IF ((GetSpecial(0006) == #002c)) {
06c2        ActiveEntity.SetMeshCoordsXZ(#000b, #000f)
06c8        ActiveEntity.SetCoordsInMeshXZ(#0f70, #0e98)
06cc        ActiveEntity.SetDirectionAndFacing(#0000)
06cd        GOTO 083d
  }
06d5      IF ((GetSpecial(0006) == #002d)) {
06da        IF (Bank0[007f].Bit(4)) {
06df          IF (Bank0[007f].Bit(5)) {
06e4            IF (Bank0[0385].Bit(7)) {
06e9              LoadAndInitModel(#0013)
06ea              EnterVehicle()
        }
06ee            LoadAndInitModel(#0003)
06ef            EnterVehicle()
06f3            IF (Bank0[0385].Bit(6)) {
06fa              ActiveEntity.SetMeshCoordsXZ(#0010, #0004)
0700              ActiveEntity.SetCoordsInMeshXZ(#0033, #0f8b)
0706              WRITE Bank0[0385].Bit(6) = #0000
        }
      }
    }
0707        GOTO 083d
  }
070f      IF ((GetSpecial(0006) == #002e)) {
0716        ActiveEntity.SetMeshCoordsXZ(#000a, #0010)
071c        ActiveEntity.SetCoordsInMeshXZ(#1707, #07e3)
0720        ActiveEntity.SetDirectionAndFacing(#00e8)
0721        GOTO 083d
  }
0729      IF ((GetSpecial(0006) == #002f)) {
0730        ActiveEntity.SetMeshCoordsXZ(#000f, #0008)
0736        ActiveEntity.SetCoordsInMeshXZ(#182b, #161f)
073a        ActiveEntity.SetDirectionAndFacing(#0080)
073b        GOTO 083d
  }
0743      IF ((GetSpecial(0006) == #0030)) {
074a        ActiveEntity.SetMeshCoordsXZ(#0010, #0006)
0750        ActiveEntity.SetCoordsInMeshXZ(#13d9, #1420)
0754        ActiveEntity.SetDirectionAndFacing(#00e3)
0755        GOTO 083d
  }
075d      IF ((GetSpecial(0006) == #0031)) {
0768        Op319(((GetSpecial(0007) & #00fc) | #0002))
076e        ActiveEntity.SetMeshCoordsXZ(#000a, #000e)
0774        ActiveEntity.SetCoordsInMeshXZ(#0a37, #0fc1)
0778        ActiveEntity.SetDirectionAndFacing(#0080)
0779        GOTO 083d
  }
0781      IF ((GetSpecial(0006) == #0033)) {
0786        IF (Bank0[007f].Bit(4)) {
078b          LoadAndInitModel(#0003)
078c          EnterVehicle()
0790          LoadAndInitModel(#000a)
    }
0791        GOTO 083d
  }
0799      IF ((GetSpecial(0006) == #0035)) {
07a0        ActiveEntity.SetMeshCoordsXZ(GetSpecial(0000), GetSpecial(0001))
07a6        ActiveEntity.SetCoordsInMeshXZ(GetSpecial(0002), GetSpecial(0003))
07aa        ActiveEntity.SetDirectionAndFacing(GetSpecial(0004))
07ab        GOTO 083d
  }
07b3      IF ((GetSpecial(0006) == #0036)) {
07b8        IF (Bank0[0352].Bit(2)) {
07bd          LoadAndInitModel(#000d)
07be          EnterVehicle()
    }
07c4        ActiveEntity.SetMeshCoordsXZ(#0014, #0011)
07ca        ActiveEntity.SetCoordsInMeshXZ(#0fe1, #1880)
07ce        ActiveEntity.SetDirectionAndFacing(#00c0)
07cf        GOTO 083d
  }
07d7      IF ((GetSpecial(0006) == #0037)) {
07de        ActiveEntity.SetMeshCoordsXZ(#000b, #0016)
07e4        ActiveEntity.SetCoordsInMeshXZ(#0b50, #0247)
07e8        ActiveEntity.SetDirectionAndFacing(#0000)
07e9        GOTO 083d
  }
07f1      IF ((GetSpecial(0006) == #0039)) {
07f8        ActiveEntity.SetMeshCoordsXZ(#0013, #000a)
07fe        ActiveEntity.SetCoordsInMeshXZ(#1d13, #0f0c)
0802        ActiveEntity.SetDirectionAndFacing(#0080)
0803        GOTO 083d
  }
080b      IF ((GetSpecial(0006) == #003a)) {
0812        ActiveEntity.SetMeshCoordsXZ(#0013, #000a)
0818        ActiveEntity.SetCoordsInMeshXZ(#19f2, #00f9)
081c        ActiveEntity.SetDirectionAndFacing(#0019)
081d        GOTO 083d
  }
0825      IF ((GetSpecial(0006) == #003b)) {
082a        IF (Bank0[007f].Bit(4)) {
082f          LoadAndInitModel(#0003)
0830          EnterVehicle()
0836          ActiveEntity.SetMeshCoordsXZ(#0010, #0004)
083c          ActiveEntity.SetCoordsInMeshXZ(#0033, #0f8b)
    }

15
FF7 Tools / Re: FFVII Enemy Database & Calculator V1.0.0
« on: 2019-02-19 20:06:16 »
You would be a total force of nature if you ever got some coding under your belt. Great work on this!

16
This is where the data is stored. Of course... being that you'll need to use my tool Ochu to get the coords (by leaving each town) and then do the math on each coord and look it up in the event file, it's going to be annoying.
No worries, I have my own tool that sifts thru WM scripts, but really I've already enlisted some help in finding the first three WM coordinates, from there I should be able to spot a pattern. The way I have my code set up, it's easy to extract data from these scripts and feed them into my database.

17
Anyone know what the complication is?  The way I see it, it doesn't seem all that hard to do.  The one thing I'm not too familiar on is how the PC stores the MAP file.  Nothing I'm envisioning involves increasing the size of any files, just simple byte-swapping.  Also, minor OPTIONAL patching of the EXE, but only as it pertains to enabling new terrains to have encounters.

18
<reserved>

19
I'm looking to gauge how much interest there would be in a World Map Walkmesh editor.  If so, I'll modify the naming of this topic appropriately to match the usual convention.

This editor would entail modding some of the things I've uncovered recently and documented in this topic, specifically around changing which terrains have encounters.

This editor will modify:
  • Mesh Triangle Coordinates
  • Adding/removing triangles
  • Texture references and UV mapping
  • Walkmesh statuses (for purposes of vehicle/chocobo fencing...and also for encounter changes
  • WM encounter rates/formations and also which areas/statuses activate encounters
  • All 3 WMs (Overworld, underwater, and snowfield) {Unknown if more can be added}
  • Actual texture imaging (although I don't currently have a working understanding of that yet)
  • WM coordinate references (when leaving field maps and entering the world map) {I don't currently know how this is handled yet, but only a matter of time}
  • Not yet, but possibly the ability to change which map blocks get modified along the way, like the Junon UW crater

20
I found a bit more.  Thanks to both ergonomy_joe and JBedford.  I found the enc_w.bin file within world.bin (after decompressed: offset 0x1D948 size:0x8A0 header:0xA0), which is the file that contains all the encounters on the world map (probability and enemy formations).  The enc_w.bin file contains 64 possible configurations for encounters.  These are divided into 16 different areas on the map (Midgar Area, Nibel Area, etc) indicated by the text that shows up in the MENU.  The text for these 16 areas are first 16 texts that are defined in a file called "mes", which is another file that exists within world.bin (offset:0x1E5F0 size:0x1000) This leaves 4 possible configurations per area, which are divided amongst some of the different terrain types that exist within that area, also known as walkmesh statuses, listed at the bottom of this page in the Wiki.  If you look at the world map walkmesh image I posted earlier (the Overworld link), you'll see a bunch of small triangles, each individual triangle has a walkmesh status associated with it.

This enc_w.bin is not a new file to us, it has been deciphered before, even with notes indicating which walkmesh statuses are the ones that are used for encounters.  This, however, can be found by simple trial and error and manually writing down this information while playing and checking against the available encounter configurations.

I, however, was looking to find how the game knows which walkmesh statuses are valid ones to use and look up in the configurations.  I thought maybe this was information that was in the 0xA0 header of the enc_w.bin file, but that lead to a dead end.  I sent a PM over to JBedford, who told me this had to be determined within the EXE, which for me is the last area of my expertise.  From there, I had a look thru the world map code that was reverse engineered by ergonomy_joe and did indeed find a table (inside his NEWFF7/C_00766B70.cpp) that contained some similar-looking numbers which looked a lot like the common walkmesh status IDs that encounters use.  Since joe's code is based on the PC version of the game, I wanted to find where it could be located in the PSX version.  Since the walkmesh statuses could've been stored a good number of ways (they only take up 5 bits), this would've been very difficult to find on my own, but with joe's code, I could see how the game stored these values, which was in 8-bit segments (leaving 3 unused).  I searched and found it in the PSX version, again in the world.bin file (offset: 0x272B4 size:0x40)

Here is the list, divided in groups of 4 (each area):
Code: [Select]
00 09 00 11 Midgar Area
00 00 00 11 Grasslands Area
00 09 01 11 Junon Area
00 14 00 11 Corel Area
00 09 08 11 Gold Saucer Area
00 00 19 11 Gongaga Area
00 09 13 11 Cosmo Area
00 00 01 11 Nibel Area
00 00 01 11 Rocket Launch Pad Area
00 09 0E 11 Wutai Area
00 09 19 11 Woodlands Area
00 0A 09 11 Icicle Area
00 09 19 11 Mideel Area
00 00 08 0B North Corel Area
00 00 08 00 Cactus Island
00 00 01 00 Goblin Island

One thing to note, every area has a Grass status configuration, which is a walkmesh status ID of 00.  If you look at every area, they all begin with 00.  So the first configuration in each area in enc_w.bin shows you the enemies you'll encounter in the Grass parts.  However, you'll notice that some of the areas contain multiple references to Grass statuses.  I believe the game only uses the first one it finds, and effectively marks any subsequent ones as "unused".  It's unclear, as I haven't tested it, if the game REQUIRES each area to have a Grass status or not.  Either way, if the enc_w.bin Grass configuration for one area is all 00s, that effectively disables encounters for the area anyways.  My thought though is that you could have an area with 4 statuses that AREN'T a Grass status and it would work, but not tested.

Another important thing to note is the Icicle Area, the 3rd status referenced is ID 09, which is a Dirt/Wasteland status.  You'll notice there is no dirt area in the Icicle Area...or is there?  This is the configuration that is used for encounters in the snowfield area in Great Glacier!  Even though it looks like snow, that's just because a different texture ID is used instead of the usual Dirt texture.  They couldn't use the Snow status there because it's already used by the Snow area on the main world map.

So, here is the list of the statuses that are used in each area:
Code: [Select]
00 09 00 11 Midgar Area (Grass, Dirt, <unused>, Beach)
00 00 00 11 Grasslands Area (Grass, <unused>, <unused>, Beach)
00 09 01 11 Junon Area (Grass, Dirt, Forest, Beach)
00 14 00 11 Corel Area (Grass, Mountain Pass, <unused>, Beach)
00 09 08 11 Gold Saucer Area (Grass, Dirt, Desert, Beach)
00 00 19 11 Gongaga Area (Grass, <unused>, Jungle, Beach)
00 09 13 11 Cosmo Area (Grass, Dirt, Canyon, Beach)
00 00 01 11 Nibel Area (Grass, <unused>, Forest, Beach)
00 00 01 11 Rocket Launch Pad Area (Grass, <unused>, Forest, Beach)
00 09 0E 11 Wutai Area (Grass, Dirt, Wutai Bridge, Beach)
00 09 19 11 Woodlands Area (Grass, Dirt, Jungle, Beach)
00 0A 09 11 Icicle Area (Grass, Snow, Snowfield (Dirt), Beach)
00 09 19 11 Mideel Area (Grass, Dirt, Jungle, Beach)
00 00 08 0B North Corel Area (Grass, <unused>, Desert, Riverside)
00 00 08 00 Cactus Island (Grass, <unused>, Desert, <unused>)
00 00 01 00 Goblin Island (Grass, <unused>, Forest, <unused>)

21
Does anyone have any detail on the structure of the world.bin file?

22
Another world map image. I filled in all the triangles with color pertaining to what kind of walkmesh it is. Perhaps someday I'll actually apply the real texture, but for now that's the best I can do.


23
More cool stuff. I created a rather large image of the world map walkmesh wireframe for your viewing pleasure:

I should warn you, it's over 5MB

Overworld

Underwater

24
Right, and my problem is right now that I'm exclusively dealing with PSX at this point. My Steam account has issues currently and won't let me make purchases on it, so I can't get Steam FF7 atm. So if I wanted to get actual coordinates of the drop points for each town, I'd be a huge process and hassle that I'm not willing to do atm.

You're correct tho, the WM coordinates are definitely NOT in the FIELD.TBL file, only the field coordinates are.

25
It sounds like you're looking for something that will start every new game with extra equipment and stats.  Black Chocobo can only modify existing save files to give you the extra stuff you need, which is the easiest approach, but will only affect THAT save file.

If you want it to happen EVERY new game, it's more complicated and you won't find any pre-built tool that does it, but you you'd have to use Makou Reactor and modify the md1stin map, add a new script group in that map, there are codes to increment specific items, materias, and gil.  But like I said, it's both complicated and you won't find anything that does this already, it'd be a completely custom hack.

Pages: [1] 2 3