-
Notifications
You must be signed in to change notification settings - Fork 257
Pilotwings 64 Research & Development
Some of these are confirmed based on strings in the main application. Some are guesses based on the character grouping and logic.
Magic | Description | Notes |
---|---|---|
BIRD | Birdman | |
CB | Cannon Ball | |
HG | Hang Glider | |
HM | Jumble Hopper | |
GC | Gyro Copter | |
RP | Rocket Pack | |
SD | Sky Diver | |
UV | UltraVision | Engine Codename |
ADAT | ASCII (?) Data | See: https://github.com/queueRAM/pilotwings_64/pull/3 |
APTS | Audio Switch Points | |
BALS | Balloons / Balls | |
BNUS | Bonus | Secret Birdman stars in the levels |
BTGT | Ball Target | Missions where you push a ball into destination cylinder with the RP |
CNTG | Cannon Target | |
COMM | Command/Common | |
DATA | Text Data | Strings throughout the game, see: https://github.com/queueRAM/pilotwings_64/pull/3 |
HPAD | Hover Pad | Rocket Pack hovering landing pads |
HOPD | Hopper Destination | |
JPTX | Japan TeXt | String character lookup table? |
LPAD | Landing Pad | |
LSTP | Landing Strip | |
PDAT | Path Data | |
PHDR | Path Header | |
PHTS | Photos | Objects to photograph while in missions with Hang Glider |
PPOS | Path Pose Line | ? |
QUAT | Quaternion | |
RNGS | Rings | |
SPTH | SOMETHING Path | Interpreted as 3 (x,y,z) or 6 (x,y,z, heading, pitch, roll) Hermite splines with different tangent logic. Possibly related to SkyDiver missions and player placement in task. |
STRG | String | |
TABL | FS Table | File lookup table/map in the ROM and housing FORM sizes for each chunk. MIO0 compressed. |
THER | Thermals | Hang Glider lift points |
TPAD | Takeoff Pad | |
TPTS | Terra Switch Points | for warping the player and switching terras on/off (for caves) |
TOYS | Toys | Seems to refer to animated models (like ferris wheel) |
UPWL | PilotWings Level | Pre-mission "stage setup", 4 levels: Holiday Island, Ever-Frost Island, Crescent Island, Little States, has info about sounds, level transitions, and some special models |
UPWT | PilotWings Task | Missions: target/ring/balloon X/Y/Z coordinates, landing pad/strip locations, etc |
UVAN | Animation | |
UVBT | Blit | |
UVCT | Contour | Main terrain geometry |
UVFT | Font Texture | Template? Near STRG marker |
UVEN | Environment | maybe skybox? |
UVLV | UltraVision Level | lists other UVTR,UVMD,UVTX to load |
UVMD | Model | |
UVSQ | UltraVision Sequence | Guess |
UVSX | UltraVision Sound ArXive | Standard N64 .CTL/.TBL audio data(wavetables and ADPCM compressed audio) |
UVSY | UltraVison System | Guess |
UVTR | Terra | Grid of UVCT contours |
UVTX | Texture | |
WOBJ | Wind Objects | Wind socks and wind turbines, which rotate based on the wind |
This is for things like X/Z/Y coordinates of objects/vehicles/etc and other things I've found to be of interest while dumping memory in the PJ64 debugger. Some of these mem locations can be modified in-game ("Live) but some must be modified during or right after DMA ROM read.
I'm fairly confident I have X/Z/Y coordinates correct but please double check and correct me if I reversed X/Z somehow.
Feel free to correct my findings and update/add/remove things as needed. - roto
Memory Address | Data Type | Name | Description/Notes |
---|---|---|---|
80126C64 | data | UVTR First hit | After DMA ROM read |
8018fad8 | data | snow data | pointer to itself, then snow coords (?), then snow pixel indices |
80263780 | data | Dynamic objects | array of dobjs, stride is 0x40, first short is the model ID, followed by indices into the dobj matrix array |
80265080 | data | Dobj matrices | array of floating point 4x4 joint matrices (so stride 0x40) used by dobjs |
80265294 | float | Ball Width | JetPack Level 1 |
802652A8 | float | Ball Height | JetPack Level 1 |
802652B0 | float | Ball / Model X Live | Change position of "current target" live, after ROM read |
802652B4 | float | Ball / Model Z Live | Seems to affect models in Character Select screen too |
802652B8 | float | Ball / Model Y Live | |
80362758 | float | Jetpack Rotation Angle | |
80362788 | float | Vehicle X Live | |
8036278C | float | Vehicle Z Live | |
80362790 | float | Vehicle Y Live | |
8036AAC4 | data | Ring X-Rotate Angle | ROM read, on UPWT load, can't seem to find this in memory after |
8036C6E0 | float | Minimap Target X | |
8036C6E4 | float | Minimap Target Z | |
8036C6E8 | float | Minimap Target Y | |
8036DA79 | data | Ring/Object "Model" | Weird one, change to '01' for a glitched out Hang Glider |
8036DAAC | float | Ring X Live | |
8036DAB0 | float | Ring Z Live | |
8036DAB4 | float | Ring Y Live | |
8036DC0C | data | Ring rotation speed | Change to 41 |
8036DC18 | data | Ring Rotation (Flip) | Change to 78 |
80373ef0 | data | pointer to snow data | |
8037A600 | data | COMM Gyro Level 1 | Temp marker |
8037AA21 | data | Number of Rings? | Gyro 1st Level |
8037AA22 | data | Number of Balloons (objectives/goals?) | JetPack Level 1 |
function names starting uv are taken directly from debug text
RAM address | Name/Signature | Notes |
---|---|---|
205814 | uvSortAdd(int category, float dist, modelPlacement* obj) | appends the given S/Dobj (based on category) to the appropriate list for rendering |
206058 | double uvClkGetSec(int index) | returns the elapsed seconds since a start time indicated by index |
216f70 | uvDobjModel(int index, int modelID) | loads a dynamic object |
221398 | uvGfxStateDraw(uint32 state) | prepares rsp geo mode and rdp other mode for drawing a set of triangles. the lower bytes of state are the texture ID, if any, while the upper bytes get translated into the mode flags |
229270 | axisRotation(transform* mat, float angle, uint8 axis) | rotates mat (excluding the translation part), axis is 78,79,7a corresponding to x,y,z |
22cef8 | modelPlacement* uvSobj(uint32 sobjID) | retrieves the sobj struct for a given ID. ID format is (terraID << 24) | (contourID << 12) | placementID
|
22cfc4 | uvSobjPosm(uint32 sobjID, int part, transform* mat) | sets the transform for the given part of the sobj to mat (storing in fixed-point format) |
22f7e8 | computeLineEndpoints(uint16* entrance, *exit, float xmin, xmax, ymax, ymin, intercept, slope, inverseSlope, bool handedness, float widthScale, heightScale) | stores the endpoints of a line through the given rectangle, using a coordinate that increases ccw around the rectangle, increasing widthScale or heightScale across each side |
2315ec | float rand() | random number generator, seemingly uniform on [0,1), but haven't analyzed it too much |
30b868 | loadLevelDobjs | load several Dobjs depending on level ID (1,3,5,a) |
23031c | uvTxtDraw(int texID) | appends the texture's display list, including additional commands for scrolling |
33fe40 | randomSnow | calls RNG a few times, maybe for new snowflakes |
33ff30 | drawSnow | draws snow pixels into frame buffer |
33ffb4 | computeSnow | computes snow pixel positions |
347e9c | animateToy(toy* toy) | animates the given toy. The toy structure has an Sobj ID (see above) at 0x04 and a toy type byte (0-4) at 0x08 |
The PDAT container at 0x384E64 has (among other yet unknown structures such as "RPKT") various X/Z/Y coordinates in the "PPOS" sets for the first demo flight of the game when left idle at the Title Screen. The demo is of the first Gyro Copter level where you are shown how to fly through rings and then loop around the airport.
If we take the PPOS data and convert the it to floats, we can graph the demo flight path as such:
The example code to do this (made by roto) is terrible and I apologize for it but it works:
import struct
import numpy as np
# 3D stuff
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
from matplotlib import style
x_list = []
z_list = []
y_list = []
with open("ppos2_clean", "r") as f:
data = f.read().splitlines()
for line in data:
pos_x = bytearray.fromhex(line[0:8])
pos_z = bytearray.fromhex(line[8:16])
pos_y = bytearray.fromhex(line[16:24])
x_list.append(round(struct.unpack('>f', pos_x)[0],6))
z_list.append(round(struct.unpack('>f', pos_z)[0],6))
y_list.append(round(struct.unpack('>f', pos_y)[0],6))
print "%s %s %s" % (round(struct.unpack('>f', pos_x)[0],6),
round(struct.unpack('>f', pos_z)[0],6),
round(struct.unpack('>f', pos_y)[0],6))
fig = plt.figure()
ax1 = fig.add_subplot(111, projection='3d')
x = np.array(x_list)
z = np.array(z_list)
y = np.array(y_list)
ax1.plot(x,z,y)
ax1.set_xlabel('x axis')
ax1.set_ylabel('z axis')
ax1.set_zlabel('y axis')
plt.show()
To feed this code with the data points ("ppos2_clean") I just ripped the PPOS data from the PW64 FS dump python script made by queueRAM (Found Here)
You can find a tool to help parse the UPWT blocks here: https://github.com/roto-n64/pw64/blob/master/pw64_upwt_parser.py
The COMM chunk in UPWT is typically 0x430 bytes in size. This table contains the Mission/Test setups. These were enumerated by pfedak/roto via MIPS function RE (pfedak), manual bit-fuzzing and UPWT comparisons (roto).
Some of the mission details (such as Target designations) were verified by debug_print output after modifying data with unexpected inputs.
Debug output sample (Setting BALS to 0xFF): balls : too many balls defined in level [%d]
The offsets in this table are from the start of the COMM data chunk (after COMM Marker+Length).
Offset | Attribute Name | Known Types/Options | Notes |
---|---|---|---|
0x0 | Test Class | '00': 'Beginner', '01': 'Class A', '02': 'Class B', '03': 'Pilot Class' | |
0x1 | Vehicle | '00': 'Hang Glider', '01': 'Rocket Pack', '02': 'Gyro Copter', '03': 'Cannon', '06': 'Birdman' | |
0x2 | Test Number | 00 = Test 1, 01 = Test 2, etc | |
0x3 | Level | '00': 'Holiday Island', '01': 'Crescent Island', '02': 'Little States', '03': 'Ever-Frost Island' | |
0x8 | Weather / Time of Day | '00': 'Sunny', '01': 'Sunny Part 2', '02': 'Cloudy', '03': 'Snowing?', '04': 'Evening', '05': 'Starry Night' | |
0x41D | Hang Glider Thermals | ||
0x41E | Local Winds | ||
0x41F | Takeoff Pads/Strips | ||
0x420 | Landing Pads | ||
0x421 | Landing Strips | ||
0x422 | Rings | ||
0x423 | Balloons | ||
0x424 | Rocket Targets | ||
0x425 | Floating Pads | ||
0x426 | Ball Targets | Cylindrical areas to push a ball into. | |
0x427 | Photo Targets | Objects to photograph in Hang Glider tests. | |
0x428 | "Falcos Domains" | B_GC_3/P_GC_3: Meca Hawk boss. Probably coordinates for him to run to. | |
0x429 | Unknown | ||
0x42A | Canon Targets | ||
0x42B | Jumble Hopper Goals |