mirror of
https://github.com/k4zmu2a/SpaceCadetPinball.git
synced 2024-12-19 12:22:27 -05:00
Partman v1.
DAT file format doc.
This commit is contained in:
parent
2d96ba2dd0
commit
375db278c4
11 changed files with 475 additions and 5 deletions
123
Doc/.dat file format.txt
Normal file
123
Doc/.dat file format.txt
Normal file
|
@ -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 :)
|
147
SpaceCadetPinball/DatParser.cpp
Normal file
147
SpaceCadetPinball/DatParser.cpp
Normal file
|
@ -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});
|
||||
}
|
||||
|
||||
|
||||
|
7
SpaceCadetPinball/DatParser.h
Normal file
7
SpaceCadetPinball/DatParser.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
class DatParser
|
||||
{
|
||||
public:
|
||||
static void Parse(const char * file);
|
||||
};
|
||||
|
|
@ -4,17 +4,27 @@
|
|||
#include "pch.h"
|
||||
#include <iostream>
|
||||
#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
|
||||
|
|
|
@ -91,6 +91,7 @@
|
|||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -151,11 +152,15 @@
|
|||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="DatParser.h" />
|
||||
<ClInclude Include="objlist_class.h" />
|
||||
<ClInclude Include="partman.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="DatParser.cpp" />
|
||||
<ClCompile Include="objlist_class.cpp" />
|
||||
<ClCompile Include="partman.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
|
|
|
@ -21,6 +21,12 @@
|
|||
<ClInclude Include="objlist_class.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="partman.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DatParser.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
|
@ -32,6 +38,12 @@
|
|||
<ClCompile Include="objlist_class.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="partman.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DatParser.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="NatvisFile.natvis" />
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "pch.h""
|
||||
#include "pch.h"
|
||||
#include "objlist_class.h"
|
||||
#include <cstdlib>
|
||||
// v1 from Ida
|
||||
|
|
|
@ -4,7 +4,7 @@ struct __declspec(align(4)) objlist_struct1
|
|||
{
|
||||
int Size;
|
||||
int Count;
|
||||
int Array[];
|
||||
int Array[1];
|
||||
};
|
||||
|
||||
|
||||
|
|
102
SpaceCadetPinball/partman.cpp
Normal file
102
SpaceCadetPinball/partman.cpp
Normal file
|
@ -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;
|
||||
}
|
58
SpaceCadetPinball/partman.h
Normal file
58
SpaceCadetPinball/partman.h
Normal file
|
@ -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[];
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
@ -10,5 +10,11 @@
|
|||
#define PCH_H
|
||||
|
||||
// TODO: add headers that you want to pre-compile here
|
||||
#include <windows.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#define memoryallocate(x) malloc(x);
|
||||
#define memoryfree(x) free(x);
|
||||
|
||||
#endif //PCH_H
|
||||
|
|
Loading…
Reference in a new issue