-
Notifications
You must be signed in to change notification settings - Fork 0
psx pseudo docs
This page objective is to help developers in better understanding SotN resources and in no-way is a documentation to any code on this or any other project.
Note: This is based on Nyxojaele's papers and hasn't yet be tested.
Before entering these lands you might understand a few items:
-
uXX
is an unsigned integer sized in XX bits -
uXX_le
is an unsigned integer sized in XX bits in little-endian -
YY[XX]
is an array of XX occurrences of YY -
YY[VARIABLE]
is an array of unknown occurrences of YY -
{...}
means it's a structure -
endianness
key means the structure as a whole and not each of its elements - If
endianness
key is not specified consider it big-endian -
XX_ptr<YY>
is a pointer to something of type YY
total-size: 4 Bytes
type: {u16_le x, u16_le y}
total-size: 16 Bytes
type: {u16_le width, u16_le height}
total-size: 2 Bytes
type: {u8 x, u8 y}
total-size: 3 Bytes
endianness: le
type: {
u6 src_width,
u6 src_height,
u6 dst_width,
u6 dst_height,
}
total-size: 2 Bytes
type: {u8 width, u8 height}
total-size: 1 Byte
type: {u4 x, u4 y}
total-size: 1 Byte
type: 2d_smallpos
Not real position, multiply each element by 16 to get real position
total-size: 1 Byte
type: 2d_smallpos
Not real position, multiply each element by 256 to get real position
total-size: 32 Bytes
type: rgba[16]
total-size: 1 Byte
type: u8
total-size: 4 bits
type: u4
total-size: 1 Byte
type: enum
total-size: (>= 6 Bytes)
type {
entity_sprite_partref ref,
union {
entity_sprite_part[VARIABLE] parts,
2d_big_pos dest_pos
}
}
if ref.is_mapped
then parts exists else dest_pos exists
total-size: 2 Byte
endianness: le
type {
u1 is_mapped,
union {
u15 count
u15 index
}
}
if is_mapped then count will have the number of entity_code_sprite.parts
else you'll have to find a generic part through the index value
total-size: 2 Byte
endianness: le
total-size: 10 bytes
type: {
2d_bigpos pos,
entity_identity identity,
entity_state state,
entity_ai_state ai_state
}
total-size: (>= 8 Bytes)
type: entity_gfxpkg[VARIABLE]
total-size: 8 Bytes
type: {
2d_pos vram_pos,
2d_size dim,
psx_ptr data
}
data is compressed
total-size: 1 Byte
type: u8
TODO: Is this actually an entity_gfxentry_index
or an entity_gfxpkg_index
?
total-size: (>= 8 Bytes)
type: {
u32 start,
entity_gfxentry[VARIABLE] entries
u32 end
}
-
start is
0x00000000
(generally) or0x00000004
(when last package) -
end is always
0xFFFFFFFF
- TODO: is start little-endian?
total-size: 2 Byte
endianness: le
type: {
u3 unknow_a,
u3 unknow_b,
u10 type_id
}
total-size: 1 Byte
type: u8
total-size: 22 Bytes
type: {
u16_le draw_flags,
2d_bigpos dest_pos,
2d_bigsize dest_dim,
u16_le clut,
u16_le texture_pg,
2d_bigpos src_b_pos,
2d_bigpos src_e_pos,
}
total-size: 2 Byte
endianness: le
type: {
u3 death_id,
u9 unknow,
u4 type_id
}
total-size: (>= 64 Bytes)
type: {
map_header sections,
u8[VARIABLE] data
}
data includes 2 map_lsentity
per room which can be founded in-file positions got from these values:
- X-sorted version:
*((u16*)(entity_spawnroom + 28))
- Y-sorted version:
*((u16*)(entity_spawnroom + 40))
total-size: 64 Bytes
type: map_intern_ptr[16]
/*
Index Offset Type
4 0x10 map_lsroom
8 0x20 map_lslayout
? 0x?? entity_gfxdef
? 0x?? entity_spawnframe
? 0x?? entity_spawnroom
? 0x?? sprite_banks
total-size: 4 Bytes
type: psx_ptr
You can always subtract 0x80180000
to get the in-file position
total-size: 16 Bytes
type: {
map_intern_ptr<tile_index[VARIABLE]> tiles,
map_intern_ptr<tiledef> tiles_def,
2d_resize dims,
u8 tile_flags,
u8 z_index,
u8 z_priority,
u16_le layer_flags
}
total-size: 8 Bytes
type: {
map_intern_ptr<map_layer> foreground,
map_intern_ptr<map_layer> background
}
total-size: 1 Byte
type: u8
total-size: (>= 8 Bytes)
type: {entity_def[VARIABLE] entities}
This array ends with a 0xFFFFFFFF
total-size: (>= 8 Bytes)
type: {map_layout[VARIABLE] layouts}
total-size: (>= 9 Bytes)
type: {
map_room[VARIABLE] rooms,
u24 padding
}
- This array ends with a
0x40
- padding is always zeroed
total-size: 8 Bytes
type: {
2d_pos map_start,
2d_pos map_end,
map_layout_index layout_id,
u8 yet_unknow,
entity_gfx_index ent_gfx_id,
entity_layout_index ent_layout_id
}
total-size: 4 Bytes
type: u32_le
total-size: 2 Bytes
endianness: le
type: {u5 red, u5 green, u5 blue, u1 alpha}
total-size: 16 Bytes
type: {
psx_ptr<2d_smallpos[VARIABLE]> tileset_coords,
psx_ptr<2d_smallpos[VARIABLE]> tile_coords,
psx_ptr<clut_coord_index[VARIABLE]> clut_coords,
psx_ptr<collision_type[VARIABLE]> collisions
}
total-size: 2 Bytes
type: u16_le
total-size: 262144 Bytes
type: tileset_slot[8]
total-size: 8192 Bytes
type: tileset_tile[8][8]
total-size: 32768 Bytes
type: tileset_group[4]
total-size: 128 Bytes
type: clut_index[16][16]
fn(in, out)
common = in.read_le(8)
.loop:
opcode = in.read_nibble(1)
.switch(opcode):
.case 0:
out.write(repeat("0, ((in.read_nibble(1) << 4) + in.read_nibble(1) + 19)))
.case 0x1:
out.write(in.read_nibble(1))
.case 0x2:
out.write(repeat(in.read_nibble(1), 2))
.case 0x3:
out.write(in.read_nibble(2))
.case 0x4:
out.write(in.read_nibble(3))
.case 0x5:
desired = in.read_nibble(1)
loop = in.read_nibble(1)
out.write(desired.repeat(loop))
.case 0x6:
out.write(repeat("0", in.read_nibble(1)))
.case 0x7..0xE:
index = opcode-0x7
target = common[index]
loop = (target & 0xf0) >> 4
desired = target & 0x0
out.write(desired.repeat(loop))
.case 0xF:
.break
- in and out would be like buffers
-
read_le(n)
reads n Bytes in little-endian -
read_nibble(n)
reads n Nibbles -
write(values)
writes values (remember: Nibbles are the smallest value) -
repeat(data, n)
repeat data n times - "0 is a zeroed Nibble