Lode Runner - Total Recall (v2.01a.3)
Cette révision appartient à :
@@ -50,30 +50,137 @@ value | Character | Type
|
||||
#define READ_LEVEL_DATA_SIZE (256)
|
||||
#define ONE_LEVEL_DATA_SIZE (224)
|
||||
|
||||
#define APPLE_DISK_NO (3)
|
||||
#define PLAYER_ID (0x09)
|
||||
|
||||
#if (APPLE_DISK_NO == 1)
|
||||
//#define APPLE_DISK_NO (5)
|
||||
#define C64_DISK_NO (1)
|
||||
|
||||
#define FILE_NAME "Lode_Runner_Apple-II.dsk"
|
||||
#define MAX_LEVEL (150)
|
||||
#define TITLE_NAME "Lode Runner (Apple-II 1983)"
|
||||
#define DATA_VAR_NAME "baseLevelData"
|
||||
#ifdef APPLE_DISK_NO //APPLE-II
|
||||
|
||||
#elif (APPLE_DISK_NO == 2)
|
||||
#define MAP_START_POSITION (0x3000L)
|
||||
|
||||
#define FILE_NAME "Lode_Runner_Championship _Apple-II.dsk"
|
||||
#define MAX_LEVEL (50)
|
||||
#define TITLE_NAME "Championship Lode Runner (Apple-II 1984)"
|
||||
#define DATA_VAR_NAME "champLevelData"
|
||||
#if (APPLE_DISK_NO == 1)
|
||||
|
||||
#define FILE_NAME "./apple2.dsk/Lode_Runner_Apple-II.dsk"
|
||||
#define MAX_LEVEL (150)
|
||||
#define TITLE_NAME "Classic Lode Runner (Apple-II 1983)"
|
||||
#define DATA_VAR_NAME "classicLevelData"
|
||||
|
||||
#elif (APPLE_DISK_NO == 3)
|
||||
#elif (APPLE_DISK_NO == 2)
|
||||
|
||||
#define FILE_NAME "Revenge_of_Lode_Runner.dsk"
|
||||
#define MAX_LEVEL (25)
|
||||
#define TITLE_NAME "Revenge of Lode Runner (Apple-II 1986)"
|
||||
#define DATA_VAR_NAME "RevengeLevelData"
|
||||
#define FILE_NAME "./apple2.dsk/Lode_Runner_Championship _Apple-II.dsk"
|
||||
#define MAX_LEVEL (50)
|
||||
#define TITLE_NAME "Championship Lode Runner (Apple-II 1984)"
|
||||
#define DATA_VAR_NAME "champLevelData"
|
||||
|
||||
#endif
|
||||
#elif (APPLE_DISK_NO == 3)
|
||||
|
||||
#define FILE_NAME "./apple2.dsk/Revenge_of_Lode_Runner.dsk"
|
||||
#define MAX_LEVEL (25)
|
||||
#define TITLE_NAME "Revenge of Lode Runner (Apple-II 1986)"
|
||||
#define DATA_VAR_NAME "revengeLevelData"
|
||||
|
||||
#elif (APPLE_DISK_NO == 4)
|
||||
|
||||
#define FILE_NAME "./apple2.dsk/Lode Runner Fan Book (4 Levels).do"
|
||||
#define MAX_LEVEL (4)
|
||||
#define TITLE_NAME "Lode Runner Fan Book (4 levels)"
|
||||
#define TITLE_NOTES "Image got from: http://ww3.tiki.ne.jp/~maclr/lr/lr.html"
|
||||
#define DATA_VAR_NAME "fanBookLevelData"
|
||||
|
||||
#elif (APPLE_DISK_NO == 5)
|
||||
|
||||
#define FILE_NAME "./apple2.dsk/MYLODE.DSK"
|
||||
#define MAX_LEVEL (54)
|
||||
#define TITLE_NAME "Peter Ferrie's My Lode"
|
||||
#define TITLE_NOTES "Image got from: http://pferrie.host22.com/misc/appleii.htm"
|
||||
#define DATA_VAR_NAME "FerrieLevelData"
|
||||
|
||||
#endif
|
||||
|
||||
#elif defined C64_DISK_NO //C64
|
||||
|
||||
#define MAP_START_POSITION (0x2A00L)
|
||||
|
||||
#define START_GOOD_BYTE 0x0D
|
||||
#define START_SKIP_BYTE1 0x4B
|
||||
|
||||
#if (C64_DISK_NO == 1)
|
||||
|
||||
#define FILE_NAME "./C64.dsk/Professional Lode Runner (1985)(Dodosoft).fixed.d64"
|
||||
|
||||
//#define FILE_NAME "./C64.dsk/LODERUNNER[amg].fix.D64"
|
||||
|
||||
//#define FILE_NAME "./C64.dsk/Lode Runner (1983)(Broderbund).d64"
|
||||
#define START_ALL_ISGOOD 1
|
||||
|
||||
#define MAX_LEVEL (200)
|
||||
#define TITLE_NAME "Lode Runner I (C64)"
|
||||
#define DATA_VAR_NAME "c64ver1"
|
||||
|
||||
#elif (C64_DISK_NO == 2)
|
||||
|
||||
#define FILE_NAME "./C64.dsk/LODERUN2.D64"
|
||||
|
||||
#define MAX_LEVEL (21)
|
||||
#define TITLE_NAME "Lode Runner II (C64)"
|
||||
#define DATA_VAR_NAME "c64ver2"
|
||||
|
||||
#elif (C64_DISK_NO == 3)
|
||||
|
||||
#define FILE_NAME "./C64.dsk/Atlantis Lode Runner (19xx)(-)[cr TBC].d64"
|
||||
|
||||
#define START_SKIP_BYTE2 0x48
|
||||
#define START_SKIP_BYTE3 0x4D //Level 140: BAD SECTOR
|
||||
|
||||
#define MAX_LEVEL (150)
|
||||
#define TITLE_NAME "Atlantis Lode Runner (C64)"
|
||||
#define DATA_VAR_NAME "c64Atlantis"
|
||||
|
||||
#elif (C64_DISK_NO == 4)
|
||||
|
||||
#define FILE_NAME "./C64.dsk/LODERUN4.D64"
|
||||
#define MAX_LEVEL (200)
|
||||
#define TITLE_NAME "Lode Runner IV (C64)"
|
||||
#define DATA_VAR_NAME "c64ver4"
|
||||
|
||||
#elif (C64_DISK_NO == 5)
|
||||
|
||||
#define FILE_NAME "./C64.dsk/LODERUN5.D64"
|
||||
#define MAX_LEVEL (200)
|
||||
#define TITLE_NAME "Lode Runner V (C64)"
|
||||
#define DATA_VAR_NAME "c64ver5"
|
||||
|
||||
#elif (C64_DISK_NO == 6)
|
||||
|
||||
#define FILE_NAME "./c64.dsk/Lode Runner (1983)(Broderbund).d64"
|
||||
|
||||
#define START_ALL_ISGOOD 1
|
||||
#define START_SKIP_BYTE2 0x02
|
||||
#define START_SKIP_BYTE3 0x03
|
||||
|
||||
#define MAX_LEVEL (176)
|
||||
#define TITLE_NAME "Lode Runner Fans version (C64)"
|
||||
#define DATA_VAR_NAME "c64Fans"
|
||||
|
||||
#elif (C64_DISK_NO == 7)
|
||||
|
||||
#define FILE_NAME "./C64.dsk/LODERUN_CHAMP(FF).D64"
|
||||
|
||||
#define START_ALL_ISGOOD 1
|
||||
#define DATA_XOR_VALUE 0xFF
|
||||
|
||||
#define MAX_LEVEL (50)
|
||||
#define TITLE_NAME "Championship Lode Runner (C64)"
|
||||
#define DATA_VAR_NAME "c64Champ"
|
||||
|
||||
#endif
|
||||
|
||||
#else //Error
|
||||
|
||||
#error Please define "APPLE_DISK_NO" or "C64_DISK_NO"
|
||||
|
||||
#endif
|
||||
|
||||
char tileType[] = {
|
||||
' ', //0x00: Empty space
|
||||
@@ -88,22 +195,39 @@ char tileType[] = {
|
||||
'&' //0x09:Player
|
||||
};
|
||||
|
||||
int allZero(unsigned char *levelData)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < ONE_LEVEL_DATA_SIZE; i++) {
|
||||
if(levelData[i]) return 0;
|
||||
}
|
||||
return 1; //all zero
|
||||
}
|
||||
|
||||
int goodLevel(unsigned char *levelData)
|
||||
{
|
||||
int i;
|
||||
unsigned char leftTile, rightTile;
|
||||
int allZero = 1;
|
||||
int playerNo = 0;
|
||||
|
||||
|
||||
for(i = 0; i < ONE_LEVEL_DATA_SIZE; i++) {
|
||||
//levelData[i] = levelData[i] ^ 0xFF;
|
||||
#ifdef DATA_XOR_VALUE
|
||||
levelData[i] = levelData[i] ^ DATA_XOR_VALUE;
|
||||
#endif
|
||||
leftTile = levelData[i] & 0xF;
|
||||
rightTile = levelData[i] >> 0x04;
|
||||
if(leftTile >= MAX_TILE_TYPE || rightTile >= MAX_TILE_TYPE) {
|
||||
return 0;
|
||||
}
|
||||
if(leftTile == PLAYER_ID) playerNo++;
|
||||
if(rightTile == PLAYER_ID) playerNo++;
|
||||
|
||||
if(leftTile != 0 || rightTile != 0) allZero = 0;
|
||||
}
|
||||
if(playerNo != 1) return 0;
|
||||
return !allZero;
|
||||
return 1; //OK
|
||||
}
|
||||
@@ -113,7 +237,10 @@ void dumpTitle(void)
|
||||
printf("//************************************************************\n");
|
||||
printf("//* All levels extract from: \n");
|
||||
printf("//* %s DISK IMAGE\n",TITLE_NAME );
|
||||
printf("//* by Simon Hung 2014/02/20\n");
|
||||
#ifdef TITLE_NOTES
|
||||
printf("//* %s\n",TITLE_NOTES );
|
||||
#endif
|
||||
printf("//* by Simon Hung 2015/01/05\n");
|
||||
printf("//************************************************************\n\n");
|
||||
}
|
||||
|
||||
@@ -163,12 +290,12 @@ void dumpLevel4JavaScript(int level, unsigned char *levelData)
|
||||
int main(void)
|
||||
{
|
||||
FILE *fp;
|
||||
unsigned char levelData[READ_LEVEL_DATA_SIZE];
|
||||
unsigned char levelBuf[READ_LEVEL_DATA_SIZE];
|
||||
unsigned char *levelData;
|
||||
int curLevel = 0;
|
||||
int readSize= 0, isGood;
|
||||
unsigned long curPos = 0x3000L;
|
||||
int readSize= 0, isGood = 1;
|
||||
unsigned long curPos = MAP_START_POSITION;
|
||||
unsigned long dspPos = curPos;
|
||||
int doubleError = 0;
|
||||
|
||||
if((fp = fopen(FILE_NAME, "rb")) ==NULL) {
|
||||
printf("Open file \"%s\" failed !\n", FILE_NAME);
|
||||
@@ -184,33 +311,58 @@ int main(void)
|
||||
dumpTitle();
|
||||
|
||||
printf("var %s = [\n", DATA_VAR_NAME);
|
||||
#ifdef C64
|
||||
do {
|
||||
|
||||
while(
|
||||
#ifndef START_ALL_ISGOOD
|
||||
isGood &&
|
||||
#endif
|
||||
while(curLevel < MAX_LEVEL &&
|
||||
(readSize = fread(levelData, sizeof(char), READ_LEVEL_DATA_SIZE, fp)) == READ_LEVEL_DATA_SIZE &&
|
||||
(isGood = goodLevel(levelData))
|
||||
curLevel < MAX_LEVEL &&
|
||||
(readSize = fread(levelBuf, sizeof(char), READ_LEVEL_DATA_SIZE, fp)) == READ_LEVEL_DATA_SIZE
|
||||
){
|
||||
//dumpLevel(++curLevel, levelData);
|
||||
//printf("%x", dspPos);
|
||||
dumpLevel4JavaScript(++curLevel, levelData);
|
||||
dspPos += READ_LEVEL_DATA_SIZE;
|
||||
doubleError=0;
|
||||
}
|
||||
#ifdef C64
|
||||
doubleError++;
|
||||
if(!isGood) {
|
||||
curPos += 0x1500L;
|
||||
dspPos = curPos;
|
||||
if(fseek(fp, curPos, SEEK_SET) != 0) {
|
||||
printf("Fseek error ! @%d\n", __LINE__);
|
||||
fclose(fp);
|
||||
return 1;
|
||||
levelData = levelBuf;
|
||||
#ifdef START_GOOD_BYTE
|
||||
unsigned char startByte = *(levelData++);
|
||||
|
||||
switch(startByte) {
|
||||
case START_SKIP_BYTE1:
|
||||
#ifdef START_SKIP_BYTE2
|
||||
case START_SKIP_BYTE2:
|
||||
#endif
|
||||
#ifdef START_SKIP_BYTE3
|
||||
case START_SKIP_BYTE3:
|
||||
#endif
|
||||
#ifdef START_SKIP_BYTE4
|
||||
case START_SKIP_BYTE4:
|
||||
#endif
|
||||
//printf("SKIP0 - %x\n", dspPos);
|
||||
break;
|
||||
case 0: //good if not allzero
|
||||
if(allZero(levelData)){
|
||||
//printf("SKIP1 - %x\n", dspPos);
|
||||
break;
|
||||
}
|
||||
|
||||
} else doubleError++;
|
||||
} while(curLevel < MAX_LEVEL && doubleError <= 1);
|
||||
#endif
|
||||
#ifdef START_ALL_ISGOOD
|
||||
default:
|
||||
#endif
|
||||
case START_GOOD_BYTE:
|
||||
#endif
|
||||
if((isGood = goodLevel(levelData))) {
|
||||
//dumpLevel(++curLevel, levelData);
|
||||
//printf("%x", dspPos);
|
||||
dumpLevel4JavaScript(++curLevel, levelData);
|
||||
}
|
||||
#ifdef START_GOOD_BYTE
|
||||
break;
|
||||
#ifndef START_ALL_ISGOOD
|
||||
default:
|
||||
isGood = 0;
|
||||
printf("%x", dspPos);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
dspPos += READ_LEVEL_DATA_SIZE;
|
||||
}
|
||||
printf("];\n");
|
||||
|
||||
fclose(fp);
|
||||
|
||||
Fichier binaire non affiché.
Fichier binaire non affiché.
BIN
Fichier binaire non affiché.
Fichier binaire non affiché.
Fichier binaire non affiché.
Fichier binaire non affiché.
+385
Diff de fichier supprimé car une ou plusieurs lignes sont trop longues
Diff de fichier supprimé car une ou plusieurs lignes sont trop longues
Fichier binaire non affiché.
Diff de fichier supprimé car une ou plusieurs lignes sont trop longues
Fichier binaire non affiché.
Fichier binaire non affiché.
Fichier binaire non affiché.
Fichier binaire non affiché.
Fichier binaire non affiché.
Fichier binaire non affiché.
Fichier binaire non affiché.
Fichier binaire non affiché.
Fichier binaire non affiché.
@@ -0,0 +1,543 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define WORD unsigned __int16
|
||||
#define BYTE unsigned __int8
|
||||
|
||||
#define IMAGE_HEAD_SIZE 0x70
|
||||
#define IMAGE_HEAD_STRING "Lode Runner Puzzle Set"
|
||||
|
||||
#define PZL_SIZE_ADDR (6)
|
||||
|
||||
#define PZL_HEAD_SIZE (8)
|
||||
#define PZL_TITLE_SIZE (256)
|
||||
|
||||
#define MAX_LAYERS (14)
|
||||
#define LAYER_X_SIZE (30)
|
||||
#define LAYER_Y_SIZE (18)
|
||||
#define ONE_LAYER_SIZE (LAYER_X_SIZE*LAYER_Y_SIZE)
|
||||
#define TOTAL_LAYER_SIZE (MAX_LAYERS * ONE_LAYER_SIZE)
|
||||
|
||||
#define PZL_MAX_COMP_SIZE (PZL_HEAD_SIZE + PZL_TITLE_SIZE + TOTAL_LAYER_SIZE) //assume
|
||||
|
||||
#define PZL_FULL_SIZE (7923)
|
||||
#define TEST_BYTE_VALUE (0xF5)
|
||||
|
||||
#define TILE_Y_MIN (1)
|
||||
#define TILE_Y_MAX (16)
|
||||
|
||||
#define LAYER_FIRST_ID (1)
|
||||
#define LAYER_LAST_ID (14)
|
||||
|
||||
#define BUFFER_BASE (0x122)
|
||||
#define LAYER_STEP (540) //30*18
|
||||
#define LAYER_ZERO (BUFFER_BASE - LAYER_STEP)
|
||||
#define LAYER_Y_INC (18)
|
||||
|
||||
#define getTitle() (pzlBuf + PZL_HEAD_SIZE)
|
||||
#define PZL_FIRST_OFFSET (291)
|
||||
#define PZL_LAST_OFFSET (7849)
|
||||
|
||||
#define TEXT_LINE_SIZE (16)
|
||||
|
||||
const char *layerName[] = {
|
||||
"Layer 1: Tool Class",
|
||||
"Layer 2: Tool Subclass",
|
||||
"Layer 3: Unknown",
|
||||
"Layer 4: Unknown",
|
||||
"Layer 5: Transporter Destination X",
|
||||
"Layer 6: Transporter Destination Y",
|
||||
"Layer 7: Tool Hooks",
|
||||
"Layer 8: Turf Class",
|
||||
"Layer 9: Turf Subclass",
|
||||
"Layer 10: Turf Appearance",
|
||||
"Layer 11: Unknown",
|
||||
"Layer 12: Unknown",
|
||||
"Layer 13: Door levels > 255",
|
||||
"Layer 14: Turf Hooks"
|
||||
};
|
||||
|
||||
int checkHead(FILE *fp)
|
||||
{
|
||||
BYTE headBuf[IMAGE_HEAD_SIZE];
|
||||
int nRead;
|
||||
|
||||
if( (nRead = fread (headBuf,sizeof(BYTE), sizeof(headBuf), fp)) != IMAGE_HEAD_SIZE) {
|
||||
printf("Read head failed (%d)\n", nRead);
|
||||
return 1;
|
||||
}
|
||||
if(strncmp(IMAGE_HEAD_STRING, (char*) headBuf, sizeof(IMAGE_HEAD_STRING)-1) != 0) {
|
||||
printf("Bead Head String\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
BYTE pzlBuf[PZL_FULL_SIZE+1]; //one byte for check
|
||||
|
||||
int pzlDecompress(BYTE *pzlCompBuf, int pzlCompSize)
|
||||
{
|
||||
int error = 0;
|
||||
int bufIdx, compIdx;
|
||||
enum decompState { getCmd, getStringCnt, decompEnd, doRepeat, doString };
|
||||
|
||||
memset(pzlBuf, TEST_BYTE_VALUE, PZL_FULL_SIZE+1);
|
||||
//pzlBuf[PZL_FULL_SIZE-1] = TEST_BYTE_VALUE;
|
||||
//pzlBuf[PZL_FULL_SIZE] = TEST_BYTE_VALUE;
|
||||
|
||||
//copy pzl header to pzl buffer
|
||||
memcpy(pzlBuf, pzlCompBuf, PZL_HEAD_SIZE);
|
||||
bufIdx = PZL_HEAD_SIZE;
|
||||
|
||||
decompState state = getCmd;
|
||||
for(compIdx = PZL_HEAD_SIZE; !error && compIdx < pzlCompSize; compIdx++)
|
||||
{
|
||||
BYTE c = pzlCompBuf[compIdx];
|
||||
BYTE copyCnt;
|
||||
|
||||
switch (state) {
|
||||
case getCmd:
|
||||
switch(c) {
|
||||
case 0x00:
|
||||
state = decompEnd;
|
||||
break;
|
||||
case 0xFF:
|
||||
state = getStringCnt; //copy string mode
|
||||
break;
|
||||
default:
|
||||
state = doRepeat; //repeat mode
|
||||
copyCnt = c; //
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case getStringCnt:
|
||||
if (c < 1) {
|
||||
//return 1;
|
||||
state = getCmd;
|
||||
} else {
|
||||
state = doString;
|
||||
copyCnt = c;
|
||||
if (compIdx + copyCnt >= PZL_FULL_SIZE)
|
||||
error = 1;
|
||||
}
|
||||
break;
|
||||
case decompEnd:
|
||||
pzlBuf[bufIdx++] = 0;
|
||||
error = 1;
|
||||
break;
|
||||
case doString:
|
||||
pzlBuf[bufIdx++] = c;
|
||||
if(--copyCnt <= 0) state = getCmd;
|
||||
break;
|
||||
case doRepeat:
|
||||
if (bufIdx + copyCnt >= PZL_FULL_SIZE) {
|
||||
error = 1;
|
||||
} else {
|
||||
while(copyCnt--) pzlBuf[bufIdx++] = c;
|
||||
state = getCmd;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(state == decompEnd) error = 0;
|
||||
if(error || pzlBuf[PZL_FULL_SIZE] != TEST_BYTE_VALUE) {
|
||||
//buffer overrun
|
||||
printf("Error: Buffer overrun !\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dspArray(int idx, int len)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < len; i += TEXT_LINE_SIZE) {
|
||||
int offset = idx + i;
|
||||
printf("%4d: ", offset);
|
||||
for (j = 0; j < TEXT_LINE_SIZE; j++) {
|
||||
if (i + j < len)
|
||||
printf("%4d", (int) pzlBuf[idx + i + j]);
|
||||
else
|
||||
printf(" ");
|
||||
}
|
||||
printf(" ");
|
||||
for (j = 0; j < TEXT_LINE_SIZE; j++) {
|
||||
char ch = pzlBuf[idx + i + j];
|
||||
if (i + j < len) {
|
||||
if (ch >= ' ' && ch < 127)
|
||||
printf("%c ", ch);
|
||||
else
|
||||
printf(". ");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
int getTile(int x, int y, int layer)
|
||||
{
|
||||
if (x < 0 || x > 29 || y < 0 || y > 18 || layer < LAYER_FIRST_ID || layer > LAYER_LAST_ID)
|
||||
return -1;
|
||||
|
||||
int idx = LAYER_ZERO + layer * LAYER_STEP + x * LAYER_Y_INC + y;
|
||||
|
||||
return pzlBuf[idx];
|
||||
}
|
||||
|
||||
void dspLayerArray(int layer)
|
||||
{
|
||||
int tile;
|
||||
printf("%s\n", layerName[layer-1]);
|
||||
printf(" ");
|
||||
for (int x = 1; x < 29; x++) printf("%4d", x);
|
||||
printf("\n");
|
||||
|
||||
for (int y = TILE_Y_MIN; y <= TILE_Y_MAX; y++) {
|
||||
printf("%2d", y);
|
||||
for (int x = 1; x < 29; x++) {
|
||||
tile = getTile(x, y, layer);
|
||||
if(tile) printf("%4d", tile);
|
||||
else printf(" ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void displayTextPzl(int pzlNumber)
|
||||
{
|
||||
// write puzzle title
|
||||
printf("Puzzle %d, Title:\n%s\n\n"
|
||||
"Edited data must have the same number of bytes in each line or an error\n"
|
||||
"will occur. Edited data values have a range from 0-255. Use 0xNN format\n"
|
||||
"for hexadecimal values. All lines must have the same content. Extra carrage\n"
|
||||
"returns or deleted comments will cause an error. Data in layers is\n"
|
||||
"deconvoluted for easier interpretation. NotePad or an editor using a constant\n"
|
||||
"courier type will be more easily readable than an editor using a variable pitch\n"
|
||||
"font. An error message on the first error detected will be given. Subsequent\n"
|
||||
"errors will be shown after all previous errors are corrected. The first row\n"
|
||||
"and column of the layers are the row and column numbers. Some data is mondified\n"
|
||||
"when the puzzle file is saved.\n\n"
|
||||
"Puzzle Header: 8 consisting of:\n"
|
||||
"Two bytes compressed length (modified by this program)\n"
|
||||
"Two bytes zeros\n"
|
||||
"Two bytes puzzle number (modified by this program on save file)\n"
|
||||
"Two bytes which always seem to be 1 and 0\n"
|
||||
"Puzzle title block 256 bytes or so\n"
|
||||
"Sixteen bytes unknown.\n"
|
||||
"This is then followed by layer 1\n\n", pzlNumber, getTitle());
|
||||
|
||||
// write Puzzle title block
|
||||
dspArray(0, PZL_FIRST_OFFSET - 1);
|
||||
|
||||
// write puzzle sets
|
||||
/*
|
||||
for (int layer = 1; layer <= 14; layer++)
|
||||
dspLayerArray(layer);
|
||||
*/
|
||||
dspLayerArray(1);
|
||||
dspLayerArray(2);
|
||||
dspLayerArray(8);
|
||||
dspLayerArray(9);
|
||||
dspLayerArray(10);
|
||||
|
||||
printf("\n"
|
||||
"Player data: consists of data for Jake and Wes followed by data for monks.\n"
|
||||
"Most of this data is accessable through the player editor.\n\n");
|
||||
|
||||
dspArray(PZL_LAST_OFFSET + 1, PZL_FULL_SIZE - PZL_LAST_OFFSET);
|
||||
}
|
||||
|
||||
//value | Character | Type
|
||||
//------+-----------+-----------
|
||||
// 0x0 | <space> | Empty Space ==> No Truf (Layer 8, Layer 9) = (0,0)
|
||||
// 0x1 | # | Normal Brick ==> Turf (Layer 8, Layer 9) = (1,1)
|
||||
// 0x2 | @ | Solid Brick ==> Bedrock (Layer 8, Layer 9) = (1,2)
|
||||
// 0x3 | H | Ladder ==> Ladder (Layer 8, Layer 9) = (5,1)
|
||||
// 0x4 | - | Bar ==> Bar (Layer 8, Layer 9) = (6,1)
|
||||
// 0x5 | X | False Brick ==> Trap Truf (Layer 8, Layer 9) = (2,6)
|
||||
// 0x6 | S | Exit Ladder ==> Exit ladder (Layer 8, Layer 9) = (5,2)
|
||||
// 0x7 | $ | Gold ==> Coin (Layer 1, Layer 2) = (4,1)
|
||||
// 0x8 | 0 | Guard
|
||||
// 0x9 | & | Player
|
||||
|
||||
#define CLASSIC_MAP_X_SIZE (28)
|
||||
#define CLASSIC_MAP_Y_SIZE (16)
|
||||
#define CLASSIC_MAP_SIZE (CLASSIC_MAP_X_SIZE * CLASSIC_MAP_Y_SIZE);
|
||||
|
||||
BYTE mapClassic[CLASSIC_MAP_X_SIZE][CLASSIC_MAP_Y_SIZE];
|
||||
|
||||
#define CLASSIC_TILE_EMPTY (' ')
|
||||
#define CLASSIC_TILE_BRICK ('#')
|
||||
#define CLASSIC_TILE_SOLID ('@')
|
||||
#define CLASSIC_TILE_LADDER ('H')
|
||||
#define CLASSIC_TILE_BAR ('-')
|
||||
#define CLASSIC_TILE_TRAP ('X')
|
||||
#define CLASSIC_TILE_EXIT_LADDER ('S')
|
||||
#define CLASSIC_TILE_GOLD ('$')
|
||||
#define CLASSIC_TILE_GUARD ('0')
|
||||
#define CLASSIC_TILE_RUNNER ('&')
|
||||
|
||||
#define RUNNER_CNT_ADDR (0x1eaa) //7850
|
||||
#define RUNNER_BASE_ADDR (0x1eac)
|
||||
#define RUNNER_ENABLE_OFFSET (0)
|
||||
#define RUNNER_DATA_OFFSET (1)
|
||||
#define RUNNER_X_OFFSET (2)
|
||||
#define RUNNER_Y_OFFSET (3)
|
||||
#define RUNNER_STEP_SIZE (4)
|
||||
|
||||
#define GUARD_CNT_ADDR (0x1eb4) //7860
|
||||
#define GUARD_BASE_ADDR (0x1eb5)
|
||||
#define GUARD_DATA1_OFFSET (0)
|
||||
#define GUARD_ENABLE_OFFSET (1)
|
||||
#define GUARD_DATA2_OFFSET (2)
|
||||
#define GUARD_DOOR_OFFSET (3)
|
||||
#define GUARD_X_OFFSET (4)
|
||||
#define GUARD_Y_OFFSET (5)
|
||||
#define GUARD_STEP_SIZE (6)
|
||||
|
||||
int mapClassicAddGuy()
|
||||
{
|
||||
BYTE *runnerBase = pzlBuf + RUNNER_BASE_ADDR;
|
||||
int runnerCnt = *(pzlBuf+RUNNER_CNT_ADDR);
|
||||
BYTE runnerX, runnerY;
|
||||
|
||||
BYTE *guardBase = pzlBuf + GUARD_BASE_ADDR;
|
||||
int guardCnt = *(pzlBuf + GUARD_CNT_ADDR);
|
||||
BYTE guardX, guardY;
|
||||
|
||||
|
||||
if(runnerCnt != 1) {
|
||||
printf("Error: runner count != 1 (%d)\n", runnerCnt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if( !*(runnerBase + RUNNER_ENABLE_OFFSET)) {
|
||||
runnerBase += RUNNER_STEP_SIZE;
|
||||
continue;
|
||||
}
|
||||
runnerX = *(runnerBase + RUNNER_X_OFFSET);
|
||||
runnerY = *(runnerBase + RUNNER_Y_OFFSET);
|
||||
if(runnerX < 1 || runnerX > CLASSIC_MAP_X_SIZE) {
|
||||
printf("Error: wrong runnerX value (%d)\n", runnerX);
|
||||
return 1;
|
||||
}
|
||||
if(runnerY < 1 || runnerY > CLASSIC_MAP_Y_SIZE) {
|
||||
printf("Error: wrong runnerY value (%d)\n", runnerY);
|
||||
return 1;
|
||||
}
|
||||
if(mapClassic[runnerX-1][runnerY-1] != CLASSIC_TILE_EMPTY) {
|
||||
if(runnerY == 1 && getTile(runnerX, runnerY, 8) == 8) {
|
||||
mapClassic[runnerX-1][runnerY-1] = CLASSIC_TILE_RUNNER;
|
||||
} else {
|
||||
printf("Error runner position already has value exist (%d, %d)\n", runnerX, runnerY);
|
||||
}
|
||||
//return 1;
|
||||
} else {
|
||||
mapClassic[runnerX-1][runnerY-1] = CLASSIC_TILE_RUNNER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for(int i = 1; i <= guardCnt; i++) {
|
||||
guardX = *(guardBase + GUARD_X_OFFSET);
|
||||
guardY = *(guardBase + GUARD_Y_OFFSET);
|
||||
if(guardX < 1 || guardX > CLASSIC_MAP_X_SIZE) {
|
||||
//printf("Error: wrong guardX value (%d)\n", guardX);
|
||||
continue;
|
||||
}
|
||||
if(guardY < 1 || guardY > CLASSIC_MAP_Y_SIZE) {
|
||||
//printf("Error: wrong guardY value (%d)\n", guardY);
|
||||
continue;
|
||||
}
|
||||
if(mapClassic[guardX-1][guardY-1] != CLASSIC_TILE_EMPTY) {
|
||||
if(guardY == 1 && getTile(guardX, guardY, 8) == 8) {
|
||||
mapClassic[guardX-1][guardY-1] = CLASSIC_TILE_GUARD;
|
||||
} else {
|
||||
printf("Error guard position already has value exist (%d, %d)\n", guardX, guardY);
|
||||
}
|
||||
} else {
|
||||
mapClassic[guardX-1][guardY-1] = CLASSIC_TILE_GUARD;
|
||||
}
|
||||
guardBase += GUARD_STEP_SIZE;;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int online2Classic(int pzlNumber)
|
||||
{
|
||||
//memset(mapClassic, CLASSIC_TILE_EMPTY, CLASSIC_MAP_SIZE);
|
||||
printf("//======<<< Level %03d >>>======\n\n", pzlNumber);
|
||||
|
||||
//(1) Set Turf
|
||||
for(int x=1; x <= CLASSIC_MAP_X_SIZE; x++) {
|
||||
for(int y=1; y <= CLASSIC_MAP_Y_SIZE; y++) {
|
||||
int layer8 = getTile(x, y, 8);
|
||||
int layer9 = getTile(x, y, 9);
|
||||
int id = layer8 * 10 + layer9;
|
||||
|
||||
switch(id) {
|
||||
case 0: //empty
|
||||
mapClassic[x-1][y-1] = CLASSIC_TILE_EMPTY;
|
||||
break;
|
||||
case 11: //normal brick
|
||||
mapClassic[x-1][y-1] = CLASSIC_TILE_BRICK;
|
||||
break;
|
||||
case 12: //solid brick
|
||||
mapClassic[x-1][y-1] = CLASSIC_TILE_SOLID;
|
||||
break;
|
||||
case 51: //ladder
|
||||
mapClassic[x-1][y-1] = CLASSIC_TILE_LADDER;
|
||||
break;
|
||||
case 61: //bar
|
||||
mapClassic[x-1][y-1] = CLASSIC_TILE_BAR;
|
||||
break;
|
||||
case 26: //trap brick
|
||||
mapClassic[x-1][y-1] = CLASSIC_TILE_TRAP;
|
||||
break;
|
||||
case 52: //end game ladder
|
||||
mapClassic[x-1][y-1] = CLASSIC_TILE_EXIT_LADDER;
|
||||
break;
|
||||
default:
|
||||
if(layer8 == 8) {
|
||||
if(layer9 == 1 && y == 1 && getTile(x, y+1, 8) == 5 && getTile(x, y+1, 9) == 2) {
|
||||
//exit door (layer8=8, layer9=1) at top position and pos(x,y+1) = exit ladder (5,2)
|
||||
// set this tile as "exit ladder"
|
||||
mapClassic[x-1][y-1] = CLASSIC_TILE_EXIT_LADDER;
|
||||
} else {
|
||||
//exit door set as empty
|
||||
mapClassic[x-1][y-1] = CLASSIC_TILE_EMPTY;
|
||||
}
|
||||
} else {
|
||||
printf("Error: can not recognize tile, (lay8, lay9) = (%d, %d)\n",layer8, layer9);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//(2) Set Tool
|
||||
for(int x=1; x <= CLASSIC_MAP_X_SIZE; x++) {
|
||||
for(int y=1; y <= CLASSIC_MAP_Y_SIZE; y++) {
|
||||
int layer1 = getTile(x, y, 1);
|
||||
//int layer2 = getTile(x, y, 2);
|
||||
if(layer1 != 0) {
|
||||
if(mapClassic[x-1][y-1] != CLASSIC_TILE_EMPTY) {
|
||||
//skip
|
||||
//printf("Error: value exist (%d, %d)\n", x, y);
|
||||
} else {
|
||||
mapClassic[x-1][y-1] = CLASSIC_TILE_GOLD;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//(3) Set Guy
|
||||
mapClassicAddGuy();
|
||||
|
||||
//(4) dump level
|
||||
for(int y=0; y < CLASSIC_MAP_Y_SIZE; y++) {
|
||||
printf("\"");
|
||||
for(int x=0; x < CLASSIC_MAP_X_SIZE; x++) {
|
||||
printf("%c", mapClassic[x][y]);
|
||||
}
|
||||
if(y < CLASSIC_MAP_Y_SIZE-1) printf("\" +\n");
|
||||
else printf("\",");
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
}
|
||||
|
||||
int dumpPuzzlLevel(FILE *fp)
|
||||
{
|
||||
WORD pzlHeader[4];
|
||||
BYTE pzlCompBuf[PZL_MAX_COMP_SIZE];
|
||||
int pzlCompSize, nRead;
|
||||
|
||||
if((nRead = fread(pzlHeader, 1, sizeof(pzlHeader), fp ) )!= sizeof(pzlHeader)) {
|
||||
if(nRead == 0) {
|
||||
//printf("End of File !!!\n");
|
||||
} else {
|
||||
printf("Read puzzle head failed !\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
pzlCompSize = pzlHeader[0] + PZL_SIZE_ADDR; //include header size
|
||||
|
||||
if( pzlCompSize < 100 || pzlCompSize > PZL_MAX_COMP_SIZE) {
|
||||
printf("Puzzle Size too short or too long (%d)\n", pzlCompSize);
|
||||
return 1;
|
||||
}
|
||||
if (pzlHeader[1] != 0) {
|
||||
printf("Puzzle wrong format (header[1] != 0) \n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// copy the header to pzlBuf
|
||||
memcpy(pzlCompBuf, pzlHeader, sizeof(pzlHeader));
|
||||
|
||||
// read puzzle body (skip header)
|
||||
if(fread(pzlCompBuf+sizeof(pzlHeader), 1, pzlCompSize - sizeof(pzlHeader), fp ) != (pzlCompSize - sizeof(pzlHeader))) {
|
||||
printf("Read puzzle body failed !\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// check for final byte to be a zero
|
||||
if (pzlCompBuf[pzlCompSize - 1] != 0)
|
||||
{
|
||||
printf("Puzzle body final byte != 0, failed !\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pzlDecompress(pzlCompBuf, pzlCompSize) == 0) {
|
||||
//displayTextPzl(pzlHeader[2]);
|
||||
online2Classic(pzlHeader[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dumpAllLevels(FILE *fp)
|
||||
{
|
||||
printf("//************************************************************\n");
|
||||
printf("//* All levels extract from: \n");
|
||||
printf("//* CGW \n");
|
||||
printf("//* by Simon Hung 2015/01/14\n");
|
||||
printf("//************************************************************\n");
|
||||
|
||||
printf("\nvar spoonbill = [\n");
|
||||
while(dumpPuzzlLevel(fp) == 0);
|
||||
printf("];\n");
|
||||
}
|
||||
|
||||
void usage(char *fileName)
|
||||
{
|
||||
printf("%s <Lode Runner *.pzl file>\n", strrchr(fileName,'\\')+1 );
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if(argc < 2) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if((fp = fopen(argv[1], "rb")) == NULL) {
|
||||
printf("Open file %s failed \n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//(1) check head
|
||||
if(checkHead(fp))return 1; //failed
|
||||
|
||||
//(2) read puzzle block
|
||||
dumpAllLevels(fp);
|
||||
//dumpPuzzlLevel(fp);
|
||||
//dumpPuzzlLevel(fp);
|
||||
}
|
||||
Fichier binaire non affiché.
Référencer dans un nouveau ticket
Bloquer un utilisateur