Author Topic: [FF7 PC] Worldmap script disassembler and recompiler - Terraform (0.9.0)  (Read 668 times)

mav

  • Crazy poster
  • *
  • Posts: 226
  • Karma: 2
    • View Profile
Terraform - Worldmap script editor for Final Fantasy VII
Version: 0.9.1 / 24.03.2020
 

What it is:

This is as far as I know the first tool that can not only read and extract worldmap scripts from world_*.lgp archive into a human-readable language, but also recompile them back to the LGP after you edited the scripts. So it's basically Makou Reactor (a very early, simple version of it) but for worldmap scripts. What can you do with it? Basically you can edit most of the game behavior that happens on the worldmap, including the behavior of Weapons, interactions with vehicles, all the messages that happen on the worldmap, etc.

For example you can make Ruby not really want to fight you, you can make Diamond Weapon approach Midgar faster (part of my Definitive Edition mod), or you can change the colour of your submarine to gold, or you can even set the lightning to a different time of day. The limit is your imagination (and the FF7 engine of course).

How to get it:

This is currently an ALPHA release, which means it's pretty rough around the edges. It's geared towards more technical folk that aren't afraid of command line and have some programming knowledge.

You can currently download this tool from my GitHub repository: https://github.com/maciej-trebacz/ff7-terraform/ (direct download link)

How to use it:

Please make sure to read the README file as it contains some instructions on how to run and use it.

Also make sure to become familiar with how FF7 World scripts work at Qhimm's wiki page: http://wiki.ffrtt.ru/index.php?title=FF7/WorldMap_Module/Script . I did update it with my recent finding and I'll keep updating it when I discover what the remaining unknown opcodes do.



Let me know what you think and have fun tinkering with the worldmap :).

PS. Please don't judge the Python code quality, the this tool was meant to be a proof of concept from the beginning ;D. Now that it actually does what it was supposed to do I'll start making the source code more readable and making the tool itself easier to use.

PS 2. If you don't want to download the tool itself and set everything up, but you just want to look at the WorldScript code for the game you can download the disassembled scripts HERE. The archive contains three directories with scripts for three world maps - overworld, underworld and snow fields in Great Glacier. The scripts are best viewed using Sublime Text editor with its syntax highlighting turned on.
« Last Edit: 2020-03-25 07:36:29 by mav »

DLPB

  • No life
  • *
  • Posts: 10256
  • Karma: 276
  • The ascension of the ordinary man
    • View Profile
im so glad someone is finally tackling this.  I'll await released tool as python isn't my thing

obesebear

  • Administrator
  • *
  • Posts: 3312
  • Karma: 113
    • View Profile
This is wonderful.  Thank you for tackling this!

NFITC1

  • No life
  • *
  • Posts: 2931
  • Karma: 73
  • I just don't know what went wrong.
    • View Profile
    • WM/PrC Blog
This is great and a LONG needed addition to the set of tools. If you want any help interpreting any undocumented script codes or improving source code readability I'd be happy to offer my services.

mav

  • Crazy poster
  • *
  • Posts: 226
  • Karma: 2
    • View Profile
This is great and a LONG needed addition to the set of tools. If you want any help interpreting any undocumented script codes or improving source code readability I'd be happy to offer my services.

Thanks! I've added a link with the disassembled scripts at the end of the first post if you want to look at them without downloading the tool. I have a flag which adds the raw HEX data above each disassembled line so you can see how the opcodes are created from raw data. There are quite a few that are still unknown, so any input on what is that they do is very welcome. I already found what some of them do and updated the wiki accordingly.

NFITC1

  • No life
  • *
  • Posts: 2931
  • Karma: 73
  • I just don't know what went wrong.
    • View Profile
    • WM/PrC Blog
Awesome! I can't tell you anything definite yet, but here's what little I've found so far:

Code 01B is similar to code 018 (distance to Point) and Code 321 (also currently unknown). It might be a "find midpoint between two points" function, but it doesn't care about the vertical values of either point. This is susceptible to a divide by 0 error. Probably not an issue, but don't call this if the points are directly on the x or z axis.
Code 01A is a valid code, but there's no documentation on it. It looks like it's probably the distance between two points or two models. I'm not sure which.

mav

  • Crazy poster
  • *
  • Posts: 226
  • Karma: 2
    • View Profile
Good analysis. As far as I can tell 01B is used only twice, in the code that determines Emerald Weapon's movement:

