#include #include #include #include #include #include #include #include "getopt.h" #include "misc.h" #include "typedefs.h" #include "seq.h" #include "debug4g.h" #define kMaxFrames 1024 struct SEQFRAME1 { unsigned nTile : 16; signed shade : 8; unsigned translucent : 1; unsigned blocking : 1; unsigned hitscan : 1; unsigned pal : 4; }; struct Seq1 { char signature[4]; short version; short nFrames; // sequence length short ticksPerFrame; // inverted play rate short keyFrame; uchar flags; char pad[3]; SEQFRAME1 frame[1]; }; struct SEQFRAME2 { unsigned nTile : 12; unsigned reserved1 : 3; unsigned translucentR : 1; signed shade : 8; unsigned translucent : 1; unsigned blocking : 1; unsigned hitscan : 1; unsigned pal : 5; unsigned xrepeat : 8; unsigned yrepeat : 8; unsigned reserved2 : 16; }; struct Seq2 { char signature[4]; short version; short nFrames; // sequence length short ticksPerFrame; // inverted play rate short keyFrame; uchar flags; char pad[3]; SEQFRAME2 frame[1]; }; struct FNODE { FNODE *next; char name[1]; }; FNODE head = { &head, "" }; FNODE *tail = &head; BOOL bForcePal = FALSE; uchar nPal; BOOL bForceShade = FALSE; char nShade; BOOL bForceXRepeat = FALSE; uchar xrepeat; BOOL bForceYRepeat = FALSE; uchar yrepeat; BOOL bForceTranslucent = FALSE; BOOL bIsTranslucent; BOOL bIsTranslucentR; Seq *pSeq = NULL; /******************************************************************************* FUNCTION: ShowBanner() DESCRIPTION: Show application banner *******************************************************************************/ void ShowBanner( void ) { printf("ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n"); printf("SEQ Loathing Update Tool Version 3.0 Copyright (c) 1995 Q Studios Corporation\n"); printf("ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ\n"); } /******************************************************************************* FUNCTION: ShowUsage() DESCRIPTION: Display command-line parameter usage, then exit *******************************************************************************/ void ShowUsage(void) { printf("Syntax: SLUT [options] files[.seq]\n"); printf("-pN force all palookups to N\n"); printf("-sN force all shade values to N\n"); printf("-t[0|1|2] force translucency level\n"); printf("-xN force all x repeats to N\n"); printf("-yN force all y repeats to N\n"); printf("-? This help\n"); exit(0); } /******************************************************************************* FUNCTION: QuitMessage() DESCRIPTION: Display a printf() style message, the exit with code 1 *******************************************************************************/ void QuitMessage(char * fmt, ...) { char msg[80]; va_list argptr; va_start( argptr, fmt ); vsprintf( msg, fmt, argptr ); va_end(argptr); printf(msg); exit(1); } void ProcessFile(char *filename) { char bakname[_MAX_PATH], tempname[_MAX_PATH]; int i, hFile, nSize; strcpy(bakname, filename); ChangeExtension(bakname, ".BAK"); tmpnam(tempname); printf("%s: ", filename); hFile = open(filename, O_RDONLY | O_BINARY); if ( hFile == -1 ) QuitMessage("Couldn't open file %s, errno=%d\n", filename, errno); nSize = filelength(hFile); Seq *pTempSeq = (Seq *)malloc(nSize); dassert(pTempSeq != NULL); if ( !FileRead(hFile, pTempSeq, nSize) ) { close(hFile); QuitMessage("Error reading SEQ file"); } close(hFile); memcpy(pSeq, pTempSeq, nSize); if (memcmp(pSeq->signature, kSEQSig, sizeof(pSeq->signature)) != 0) QuitMessage("SEQ file corrupted"); switch ( pTempSeq->version >> 8 ) { case 3: break; // current version case 2: { // convert old sequence format Seq2 *pSeq2 = (Seq2 *)pTempSeq; memset(pSeq, 0, sizeof(Seq)); pSeq->nFrames = pSeq2->nFrames; pSeq->ticksPerFrame = pSeq2->ticksPerFrame; // check version 2 minor version switch ( pTempSeq->version & 0xFF ) { case 2: pSeq->flags = pSeq2->flags; for (i = 0; i < pSeq2->nFrames; i++) { memset(&pSeq->frame[i], 0, sizeof(SEQFRAME)); pSeq->frame[i].nTile = pSeq2->frame[i].nTile; pSeq->frame[i].translucent = pSeq2->frame[i].translucent; pSeq->frame[i].translucentR = pSeq2->frame[i].translucentR; pSeq->frame[i].blocking = pSeq2->frame[i].blocking; pSeq->frame[i].hitscan = pSeq2->frame[i].hitscan; pSeq->frame[i].xrepeat = pSeq2->frame[i].xrepeat; pSeq->frame[i].yrepeat = pSeq2->frame[i].yrepeat;; pSeq->frame[i].shade = pSeq2->frame[i].shade; pSeq->frame[i].pal = pSeq2->frame[i].pal; } break; case 1: pSeq->flags = pSeq2->flags; for (i = 0; i < pSeq2->nFrames; i++) { memset(&pSeq->frame[i], 0, sizeof(SEQFRAME)); pSeq->frame[i].nTile = pSeq2->frame[i].nTile; pSeq->frame[i].translucent = pSeq2->frame[i].translucent; pSeq->frame[i].translucentR = 0; pSeq->frame[i].blocking = pSeq2->frame[i].blocking; pSeq->frame[i].hitscan = pSeq2->frame[i].hitscan; pSeq->frame[i].xrepeat = pSeq2->frame[i].xrepeat; pSeq->frame[i].yrepeat = pSeq2->frame[i].yrepeat;; pSeq->frame[i].shade = pSeq2->frame[i].shade; pSeq->frame[i].pal = pSeq2->frame[i].pal; } break; case 0: pSeq->flags = 0; for (i = 0; i < pSeq2->nFrames; i++) { memset(&pSeq->frame[i], 0, sizeof(SEQFRAME)); pSeq->frame[i].nTile = pSeq2->frame[i].nTile; pSeq->frame[i].translucent = pSeq2->frame[i].translucent; pSeq->frame[i].translucentR = 0; pSeq->frame[i].blocking = pSeq2->frame[i].blocking; pSeq->frame[i].hitscan = pSeq2->frame[i].hitscan; pSeq->frame[i].xrepeat = pSeq2->frame[i].xrepeat; pSeq->frame[i].yrepeat = pSeq2->frame[i].yrepeat;; pSeq->frame[i].shade = pSeq2->frame[i].shade; pSeq->frame[i].pal = pSeq2->frame[i].pal; } break; } break; } case 1: { // convert old sequence format Seq1 *pSeq1 = (Seq1 *)pTempSeq; memset(pSeq, 0, sizeof(Seq)); pSeq->nFrames = pSeq1->nFrames; pSeq->ticksPerFrame = pSeq1->ticksPerFrame; for (i = 0; i < pSeq1->nFrames; i++) { memset(&pSeq->frame[i], 0, sizeof(SEQFRAME)); pSeq->frame[i].nTile = pSeq1->frame[i].nTile; pSeq->frame[i].translucent = pSeq1->frame[i].translucent; pSeq->frame[i].blocking = pSeq1->frame[i].blocking; pSeq->frame[i].hitscan = pSeq1->frame[i].hitscan; pSeq->frame[i].xrepeat = 64; pSeq->frame[i].yrepeat = 64; pSeq->frame[i].shade = pSeq1->frame[i].shade; pSeq->frame[i].pal = pSeq1->frame[i].pal; } break; } default: QuitMessage("Obsolete SEQ version"); } free(pTempSeq); // set forced frame attributes for (i = 0; i < pSeq->nFrames; i++) { if ( bForcePal ) pSeq->frame[i].pal = nPal; if ( bForceShade ) pSeq->frame[i].shade = nShade; if ( bForceTranslucent ) { if (bIsTranslucent) pSeq->frame[i].translucent = 1; else pSeq->frame[i].translucent = 0; if (bIsTranslucentR) pSeq->frame[i].translucentR = 1; else pSeq->frame[i].translucentR = 0; } if ( bForceXRepeat ) pSeq->frame[i].xrepeat = xrepeat; if ( bForceYRepeat ) pSeq->frame[i].yrepeat = yrepeat; } hFile = open(tempname, O_CREAT | O_WRONLY | O_BINARY | O_TRUNC, S_IWUSR); if ( hFile == -1 ) QuitMessage("Error creating temporary file"); memcpy(pSeq->signature, kSEQSig, sizeof(pSeq->signature)); pSeq->version = kSEQVersion; if ( !FileWrite(hFile, pSeq, sizeof(Seq) + pSeq->nFrames * sizeof(SEQFRAME)) ) { close(hFile); QuitMessage("Error writing temporary file"); } close(hFile); // backup the existing sequence unlink(bakname); rename(filename, bakname); rename(tempname, filename); printf("done.\n"); } void InsertFilename( char *fname ) { FNODE *n = (FNODE *)malloc(sizeof(FNODE) + strlen(fname)); strcpy(n->name, fname); // insert the node at the tail, so it stays in order n->next = tail->next; tail->next = n; tail = n; } void ProcessArgument(char *s) { char filespec[_MAX_PATH]; char buffer[_MAX_PATH2]; char path[_MAX_PATH]; strcpy(filespec, s); AddExtension(filespec, ".SEQ"); char *drive, *dir; // separate the path from the filespec _splitpath2(s, buffer, &drive, &dir, NULL, NULL); _makepath(path, drive, dir, NULL, NULL); struct find_t fileinfo; unsigned r = _dos_findfirst(s, _A_NORMAL, &fileinfo); if (r != 0) printf("%s not found\n", s); while ( r == 0 ) { strcpy(filespec, path); strcat(filespec, fileinfo.name); InsertFilename(filespec); r = _dos_findnext( &fileinfo ); } _dos_findclose(&fileinfo); } /*********************************************************************** * Process command line arguments **********************************************************************/ void ParseOptions( void ) { enum { kSwitchHelp, kSwitchForcePal, kSwitchForceShade, kSwitchForceTrans, kSwitchXRepeat, kSwitchYRepeat, }; static SWITCH switches[] = { { "?", kSwitchHelp, FALSE }, { "P", kSwitchForcePal, TRUE }, { "S", kSwitchForceShade, TRUE }, { "T", kSwitchForceTrans, TRUE }, { "X", kSwitchXRepeat, TRUE }, { "Y", kSwitchYRepeat, TRUE }, { NULL, 0, FALSE }, }; int value; int r; while ( (r = GetOptions(switches)) != GO_EOF ) { switch (r) { case GO_INVALID: QuitMessage("Invalid argument: %s", OptArgument); case GO_FULL: ProcessArgument(OptArgument); break; case kSwitchForcePal: value = strtol(OptArgument, NULL, 0); bForcePal = TRUE; nPal = (uchar)value; break; case kSwitchForceShade: value = strtol(OptArgument, NULL, 0); bForceShade = TRUE; nShade = (char)value; break; case kSwitchForceTrans: value = strtol(OptArgument, NULL, 0); bForceTranslucent = TRUE; switch(value) { case 0: bIsTranslucent = bIsTranslucentR = FALSE; break; case 1: bIsTranslucent = TRUE; bIsTranslucentR = FALSE; break; case 2: bIsTranslucent = bIsTranslucentR = TRUE; break; default: QuitMessage("Invalid translucency argument: %s", OptArgument); break; } break; case kSwitchXRepeat: value = strtol(OptArgument, NULL, 0); bForceXRepeat = TRUE; xrepeat = (uchar)value; break; case kSwitchYRepeat: value = strtol(OptArgument, NULL, 0); bForceYRepeat = TRUE; yrepeat = (uchar)value; break; } } } void main( int argc ) { ShowBanner(); pSeq = (Seq *)malloc(sizeof(Seq) + kMaxFrames * sizeof(SEQFRAME)); dassert(pSeq != NULL); if (argc < 2) ShowUsage(); ParseOptions(); // process the file list for (FNODE *n = head.next; n != &head; n = n->next) ProcessFile(n->name); }