def Chunk0x400(hndl): ##Cutscene and camera related print("Chunk 0x400: Cutscene and camera related") num = read4u(hndl) for i in range(num): read4u(hndl) readNstr(hndl) readXYZ(hndl) readMt33(hndl) readNstr(hndl) read1u(hndl)
def Chunk0xD00(hndl): print("Chunk 0xD00:") num = read4u(hndl) for i in range(num): read4u(hndl) readNstr(hndl) readXYZ(hndl) readMt33(hndl) readNstr(hndl) read1u(hndl) read4u(hndl) readXYZ(hndl)
def Chunk0x500(hndl): ##Scene sounds? print("Chunk 0x500: Scene sounds?") num = read4u(hndl) for i in range(num): read4u(hndl) readXYZ(hndl) read1u(hndl) readNstr(hndl) readflt(hndl) readflt(hndl) readflt(hndl) read4u(hndl)
def Chunk0x7001(hndl): num = read4u(hndl) # Maximum 48 characters print("Chunk 0x7001 (load characters):") for i in range(num): fname = readNstr(hndl) # max 0x40 bytes unkStr = readNstr(hndl) # max 0x80 bytes; if LvLVersion >= 200 // Always NULL? fname = fname[:fname.find(".")] + ".rfc" print("\t", fname, unkStr) for i in range(num): read4u(hndl) # not used
def Chunk0x7677(hndl): print("Chunk 0x7677: ??") num = read4u(hndl) for i in range(num): read4u(hndl) readNstr(hndl) readXYZ(hndl) readMt33(hndl) readNstr(hndl) read1u(hndl) readXYZ(hndl) readflt(hndl) read1u(hndl) readflt(hndl) read1u(hndl)
def Chunk0x900(hndl): print("Chunk 0x900:") fname = readNstr(hndl) # max 0x28 bytes print("\t", fname) read4u(hndl) ##SKIP clr1 = hndl.read(4) # RGBA? useflag1 = hndl.read(1)[0] # if == 1 -> use default, else use clr1 clr2 = hndl.read(4) # RGBA? flt1 = readflt(hndl) flt2 = readflt(hndl) clr3 = None byte_71BD1F = None if ( LVLVersion >= 247 ): hndl.read(4) # SKIP readflt(hndl) # SKIP readflt(hndl) # SKIP if ( LVLVersion >= 272 ): readflt(hndl) # SKIP if ( LVLVersion >= 258 ): readflt(hndl) # SKIP if ( LVLVersion >= 270 ): clr3 = hndl.read(4) # RGBA? byte_71BD1F = read4u(hndl) if ( LVLVersion >= 287 ): readflt(hndl) # SKIP print("\t", clr1.hex(), useflag1, clr2.hex(), flt1, flt2, clr3.hex(), byte_71BD1F)
def Chunk0x1100(hndl): print("Chunk 0x1100: Push Region???") num = read4u(hndl) for i in range(num): read4u(hndl) readNstr(hndl) readXYZ(hndl) readMt33(hndl) readNstr(hndl) read1u(hndl) a = read4u(hndl) if (a == 3): readXYZ(hndl) elif (a == 2): readXYZ(hndl) else: readflt(hndl) readflt(hndl) read4u(hndl)
def Chunk0x7777(hndl): print("Chunk 0x7777: Event - conversation") num = read4u(hndl) for i in range(num): read4u(hndl) readNstr(hndl) readXYZ(hndl) readMt33(hndl) readNstr(hndl) read1u(hndl) for j in range(read4u(hndl)): read4u(hndl) read4u(hndl) readflt(hndl) readFixNstr(hndl, 0x18) read4u(hndl) read4u(hndl) read4u(hndl) readFixNstr(hndl, 0x10) readflt(hndl)
def Chunk0x7005(hndl): num = read4u(hndl) print("Chunk 0x7005:") for i in range(num): fname = readNstr(hndl) # max 0x20 bytes fname = fname[:fname.find(".")] + ".peg" print("\t", fname) for i in range(num): read4u(hndl) # not used
def Chunk0x7680(hndl): print("Chunk 0x7680: Related to effects??") num = read4u(hndl) for i in range(num): read4u(hndl) readNstr(hndl) readXYZ(hndl) readMt33(hndl) readNstr(hndl) read1u(hndl) read4u(hndl) read4u(hndl) #SKIP read4u(hndl) if (LVLVersion >= 260): read4u(hndl) read4u(hndl) read4u(hndl) if (LVLVersion >= 228): read4u(hndl) read1u(hndl) read1u(hndl) if (LVLVersion >= 240): readflt(hndl) readflt(hndl) readNstr(hndl) read1u(hndl)
def Chunk0x1000(hndl): print("Chunk 0x1000: Decals") num = read4u(hndl) for i in range(num): read4u(hndl) #SKIP readNstr(hndl) #SKIP readXYZ(hndl) readMt33(hndl) readNstr(hndl) #SKIP read1u(hndl) #SKIP readflt(hndl) readflt(hndl) readflt(hndl) readNstr(hndl) read4u(hndl) read1u(hndl) if (LVLVersion >= 265 ): read1u(hndl) if (LVLVersion >= 294 ): read1u(hndl) if (LVLVersion >= 280 ): read1u(hndl) read1u(hndl) read4u(hndl) readflt(hndl) if (LVLVersion >= 261 ): read4u(hndl) if (LVLVersion >= 262 ): read4u(hndl)
def Chunk0x7678(hndl): print("Chunk 0x7678: Lights glare/corona/beams") num = read4u(hndl) for i in range(num): read4u(hndl) readNstr(hndl) readXYZ(hndl) readMt33(hndl) readNstr(hndl) read1u(hndl) read4u(hndl) if (LVLVersion >= 259 ): read1u(hndl) if (LVLVersion >= 288 ): read1u(hndl) if (LVLVersion >= 289 ): read1u(hndl) if (LVLVersion >= 292 ): read1u(hndl) if (LVLVersion < 232 ): read4u(hndl) if (LVLVersion >= 232 ): read1u(hndl) s = readNstr(hndl) if (s != ""): readflt(hndl) readflt(hndl) readflt(hndl) readflt(hndl) readflt(hndl) s = readNstr(hndl) if (s != ""): readflt(hndl) readflt(hndl) readflt(hndl) if (LVLVersion >= 276 ): read1u(hndl) for j in range( read4u(hndl) ): read4u(hndl)
def ReadRFL(fname): global LVLVersion rfl = RFL() fl = open(fname, "rb") fl.seek(0, 2) SZ = fl.tell() fl.seek(0, 0) if (read4u(fl) != 0xD4BADA55): print("Not a RFL") exit(-1) pegname = fname if (pegname.rfind(".") >= 0): pegname = pegname[:pegname.rfind(".")] + ".peg" if os.path.exists(pegname): rfl.Peg = ReadPeg(pegname) LVLVersion = read4u(fl) # RF2 valid versions >= 201 && <= 295 print("Level version ", LVLVersion) read4u(fl) # from version 114. Before = 0 read4u(fl) read4u(fl) read4u(fl) # from version 160. Before = 35 read4u(fl) # from version 160. Before = 0 lvlName = readNstr(fl) # from version 170. Before = "<untitled>" print("Level name :", lvlName) NextPos = fl.tell() while fl.tell() < SZ: if (fl.tell() != NextPos): print("Missing data? at ", hex(fl.tell()), " size ", hex(NextPos - fl.tell())) fl.seek(NextPos, 0) ChunkID = read4u(fl) ChunkSize = read4u(fl) NextPos = fl.tell() + ChunkSize if (ChunkID == 0x600 or ##Events? ChunkID == 0xE00 or ChunkID == 0xF00 or ChunkID == 0x3000 or ChunkID == 0x4000 or ChunkID == 0x6000 or ChunkID == 0x7679 or ChunkID == 0x7681 or ##VFX?? ChunkID == 0x7779 or ##Spline path ChunkID == 0x7900 or ChunkID == 0x7901 or ChunkID == 0x10000 or ChunkID == 0x20000 or ChunkID == 0x40000 or ChunkID == 0x50000 or ChunkID == 0x60000 or ChunkID == 0x70000 ): print("Chunk ID: ", hex(ChunkID), " NOT IMPLEMENTED Size:", hex(ChunkSize), " at: ", hex(fl.tell())) fl.seek(ChunkSize, 1) elif (ChunkID == 0x7001): Chunk0x7001(fl) elif (ChunkID == 0x7002): Chunk0x7002(fl) elif (ChunkID == 0x7003): Chunk0x7003(fl) elif (ChunkID == 0x7004): Chunk0x7004(fl) elif (ChunkID == 0x7005): Chunk0x7005(fl) elif (ChunkID == 0x900): Chunk0x900(fl) elif (ChunkID == 0x100): ### SCENE GEOMETRY rfl.Geom = Chunk0x100(fl) elif (ChunkID == 0x2000): ### SCENE GEOMETRY rfl.Movers = Chunk0x2000(fl) elif (ChunkID == 0x400): Chunk0x400(fl) elif (ChunkID == 0x500): Chunk0x500(fl) elif (ChunkID == 0x700): Chunk0x700(fl) elif (ChunkID == 0xD00): Chunk0xD00(fl) elif (ChunkID == 0x1000): Chunk0x1000(fl) elif (ChunkID == 0x1100): Chunk0x1100(fl) elif (ChunkID == 0x7680): Chunk0x7680(fl) elif (ChunkID == 0x7677): Chunk0x7677(fl) elif (ChunkID == 0x7678): Chunk0x7678(fl) elif (ChunkID == 0x7777): Chunk0x7777(fl) elif (ChunkID == 0x30000): rfl.Entities = Chunk0x30000(fl) elif (ChunkID == 0): pass else : print("Chunk ID: ", hex(ChunkID), " NOT USED Size:", hex(ChunkSize), " at: ", hex(fl.tell())) if (ChunkSize > 0): fl.seek(ChunkSize, 1) return rfl
def Chunk0x30000(hndl): print("Chunk 0x30000: Entities") EntLst = list() num = read4u(hndl) for i in range(num): ent = Entity() EntLst.append(ent) read4u(hndl) ent.Tp = readNstr(hndl) # Type ent.Pos = readXYZ(hndl) ent.Mt33 = readMt33(hndl) readNstr(hndl) # Name read1u(hndl) read4u(hndl) read4u(hndl) if (LVLVersion >= 274): read4u(hndl) read4u(hndl) readNstr(hndl) readNstr(hndl) v65 = 0 ### Read flags if (LVLVersion >= 248): flg = read4u(hndl) if (LVLVersion >= 263): read4u(hndl) if (flg & (1 << 17)) != 0: v65 = 1 else: read1u(hndl) ##SKIP read1u(hndl) read1u(hndl) read1u(hndl) read1u(hndl) ##SKIP read1u(hndl) read4u(hndl) read4u(hndl) if (LVLVersion < 248): read1u(hndl) read1u(hndl) read1u(hndl) readflt(hndl) readflt(hndl) if (LVLVersion >= 242): readflt(hndl) readflt(hndl) read4u(hndl) readNstr(hndl) readNstr(hndl) readNstr(hndl) readNstr(hndl) readNstr(hndl) readNstr(hndl) readNstr(hndl) if (LVLVersion >= 254): readNstr(hndl) read1u(hndl) read1u(hndl) if (LVLVersion < 232): for j in range( read4u(hndl) ): readNstr(hndl) read4u(hndl) read4u(hndl) read4u(hndl) read4u(hndl) #SKIP if (LVLVersion < 248): read1u(hndl) read1u(hndl) read1u(hndl) #SKIP read1u(hndl) read1u(hndl) read1u(hndl) read1u(hndl) read1u(hndl) read1u(hndl) read1u(hndl) read1u(hndl) read1u(hndl) read1u(hndl) read1u(hndl) if (LVLVersion >= 246): read1u(hndl) read1u(hndl) read1u(hndl) v65 = read1u(hndl) if (v65): readflt(hndl) if (LVLVersion >= 214): readflt(hndl) if (LVLVersion < 254): readNstr(hndl) readNstr(hndl) if (LVLVersion >= 218): read4u(hndl) read1u(hndl) if (LVLVersion >= 253): readflt(hndl) if (LVLVersion >= 255): readflt(hndl) if (LVLVersion >= 281): readflt(hndl) if (LVLVersion >= 241 and LVLVersion < 248): read1u(hndl) n = 18 if (LVLVersion >= 267): n = 19 for j in range(n): readNstr(hndl) readNstr(hndl) return EntLst
def GeomReader(hndl): g = Geom() if ( LVLVersion == 200 ): read4u(hndl) # SKIP fname = readNstr(hndl) # max 0x3F bytes; SKIP read4u(hndl) # SKIP num = read4u(hndl) for i in range(num): #Textures f = readNstr(hndl) g.Textures.append(f) if ( LVLVersion == 200 ): n = read4u(hndl) for j in range(n): read4u(hndl) #SKIP readflt(hndl) #SKIP readflt(hndl) #SKIP if ( LVLVersion > 200 and LVLVersion < 212 ): read4u(hndl) #SKIP num = read4u(hndl) for i in range(num): #Rooms room = Room() room.t = read4u(hndl) if ( LVLVersion > 233 ): # Seems room bound box room.Bounds = (readXYZ(hndl), readXYZ(hndl)) room.unk1 = read4u(hndl) room.unk2 = readflt(hndl) room.unusedStr = readNstr(hndl) room.unk3 = readflt(hndl) room.unk4 = readflt(hndl) room.unk5 = readflt(hndl) room.unk6 = read4u(hndl) room.unk7 = readflt(hndl) room.unk8 = read4u(hndl) if ( LVLVersion < 284 ): read4u(hndl) #SKIP read4u(hndl) #SKIP readflt(hndl, 0, 0.0) #SKIP read4u(hndl) #SKIP room.unk9 = readflt(hndl) room.unk10 = readflt(hndl) if ( LVLVersion < 284 ): room.unk11 = 0. room.unk12 = 0. else: room.unk11 = readflt(hndl) room.unk12 = readflt(hndl) if ( LVLVersion < 284 ): read4u(hndl) #SKIP read4u(hndl) #SKIP if ( LVLVersion < 284 and (room.unk1 & (1 << 13)) != 0 ): readNstr(hndl) #SKIP else: ## Is needed another versions? print("Needed Room Reading for version <= 233") pass if ( LVLVersion >= 231 and LVLVersion < 252 ): n = read4u(hndl) for j in range(n): read4u(hndl) #SKIP g.Rooms.append(room) num = read4u(hndl) ## Version > 113. Else = 0 for i in range(num): #Sub Rooms roomID = read4u(hndl) subCount = read4u(hndl) rp = g.Rooms[roomID] for j in range(subCount): subRoomID = read4u(hndl) sr = g.Rooms[subRoomID] sr.ParentRoom = roomID rp.SubRoom.append(sr) if LVLVersion > 216: # Some Room thing... num = read4u(hndl) for i in range(num): roomID = read4u(hndl) room2ID = read4u(hndl) ## In roomID field write room2ID rm = g.Rooms[roomID] rm.URoom = room2ID num = read4u(hndl) # Room Portals for i in range(num): prt = Portal() room1ID = read4u(hndl) room2ID = read4u(hndl) prt.Room1 = room1ID prt.Room2 = room2ID # Seems portal bound box prt.Bounds = (readXYZ(hndl), readXYZ(hndl)) g.Portals.append(prt) num = read4u(hndl) # Vertex for i in range(num): g.Verticies.append( readXYZ(hndl) ) num = read4u(hndl) # Faces for i in range(num): face = Face() if LVLVersion >= 167: # A B C D ? face.N = readXYZ(hndl) face.D = readflt(hndl) face.TexID = read4S(hndl) #if tex id <= -1, then use misc-static.tga v123 = -1 if LVLVersion < 212: v123 = read4u(hndl) read4u(hndl) # SKIP. From version >= 266 face.unk1 = read4u(hndl) # From version >= 49 if ( LVLVersion >= 66 and LVLVersion < 212 ): read4u(hndl) #SKIP read4u(hndl) #SKIP face.unk2 = read4u(hndl) # From version >= 63 face.Flags = 0 if LVLVersion >= 77: face.Flags = read4u(hndl) elif LVLVersion >= 75: face.Flags = read1u(hndl) read4u(hndl) #SKIP From version 79 if (LVLVersion >= 295 and (face.Flags & 0x8000) != 0): readflt(hndl) #skip tmp = readflt(hndl) if tmp == 1.0: face.Flags |= 0x100000 elif tmp == 1.35: face.Flags |= 0x200000 elif tmp == 1.5: face.Flags |= 0x400000 else: face.Flags |= 0x800000 if ((LVLVersion >= 217 and LVLVersion < 234) or LVLVersion >= 250): read1u(hndl) #SKIP read1u(hndl) #SKIP read1u(hndl) #SKIP readflt(hndl) #Compare with 0.0 and do flags on FPU state test |= 0x4000000 if (LVLVersion >= 230 and LVLVersion < 252): for j in range(6): read1u(hndl) #SKIP face.RoomID = read4u(hndl) # Room ID for this face vnum = read4u(hndl) for j in range(vnum): vtx = FaceVtx() vtx.ID = read4u(hndl) vtx.U = readflt(hndl) vtx.V = readflt(hndl) if LVLVersion >= 212: vtx.R = read1u(hndl) vtx.G = read1u(hndl) vtx.B = read1u(hndl) vtx.A = read1u(hndl) elif v123 > -1: readflt(hndl) #SKIP readflt(hndl) #SKIP face.Vtx.append(vtx) g.Faces.append(face) return g
def LoadRfc(fname): global FVER rfc = RFC() fl = open(fname, "rb") fl.seek(0, 2) SZ = fl.tell() fl.seek(0, 0) if (read4u(fl) != 0x87128712): print("Not a RFC") exit(-1) pegname = fname if (pegname.rfind(".") >= 0): if pegname.rfind(".rfc") >= 0: pegname = pegname[:pegname.rfind(".")] + "_vcm.peg" else: pegname = pegname[:pegname.rfind(".")] + "_v3d.peg" if os.path.exists(pegname): rfc.Peg = ReadPeg(pegname) FVER = read4u(fl) # RFC valid version == 0x114 flg1 = read1u(fl) num = read4u(fl) for i in range(num): sub = RFC_s1() sub.Name = readCstr(fl) sub.field_18 = read4u(fl) sub.pos = readXYZ(fl) sub.field_28 = readflt(fl) rfc.Lst1.append(sub) num = read4u(fl) for i in range(num): sub = RFC_s2() sub.Name = readCstr(fl) sub.field_40 = read4u(fl) sub.pos = readXYZ(fl) sub.field_50 = readFLT4(fl) rfc.Lst2.append(sub) #print(sub.Name) num = read4u(fl) if flg1: for i in range(num): bon = Bone() bon.Name = readCstr(fl) bon.field_4C = read4u(fl) bon.mtx = readMt33(fl) bon.pos = readXYZ(fl) rfc.Bones.append(bon) rfc.ObjNum = read4u(fl) ### Pre allocate for i in range(rfc.ObjNum): rfc.ObjList.append(Object()) LodNum = read4u(fl) rfc.rfc4num = LodNum * rfc.ObjNum ### Pre allocate for i in range(rfc.rfc4num): rfc.LodHeap.append(LodObj()) jj = 0 for i in range(rfc.ObjNum): obj = rfc.ObjList[i] obj.numFlt = read4u(fl) # Seems always == LodNum for j in range(obj.numFlt): obj.LodList.append(rfc.LodHeap[jj]) obj.flts.append(readflt(fl)) jj += 1 for i in range(rfc.ObjNum): obj = rfc.ObjList[i] for j in range(LodNum): lodObj = obj.LodList[j] lodObj.name1 = readCstr(fl) lodObj.name2 = readCstr(fl) lodObj.dword1 = read4u(fl) lodObj.dword2 = read4u(fl) for i in range(rfc.rfc4num): ## Load LODs sub = rfc.LodHeap[i] num = read4u(fl) for j in range(num): sub.skin.Textures.append(readCstr(fl)) sub.dword2 = read4u(fl) for j in range(sub.dword2): t42 = RFC_s42() sub.t42lst.append(t42) read4u(fl) #SKIP read4u(fl) #SKIP t42.Bt1 = read1u(fl) read1u(fl) #SKIP read1u(fl) #SKIP read1u(fl) #SKIP read1u(fl) #SKIP read4u(fl) #SKIP for k in range(2): if (read1u(fl)): read4u(fl) #SKIP readNstr(fl) #SKIP read4u(fl) #SKIP readflt(fl) #SKIP read4u(fl) #SKIP read4u(fl) #SKIP for k in range(read4u(fl)): readflt(fl) #SKIP readflt(fl) #SKIP readflt(fl) #SKIP readflt(fl) #SKIP t42.nstr = readNstr(fl) read4u(fl) #SKIP for k in range(read4u(fl)): readflt(fl) #SKIP readflt(fl) #SKIP for k in range(read4u(fl)): readflt(fl) #SKIP sub.numGeom = read4u(fl) for j in range(sub.numGeom): g = Geom() sub.skin.GeomList.append(g) if (len(rfc.Bones) == 0): #In some RFM only? g.numSimpleVertex = read4u(fl) for k in range(g.numSimpleVertex): sv = SimpleVertex() sv.pos = readXYZ(fl) sv.normal = readXYZ(fl) g.SimpleVertexes.append(sv) g.TrianglesCount = read4u(fl) for k in range(g.TrianglesCount): FCvtxEs = (FaceVtx(read4u(fl), readflt(fl), readflt(fl)), FaceVtx(read4u(fl), readflt(fl), readflt(fl)), FaceVtx(read4u(fl), readflt(fl), readflt(fl))) g.Triangles.append(FCvtxEs) g.TexID = read4u(fl) #TexID g.unk = read4u(fl) g.fl1 = readflt(fl) if (len(rfc.Bones) != 0): g.bts = (read1u(fl), read1u(fl), read1u(fl), read1u(fl)) sub.skin.Pos = readXYZ(fl) sub.skin.fl1 = readflt(fl) sub.skin.Bounds = (readXYZ(fl), readXYZ(fl)) if (len(rfc.Bones) != 0): sub.skin.vtxCount = read4u(fl) sub.skin.field_40 = read4S(fl) #Signed! for k in range(sub.skin.vtxCount): vtx = Vertex() sub.skin.vtxList.append(vtx) vtx.pos = readXYZ(fl) ## Vertex vtx.normal = readXYZ(fl) ## Normal #print("v {:f} {:f} {:f}".format(vtx.pos.x, vtx.pos.y, vtx.pos.z)) if (sub.skin.field_40 > 0): vtx.sh1 = read2u(fl) for l in range(4): wght = VtxWeights() vtx.Weights.append(wght) wght.boneID = read4u( fl) #Really it's 1 Signed BYTE, so 255 == -1 wght.w = readflt(fl) if (wght.boneID & 0x80): # Fix it wght.boneID = -128 + (wght.boneID & 0x7F ) # (255 -> -1) return rfc