Code: [Select]
    WriteTo(TempByte(0), SpecialByte($Random8BitNumber) * 9 >> 8)
    WriteTo(TempByte(3), TempByte(0))
    WriteTo(TempByte(4), TempByte(3) + 1)

    ...

    WriteTo(TempWord(22), Unknown1b(TempByte(3)))
    WriteTo(TempWord(24), Unknown1b(TempByte(4)))
    If TempWord(22) - TempWord(24) >= 128 Then
      WriteTo(TempWord(22), TempWord(22) - 256)
      GoTo @LABEL_3
    EndIf
    If TempWord(24) - TempWord(22) >= 128 Then
      WriteTo(TempWord(24), TempWord(24) - 256)
    EndIf
    @LABEL_3
    WriteTo(TempWord(14), TempWord(8) - 256)
    WriteTo(TempWord(16), TempWord(14) * TempWord(22))
    WriteTo(TempWord(14), 256 - TempWord(14))
    WriteTo(TempWord(18), TempWord(24) * TempWord(14))
    WriteTo(TempWord(20), TempWord(16) + TempWord(18) >> 8)
    SetEntityDirection(TempWord(20))

That's a lot of code just to determine what his direction should be :D. TempByte(0) is a random number between 0 and 9 which determines Emerald's starting location. They are setup in 022_model_30_00 function in wm2.ev.

01A is not used anywhere as far as I can tell.

By the way, I pushed an update to the repo - the parser and decompiler now properly handle Field level ID constants, so it's easier to read code that references them, for example now we get:

Code: [Select]
  If SavemapBit($OwnChocoboStable, 0) Then
    EnterFieldLevel($ChocoboFarm, 1)
    GoTo @LABEL_2
  EndIf

and

Code: [Select]
If SpecialByte($LastFieldID) == $IcicleVillageNorth Then
Previously we had magic numbers in place of $ChocoboFarm and $IcicleVillageNorth constants.

Thanks to codemann8 for figuring a lot of this stuff out and listing all the possible fields that worldmap can reference.
« Last Edit: 2020-03-24 18:09:44 by mav »

NFITC1

  • No life
  • *
  • Posts: 2931
  • Karma: 73
  • I just don't know what went wrong.
    • View Profile
    • WM/PrC Blog
No, 01A is not used which is why I mentioned it. Codes that I find that are valid and unused are more interesting to me than codes that are. :)

I'm still trying to figure out what the format of output these distance codes generate. They make little sense to me. Both 018 and 01B take a single argument and compare it to some preloaded value (between 0 and Fh inclusive) and do some weird comparisons on it.

Code: [Select]
  if ( CurrentActor.X - Destination.X <= 0 )
    v5 = -(CurrentActor.X - Destination.X);
  else
    v5 = CurrentActor.X - Destination.X;
  deltaX = v5;
  if ( v5 >= 24000 )
    deltaX = 48000 - v5;

  if ( CurrentActor.Y - Destination.Y <= 0 )
    deltaY = -(CurrentActor.Y - Destination.Y);
  else
    deltaY = CurrentActor.Y - Destination.Y;

  if ( CurrentActor.Z - Destination.Z <= 0 )
    v3 = -(CurrentActor.Z - Destination.Z);
  else
    v3 = CurrentActor.Z - Destination.Z;
  deltaZ = v3;
  if ( v3 >= 1C000 )
    deltaZ = 38000 - v3;

  return deltaZ + deltaY + deltaX;
That's my best guess, but I'm not sure what that output would tell you. In the context of Emerald Weapon they seem to be some form of circular path and direction finding.

mav

  • Crazy poster
  • *
  • Posts: 226
  • Karma: 2
    • View Profile
It's a longshot, but maybe this opcode is for getting distance from a model to a wall (or to a triangle in the walkmesh)? Because it probably needs to know how far Emerald is from a wall so it doesn't run into walls.
« Last Edit: 2020-03-24 21:13:55 by mav »

NFITC1

  • No life
  • *
  • Posts: 2931
  • Karma: 73
  • I just don't know what went wrong.
    • View Profile
    • WM/PrC Blog
Given the small number of acceptable values they’re more likely to be waypoints that emerald travels from one to another. The code isn’t complex enough to be finding a wall. Coding collision detection is harder than you’d think.

DLPB

  • No life
  • *
  • Posts: 10256
  • Karma: 276
  • The ascension of the ordinary man
    • View Profile
Emerald never runs into a wall at any rate.  Exactly because they wanted to avoid collision detection.