diff --git a/Doc/.dat file format.txt b/Doc/.dat file format.txt new file mode 100644 index 0000000..623d4b6 --- /dev/null +++ b/Doc/.dat file format.txt @@ -0,0 +1,123 @@ ++-----------------------------------------------------+ +| 3D Pinball for Windows ("PARTOUT") .DAT file format | +| AdrienTD | ++-----------------------------------------------------+ + +//-- Header --// + ++0x00: File signature BYTE*21 ++0x15: App name BYTE*50 ++0x47: Description BYTE*100 ++0xAB: File size DWORD ++0xAF: Number of files/groups WORD ++0xB1: Size of body DWORD ++0xB5: Unknown (0) WORD + +In 3D Pinball, the file signature is "PARTOUT(4.0)RESOURCE". The rest is +filled with 0. + +//-- Body --// + +The body is constitued of groups. Every group begins with a byte that tells +how many entries are in the group. + +Every entry begins with a byte that specifies the type of the entry. A DWORD that +tells the size of the coming data follows the byte. Then there's some data for the +entry. However, if the type is 0, the type byte is followed by a short value, +and that's all. + +Existing types: + +Type Meaning/comments +--------------------------------------------------- +0 ?, does not have the 32bits size value, but a 16bits value (see above). +1 8 bpp bitmap +3 Group name +5 Palette (1 color is 1 DWORD, only present 1 time in PINBALL.DAT + with a data size of 1024 bytes for 256 colors. Some colors are 0 + because their indexes are reserved by Windows.) +9 String (content) +10 Array of 16bits integer values +11 Array of 32bits floating point values (collision box, ...) +12 16 bpp bitmap (Heightmap?) + + +//-- 8bpp bitmap data header --// ++0: Unknown (0) BYTE ++1: Width WORD ++3: Height WORD ++5: X position WORD ++7 Y position WORD ++9: Size of bitmap DWORD ++13: Unknown (1) BYTE ++14: Bitmap data BYTE*(DWORD@+9) + + +//-- 16bpp bitmap data header --// ++0: Width WORD ++2: Height WORD ++4: Pitch/2 WORD ++6: Unknown (0) DWORD ++10: Unknown (0) WORD ++12: Unknown (80) WORD ++14: Bitmap data BYTE*(DWORD@+9) + + +//-- Pinball 3D remarkable groups --// + +-- table_size +Entry type 10 contains 2 16-bit integers: first is width, second is height. + +-- table_objects +In entry type 10, the first integer is unknown, but then comes a series of +16-bits integer pairs. Every pair represents an object of the table. The +first integer is the type of object, and the second is the number of +a group/resource in this data file. + +Types of object (3D Pinball Space Cadet for Windows): +1000: ? +1001: Plunger +1002: Light (lite###) +1003: Left flipper +1004: Right flipper +1005: Bumper +1006: Yellow target +1007: Drain (no bmp) +1010: ? (no bmp) +1011: Bloc (dot between the flippers) +1012: kout (no bmp) (?) +1013: Gate +1014: Kicker +1015: Roll +1016: One way (no bmp) (?) +1017: Sink (no bmp) (?) +1018: Flag +1019: Red target +1020: Roll (the green circle that makes a weird sound when rolling on it) +1021: Ramp (no bmp) +1022: Ramp hole (no bmp) +1023: Demo (no bmp) +1024: Trip (no bmp) +1026: Lights (no bmp, list?) +1028: Bumpers list (one for attack, one for launch) +1029: kout (no bmp) (?, similar to 1012?) +1030: Fuel bargraph (list?) +1031: Sound +1033: Text box (score, ball counter, player number) + +//-- Information --// + +There's an article of the format at http://rewiki.regengedanken.de/. +I haven't read it completely, but some informations helped me a bit. + +Another thing: There's nearly nothing about hacking the game on the web (even +though the Space Cadet game bundled with Windows is very popular). +What I've only seen when doing a (Google) web search is the 'hidden test' +cheat code. [as of 2017 or even less] + + +//-- Contact --// + +Any questions? Contact me at [see my GitHub profile @AdrienTD for contacts] . + +AdrienTD :) \ No newline at end of file diff --git a/SpaceCadetPinball/DatParser.cpp b/SpaceCadetPinball/DatParser.cpp new file mode 100644 index 0000000..d43bc91 --- /dev/null +++ b/SpaceCadetPinball/DatParser.cpp @@ -0,0 +1,147 @@ +#include "pch.h" +#include "DatParser.h" + + + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +FILE* ff; unsigned char* fdat; int fsiz; +char tbuf[256]; +int ngrp; + +void err(int n) +{ + printf("Error %i\n", n); + exit(n); +} + +void cerr(int c, int n) +{ + if (c) err(n); +} + +void safeprint(char* s, int n) +{ + int i; + for (i = 0; i < n; i++) + { + if (!s[i]) break; + fputc(s[i], stdout); + } +} + +void printhexbytestr(uchar* s, int n) +{ + int i; + for (i = 0; i < n; i++) + printf("%02X", s[i]); +} + +void printshortstr(short* s, int n) +{ + int i; + for (i = 0; i < n; i++) + printf(" %i", s[i]); +} + +void printfloatstr(float* s, int n) +{ + int i; + for (i = 0; i < n; i++) + printf(" %f", s[i]); +} + +int main2(int argc, const char* argv[]) +{ + int g, en, es, n, et; unsigned char* p; + + printf("pbwdlist - 3D Pinball for Windows DAT file listing program\nby AdrienTD\n\n"); + if (argc < 2) { printf("Usage: pbwdlist FILE.DAT\n"); return 1; } + + ff = fopen(argv[1], "rb"); + cerr(!ff, -1); + printf("File: %s\n\n", argv[1]); + fseek(ff, 0, SEEK_END); + fsiz = ftell(ff); + fdat = (unsigned char*)malloc(fsiz); + cerr(!fdat, -2); + fseek(ff, 0, SEEK_SET); + fread(fdat, fsiz, 1, ff); + fclose(ff); + + printf("-- Header --"); + printf("\nFile signature:\t"); safeprint((char*)fdat, 21); + printf("\nApp name:\t"); safeprint((char*)fdat + 0x15, 50); + printf("\nDescription:\t"); safeprint((char*)fdat + 0x47, 100); + printf("\nFile size:\t%i", *((int*)(fdat + 0xAB))); + printf("\nNum. groups:\t%i", ngrp = *((short*)(fdat + 0xAF))); + printf("\nSize of body:\t%i", *((int*)(fdat + 0xB1))); + printf("\nUnknown value:\t%i", *((short*)(fdat + 0xB5))); + + printf("\n\n-- Body --"); + p = fdat + 0xB7; + for (g = 0; g < ngrp; g++) + { + n = *(p++); + printf("\nGroup %i:\tnum entries: %i, location: 0x%X\n", g, n, p - fdat - 1); + for (en = 0; en < n; en++) + { + et = *(p++); + if (et) + { + es = *((int*)p); p += 4; + printf("\t\t- type: %i, size: %i\n", et, es); + switch (et) + { + case 1: // Bitmap + printf("\t\t Bitmap, width: %i, height: %i\n", *(ushort*)(p + 1), *(ushort*)(p + 3)); + break; + case 3: // Group name + printf("\t\t Group name: "); + safeprint((char*)p, es); + printf("\n"); break; + case 5: // Palette + printf("\t\t Palette\n"); break; + case 9: // String + printf("\t\t String: "); + safeprint((char*)p, es); + printf("\n"); break; + case 10: + //printf("\t\t Content: "); + //printhexbytestr(p, es); + printf("\t\t Shorts:"); + printshortstr((short*)p, es / 2); + printf("\n"); break; + case 11: + printf("\t\t Floats:"); + printfloatstr((float*)p, es / 4); + printf("\n"); break; + case 12: + printf("\t\t Special bitmap\n"); break; + default: + printf("\t\t Unknown!\n"); break; + } + p += es; + } + else + { + es = *((short*)p); p += 2; + printf("\t\t- type: %i, value: %i\n", et, es); + } + } + } + + free(fdat); +} + + + +void DatParser::Parse(const char* file) +{ + main2(2, new const char* [2] {0, file}); +} + + + diff --git a/SpaceCadetPinball/DatParser.h b/SpaceCadetPinball/DatParser.h new file mode 100644 index 0000000..dd99525 --- /dev/null +++ b/SpaceCadetPinball/DatParser.h @@ -0,0 +1,7 @@ +#pragma once +class DatParser +{ +public: + static void Parse(const char * file); +}; + diff --git a/SpaceCadetPinball/SpaceCadetPinball.cpp b/SpaceCadetPinball/SpaceCadetPinball.cpp index 0a35790..eec39fd 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.cpp +++ b/SpaceCadetPinball/SpaceCadetPinball.cpp @@ -4,17 +4,27 @@ #include "pch.h" #include #include "objlist_class.h" +#include "partman.h" +#include "DatParser.h" int main() { - std::cout << "Hello World!\n"; + std::cout << "Hello World!\n"; - objlist_class d = objlist_class(2, 4); - for(int i=0;i<100;i++) + objlist_class d = objlist_class(2, 4); + for (int i = 0; i < 100; i++) { d.Add((void*)i); } d.Delete(3); + + auto xx = sizeof(datFileHeader); + + char dataFileName[300]; + partman::make_path_name(dataFileName, "PINBALL.DAT"); + auto datFile = partman::load_records(dataFileName); + + //DatParser::Parse(dataFileName); } // Run program: Ctrl + F5 or Debug > Start Without Debugging menu diff --git a/SpaceCadetPinball/SpaceCadetPinball.vcxproj b/SpaceCadetPinball/SpaceCadetPinball.vcxproj index dd130e9..4d486b8 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.vcxproj +++ b/SpaceCadetPinball/SpaceCadetPinball.vcxproj @@ -91,6 +91,7 @@ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true pch.h + false Console @@ -151,11 +152,15 @@ + + + + Create Create diff --git a/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters b/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters index ddfdd7b..bf4cc9f 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters +++ b/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters @@ -21,6 +21,12 @@ Header Files + + Header Files + + + Header Files + @@ -32,6 +38,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/SpaceCadetPinball/objlist_class.cpp b/SpaceCadetPinball/objlist_class.cpp index fb9e3de..d293102 100644 --- a/SpaceCadetPinball/objlist_class.cpp +++ b/SpaceCadetPinball/objlist_class.cpp @@ -1,4 +1,4 @@ -#include "pch.h"" +#include "pch.h" #include "objlist_class.h" #include // v1 from Ida diff --git a/SpaceCadetPinball/objlist_class.h b/SpaceCadetPinball/objlist_class.h index 8c364c7..d471ace 100644 --- a/SpaceCadetPinball/objlist_class.h +++ b/SpaceCadetPinball/objlist_class.h @@ -4,7 +4,7 @@ struct __declspec(align(4)) objlist_struct1 { int Size; int Count; - int Array[]; + int Array[1]; }; diff --git a/SpaceCadetPinball/partman.cpp b/SpaceCadetPinball/partman.cpp new file mode 100644 index 0000000..f9c3ae4 --- /dev/null +++ b/SpaceCadetPinball/partman.cpp @@ -0,0 +1,102 @@ +#include "pch.h" +#include "partman.h" + +short partman::_field_size[] = { 2, 0x0FFFF, 2, 0x0FFFF, 0x0FFFF, 0x0FFFF, 0x0FFFF, 0x0FFFF,0x0FFFF, 0x0FFFF, 0x0FFFF, 0x0FFFF, 0x0FFFF, 0 }; + + +datFileStruct* partman::load_records(LPCSTR lpFileName) +{ + _OFSTRUCT ReOpenBuff{}; + datFileHeader Buffer; + datFileStruct* datFile; + HFILE fileHandle, hFile; + int lenOfStr, groupIndex; + unsigned short unknown; + char* descriptionBuf, * unknownBuf, * unknownBuf2; + char** groupDataBuf; + + fileHandle = OpenFile(lpFileName, &ReOpenBuff, 0); + hFile = fileHandle; + if (fileHandle == -1) + return 0; + _lread(fileHandle, &Buffer, 183u); + if (lstrcmpA("PARTOUT(4.0)RESOURCE", Buffer.FileSignature)) + { + _lclose(fileHandle); + return 0; + } + datFile = (datFileStruct*)memoryallocate(10); + if (!datFile) + { + _lclose(fileHandle); + return 0; + } + if (lstrlenA(Buffer.Description) <= 0) + { + datFile->Description = 0; + } + else + { + lenOfStr = lstrlenA(Buffer.Description); + descriptionBuf = (char*)memoryallocate(lenOfStr + 1); + datFile->Description = descriptionBuf; + if (!descriptionBuf) + { + _lclose(fileHandle); + LABEL_10: + memoryfree(datFile); + return 0; + } + lstrcpyA(descriptionBuf, Buffer.Description); + } + unknown = Buffer.Unknown; + if (Buffer.Unknown) + { + unknownBuf = (char*)memoryallocate(Buffer.Unknown); + unknownBuf2 = unknownBuf; + if (!unknownBuf) + { + _lclose(hFile); + goto LABEL_19; + } + _lread(hFile, (void*)unknownBuf, unknown); + memoryfree(unknownBuf2); + } + groupDataBuf = (char**)memoryallocate(4 * Buffer.NumberOfGroups); + datFile->GroupData = groupDataBuf; + if (!groupDataBuf) + { + LABEL_19: + if (datFile->Description) + memoryfree(datFile->Description); + goto LABEL_10; + } + groupIndex = 0; + + + return datFile; +} + + +int partman::make_path_name(LPSTR lpFilename, LPCSTR lpString2, int nSize) +{ + int nameSize = GetModuleFileNameA(nullptr, lpFilename, nSize); + if (!nameSize || nameSize == nSize) + return 1; + for (CHAR* i = &lpFilename[nameSize]; i > lpFilename; --i) + { + if (*i == '\\' || *i == ':') + { + i[1] = 0; + break; + } + --nameSize; + } + if (nameSize + 13 < nSize) + { + lstrcatA(lpFilename, lpString2); + return 0; + } + lstrcatA(lpFilename, "?"); + return 1; +} \ No newline at end of file diff --git a/SpaceCadetPinball/partman.h b/SpaceCadetPinball/partman.h new file mode 100644 index 0000000..01a5189 --- /dev/null +++ b/SpaceCadetPinball/partman.h @@ -0,0 +1,58 @@ +#pragma once + +#pragma pack(push) +#pragma pack(1) +struct datFileHeader +{ + char FileSignature[21]; + char AppName[50]; + char Description[100]; + int FileSize; + unsigned short NumberOfGroups; + int SizeOfBody; + unsigned short Unknown; +}; +#pragma pack(pop) +static_assert(sizeof(datFileHeader) == 183, "Wrong size of datFileHeader"); + +struct datFileStruct +{ + unsigned short NumberOfGroups; + char* Description; + char** GroupData; +}; + + + +enum datFieldTypes +{ + ShortValue = 0,//, does not have the 32bits size value, but a 16bits value(see above). + Bitmap8bit = 1,// 8 bpp bitmap + Unknown2 = 2, + GroupName = 3,// Group name + Unknown4 = 4, + Palette = 5,// Palette(1 color is 1 DWORD, only present 1 time in PINBALL.DAT ,with a data size of 1024 bytes for 256 colors.Some colors are 0 ,because their indexes are reserved by Windows.) + Unknown6 = 6, + Unknown7 = 7, + Unknown8 = 8, + String = 9,// String(content) + ShortArray = 10,// Array of 16bits integer values + FloatArray = 11,// Array of 32bits floating point values(collision box, ...) + Bitmap16bit = 12,// 16 bpp bitmap(Heightmap ? ) +}; + +//typedef const char* LPCSTR; +class partman +{ +public: + static datFileStruct* load_records(LPCSTR lpFileName); + + static int make_path_name(LPSTR lpFilename, LPCSTR lpString2, int nSize = 0x12Cu); + +private: + static short _field_size[]; +}; + + + + diff --git a/SpaceCadetPinball/pch.h b/SpaceCadetPinball/pch.h index b04e71e..baa7afc 100644 --- a/SpaceCadetPinball/pch.h +++ b/SpaceCadetPinball/pch.h @@ -10,5 +10,11 @@ #define PCH_H // TODO: add headers that you want to pre-compile here +#include + +#include + +#define memoryallocate(x) malloc(x); +#define memoryfree(x) free(x); #endif //PCH_H