/**********************************************************************************************************************************/ /* File : WADINFO.C */ /* Executable : WADINFO.EXE */ /* Doc file : WADINFO.DOC */ /* Version num : 1.04 */ /* Last changed : 16-09-1994 21:49 */ /* Update count : 7 */ /* OS type : if _AMIGA_ set : AMIGA (Intuition, multitasking) */ /* Compiler : Aztec C Version 5.0a Copyright 1989 by Manx Software Systems Inc. (Jan 9 1990) */ /* Linker : Aztec C68K Linker Version 5.0a Copyright 1989 by Manx Software System Inc. */ /* LN attr : -lm -lc */ /* if _AMIGA_ cleared: PC (DOS, singletasking) */ /* Compiler : Microsoft (R) Quick C Compiler Version 2.50 */ /* Linker : Microsoft (R) QuickC Linker Version 4.10 */ /* QCL attr : /AC /G2 /Ox /F 1000 /link GRAPHICS.LIB */ /* Description : Information extractor for DOOM (TM) WAD files. */ /* Other : None */ /* */ /* By M. van der Heide of ThunderWare Research Center */ /**********************************************************************************************************************************/ /* Uncomment this line if compiling on the AMIGA */ /* #define _AMIGA_ */ #ifdef _AMIGA_ #include #include #else #pragma check_pointer (off) #pragma check_stack (off) #include #include #include #endif #include #include #include #include #include #define boolean char #ifdef _AMIGA_ #define dbyte short /* An 'int' is 4 bytes ('long') in stead of 2 on an Amiga */ #else #define dbyte int #define TRUE 1 #define FALSE 0 #endif #define DBLACK 0 /* Define names for the standard (VGA) palette colors */ #define DBLUE 1 #define DGREEN 2 #define DCYAN 3 #define DRED 4 #define DMAGENTA 5 #define DYELLOW 6 #define DWHITE 7 #define LBLACK 8 #define LBLUE 9 #define LGREEN 10 #define LCYAN 11 #define LRED 12 #define LMAGENTA 13 #define LYELLOW 14 #define LWHITE 15 #define NUMEPISODE 3 /* Define total number of episodes and levels/episode */ #define NUMLEVEL 9 #define MAXCOLORS 2 /* Define number of WAD 'directory' identifiers per type */ #define MAXLEVELS NUMEPISODE * NUMLEVEL #define MAXSPRITES 77 #define MAXMUSIC 32 #define MAXSOUNDS 122 #define MAXGRAPHS 0 #define MAXINSTRUMENTS 1 #define MAXSTATUSBAR 2 #define MAXMENUS 39 #define MAXLINEDRLF 17 /* Define the number of 'important' LineDef type fields */ #define MAXLINESWITCH 41 #define MAXLINEEND 4 #define NEWCOLORS 0x01 /* Define bit-wise (storage) values for these types */ #define NEWSOUNDS 0x02 #define NEWSPRITES 0x04 #define NEWMUSIC 0x08 #define NEWGRAPHS 0x10 #define NEWINSTRUMENTS 0x20 #define NEWSTATUSBAR 0x40 #define NEWMENUS 0x80 #define THING_PLAYER1 1 /* Define the THINGS to check for : */ #define THING_PLAYER2 2 /* Starting areas */ #define THING_PLAYER3 3 #define THING_PLAYER4 4 #define THING_DEATHMATCH 11 #define THING_CHAINSAW 2005 /* Weapons */ #define THING_SHOTGUN 2001 #define THING_CHAINGUN 2002 #define THING_LAUNCHER 2003 #define THING_PLASMAGUN 2004 #define THING_BFG9000 2006 #define THING_TROOPER 3004 /* Enemies */ #define THING_SARGEANT 9 #define THING_IMP 3001 #define THING_DEMON 3002 #define THING_SPECTRE 58 #define THING_CACODEMON 3005 #define THING_LOSTSOUL 3006 #define THING_BARON 3003 #define THING_CYBERDEMON 16 #define THING_SPIDERBOSS 7 #define TYPE_CHAINSAW 0 /* Define index-values for the THINGS identifiers */ #define TYPE_SHOTGUN 1 #define TYPE_CHAINGUN 2 #define TYPE_LAUNCHER 3 #define TYPE_PLASMAGUN 4 #define TYPE_BFG9000 5 #define TYPE_TROOPER 6 #define TYPE_SARGEANT 7 #define TYPE_IMP 8 #define TYPE_DEMON 9 #define TYPE_SPECTRE 10 #define TYPE_CACODEMON 11 #define TYPE_LOSTSOUL 12 #define TYPE_BARON 13 #define TYPE_CYBERDEMON 14 #define TYPE_SPIDERBOSS 15 #define WHEN_D12 0x0001 /* Define difficulties for when a things appears */ #define WHEN_D3 0x0002 #define WHEN_D45 0x0004 #define WHEN_MULTI 0x0010 struct WadInfo_s /* Group the main info on the WAD file together */ { char NewStuff; /* Things other than levels patched */ long NewLevels; dbyte NewDemos; }; struct WadHeader_s /* The first bytes of a WAD file: the WAD header */ { char Type[4]; /* Should be "PWAD" or "IWAD" for a (valid) WAD file */ unsigned long DirSize; /* Number of entries in the WAD 'directory' */ unsigned long DirStart; /* Pointer to start of the WAD 'directory' */ }; struct Directory_s /* One entry in the WAD 'directory' */ { unsigned long Start; /* Pointer to the data of this entry */ unsigned long Size; /* Length of this data in bytes */ char Name[8]; /* Type identifier */ }; struct Thing_s /* One entry of the 'directory' entry type "THINGS" */ { dbyte Xpos; /* Position on the map */ dbyte Ypos; dbyte Angle; /* Facing direction: north, east, etc... */ dbyte Type; /* Thing type */ dbyte When; /* Appears when ? */ }; struct Vertex_s { dbyte MapX; dbyte MapY; }; struct LineDef_s { dbyte Start; dbyte End; dbyte Flags; dbyte Type; dbyte Tag; dbyte SideDef1; dbyte SideDef2; }; struct SideDef_s { dbyte OffsetX; dbyte OffsetY; char UpperTexture[8]; char LowerTexture[8]; char NormalTexture[8]; }; struct Seg_s { dbyte Start; dbyte End; dbyte Angle; dbyte LineDef; dbyte Flip; dbyte Distance; }; struct Sector_s { dbyte FloorHeight; dbyte CeilingHeight; char FloorTexture[8]; char CeilingTexture[8]; dbyte LightLevel; dbyte Special; dbyte Tag; }; struct SubSector_s { dbyte NumberOfSegs; dbyte FirstSeg; }; struct Node_s { dbyte X; dbyte Y; dbyte Dx; dbyte Dy; dbyte FirstUpperBoundY; dbyte FirstLowerBoundY; dbyte FirstUpperBoundX; dbyte FirstLowerBoundX; dbyte SecondUpperBoundY; dbyte SecondLowerBoundY; dbyte SecondUpperBoundX; dbyte SecondLowerBoundX; dbyte Child1; dbyte Child2; }; struct BlockMapHeader_s { dbyte OriginX; dbyte OriginY; dbyte BlockCntX; dbyte BlockCntY; }; struct Remember_s { int PlayerStarts[5]; /* 1-4 = startno, 5 = deathmatch start */ int ThingType[16][4]; /* 1 = D12, 2 = D3, 3 = D45, 4 = Multi */ dbyte MinMapX; /* Vertex info */ dbyte MinMapY; dbyte MaxMapX; dbyte MaxMapY; dbyte MapSizeX; dbyte MapSizeY; struct Directory_s ThingsLoc; struct Directory_s VertexLoc; struct Directory_s LineDefLoc; struct Directory_s SideDefLoc; struct Directory_s SegLoc; struct Directory_s SectorLoc; struct Directory_s SubSectorLoc; struct Directory_s NodeLoc; struct Directory_s RejectDataLoc; struct Directory_s BlockMapLoc; boolean ThingsFilled; boolean StatsFilled; }; struct Check_s { dbyte StartMapX; dbyte StartMapY; dbyte EndMapX; dbyte EndMapY; }; struct FieldId_s { char *IdName; char *Description; char Type; boolean FieldFilled; }; struct WadHeader_s WadHeader; struct Directory_s Directory; struct WadInfo_s WadInfo; struct Thing_s Thing; struct Vertex_s Vertex; struct Remember_s Remember[27]; char *Levels[] = {"E1M1", "E1M2", "E1M3", "E1M4", "E1M5", "E1M6", "E1M7", "E1M8", "E1M9", "E2M1", "E2M2", "E2M3", "E2M4", "E2M5", "E2M6", "E2M7", "E2M8", "E2M9", "E3M1", "E3M2", "E3M3", "E3M4", "E3M5", "E3M6", "E3M7", "E3M8", "E3M9"}; char *Colors[] = {"PLAYPAL", "COLORMAP"}; char *StatusBar[] = {"AMMNUM", "ST"}; char *Instruments[] = {"GENMIDI"}; struct FieldId_s Music[] = {{"DMXGUS", "Gravis Ultra Sound driver" }, {"D_INTRO", "Introduction music" }, {"D_INTER", "Between levels" }, {"D_VICTOR", "After completing an episode" }, {"D_BUNNY", "While bunny is on the screen" }, {"D_E1M1", "Episode 1 Level 1" }, {"D_E1M2", "Episode 1 Level 2" }, {"D_E1M3", "Episode 1 Level 3" }, {"D_E1M4", "Episode 1 Level 4" }, {"D_E1M5", "Episode 1 Level 5" }, {"D_E1M6", "Episode 1 Level 6" }, {"D_E1M7", "Episode 1 Level 7" }, {"D_E1M8", "Episode 1 Level 8" }, {"D_E1M9", "Episode 1 Level 9" }, {"D_E2M1", "Episode 2 Level 1" }, {"D_E2M2", "Episode 2 Level 2" }, {"D_E2M3", "Episode 2 Level 3" }, {"D_E2M4", "Episode 2 Level 4" }, {"D_E2M5", "Episode 2 Level 5" }, {"D_E2M6", "Episode 2 Level 6" }, {"D_E2M7", "Episode 2 Level 7" }, {"D_E2M8", "Episode 2 Level 8" }, {"D_E2M9", "Episode 2 Level 9" }, {"D_E3M1", "Episode 3 Level 1" }, {"D_E3M2", "Episode 3 Level 2" }, {"D_E3M3", "Episode 3 Level 3" }, {"D_E3M4", "Episode 3 Level 4" }, {"D_E3M5", "Episode 3 Level 5" }, {"D_E3M6", "Episode 3 Level 6" }, {"D_E3M7", "Episode 3 Level 7" }, {"D_E3M8", "Episode 3 Level 8" }, {"D_E3M9", "Episode 3 Level 9" }}; struct FieldId_s Menus[] = {{"M_DOOM", "DOOM", 0}, {"M_NGAME", "New Game", 0}, {"M_OPTION", "Options", 0}, {"M_LOADG", "Load Game", 0}, {"M_SAVEG", "Save Game", 0}, {"M_RDTHIS", "Read This!", 0}, {"M_QUITG", "Quit Game", 0}, {"M_EPISOD", "Which Episode?", 1}, {"M_EPI1", "Knee-Deep in the Dead", 1}, {"M_EPI2", "The Shores of Hell", 1}, {"M_EPI3", "Inferno", 1}, {"M_NEWG", "New Game", 1}, {"M_SKILL", "Choose a Skill Level", 1}, {"M_JKILL", "I'm too young to die", 1}, {"M_ROUGH", "Hey, not too rough", 1}, {"M_HURT", "Hurt me planty", 1}, {"M_ULTRA", "Ultra-Violence!", 1}, {"M_NMARE", "Nightmare", 1}, {"M_SVOL", "Sound Volume", 1}, {"M_SFXVOL", "Sfx Volume", 1}, {"M_MUSVOL", "Music Volume", 1}, {"M_ENDGAM", "End Game", 2}, {"M_PAUSE", "Pause", 2}, {"M_MESSG", "Messages:", 2}, {"M_MSGON", "on", 2}, {"M_MSGOFF", "off", 2}, {"M_OPTTTL", "Options", 2}, {"M_DISP", "Display", 2}, {"M_MSENS", "Mouse Sensitivity", 2}, {"M_GDHIGH", "high", 2}, {"M_GDLOW", "low", 2}, {"M_DETAIL", "Graphic Detail", 2}, {"M_DISOPT", "Display options", 2}, {"M_SCRNSZ", "Screen Size", 2}, {"M_SGTTL", "Save Game", 2}, {"M_LGTTL", "Load Game", 2}, {"M_SKULL", "Selection skull", 3}, {"M_THERM", "Volume slider", 3}, {"M_LS", "Game name field in load/save", 3}}; struct FieldId_s Sprites[] = {{"PLAY", "Player", 0}, {"POSS", "Trooper", 0}, {"SPOS", "Sargeant", 0}, {"TROO", "Imp", 0}, {"SARG", "Demon & Spectre", 0}, {"HEAD", "Caco Demon", 0}, {"SKUL", "Lost Soul", 0}, {"BOSS", "Baron of Hell", 0}, {"CYBR", "Cyber Demon", 0}, {"SPID", "Spider Demon", 0}, {"BKEY", "Blue keycard", 1}, {"YKEY", "Yellow keycard", 1}, {"RKEY", "Red keycard", 1}, {"BSKU", "Blue skullkey", 1}, {"YSKU", "Yellow skullkey", 1}, {"RSKU", "Red skullkey", 1}, {"PUN", "Nothing in hand", 2}, {"SAW", "Chainsaw in hand", 2}, {"PIS", "Pistol in hand", 2}, {"SHT", "Shotgun in hand", 2}, {"CHG", "Chaingun in hand", 2}, {"PLS", "Plasmagun in hand", 2}, {"BFG", "BFG9000 in hand", 2}, {"CSAW", "Chainsaw", 2}, {"SHOT", "Shotgun", 2}, {"MGUN", "Chaingun", 2}, {"LAUN", "Rocket launcher", 2}, {"PLAS", "Plasmagun", 2}, {"BFUG", "BFG9000", 2}, {"CLIP", "Ammoclip", 3}, {"AMMO", "Box of ammo", 3}, {"SHEL", "Shells", 3}, {"SBOX", "Box of shells", 3}, {"ROCK", "Rockets", 3}, {"BROK", "Box of rockets", 3}, {"CELL", "Cells", 3}, {"CELP", "Box of cells", 3}, {"BPAK", "Backpack", 3}, {"BON1", "Healthbonus", 4}, {"BON2", "Armorbonus", 4}, {"STIM", "Stimpack", 4}, {"MEDI", "Medikit", 4}, {"ARM1", "Green armor", 4}, {"ARM2", "Blue armor", 4}, {"SOUL", "Supercharge", 4}, {"PINS", "Invisibility", 4}, {"PINV", "Invulnerability", 4}, {"PSTR", "Berserk", 4}, {"PMAP", "Computer area map", 4}, {"PVIS", "Light amplifier", 4}, {"SUIT", "Radiation suit", 4}, {"BAR", "Barrel", 5}, {"BEXP", "Barrel exploding", 5}, {"POL", "Dead body", 5}, {"GOR", "Hanging body", 5}, {"PBU", NULL, 6}, {"PSH", NULL, 6}, {"BAL", NULL, 6}, {"PUF", NULL, 6}, {"BLU", NULL, 6}, {"MIS", NULL, 6}, {"TFO", NULL, 6}, {"BFS", NULL, 6}, {"BFE", NULL, 6}, {"CAND", NULL, 7}, {"CBRA", NULL, 7}, {"COLU", NULL, 7}, {"ELEC", NULL, 7}, {"TRED", NULL, 7}, {"FSKU", NULL, 7}, {"CEYE", NULL, 7}, {"SMI", NULL, 7}, {"TGRN", NULL, 7}, {"TBLU", NULL, 7}, {"SMRT", NULL, 7}, {"SMBT", NULL, 7}, {"SMGT", NULL, 7}}; struct FieldId_s Sounds[] = {{"DPPISTOL", "Pistol fire " }, {"DSPISTOL", NULL }, {"DPSHOTGN", "Shotgun fire " }, {"DSSHOTGN", NULL }, {"DPSGCOCK", "Shotgun cock " }, {"DSSGCOCK", NULL }, {"DPSAWUP", "Chainsaw startup " }, {"DSSAWUP", NULL }, {"DPSAWIDL", "Chainsaw in rest " }, {"DSSAWIDL", NULL }, {"DPSAWFUL", "Chainsaw active " }, {"DSSAWFUL", NULL }, {"DPSAWHIT", "Chainsaw hitting " }, {"DSSAWHIT", NULL }, {"DPRLAUNC", "Rocket launch " }, {"DSRLAUNC", NULL }, {"DPRXPLOD", "BFG9000 launch " }, {"DSRXPLOD", NULL }, {"DPFIRSHT", "Fireball passing " }, {"DSFIRSHT", NULL }, {"DPFIRXPL", "Fireball hitting " }, {"DSFIRXPL", NULL }, {"DPPSTART", "Lift starting " }, {"DSPSTART", NULL }, {"DPPSTOP", "Lift stopping " }, {"DSPSTOP", NULL }, {"DPDOROPN", "Door opening " }, {"DSDOROPN", NULL }, {"DPDORCLS", "Door closing " }, {"DSDORCLS", NULL }, {"DPSTNMOV", "Floor moving " }, {"DSSTNMOV", NULL }, {"DPSWTCHN", "Switch returning " }, {"DSSWTCHN", NULL }, {"DPSWTCHX", "Switch activated " }, {"DSSWTCHX", NULL }, {"DPPLPAIN", "Player hurt " }, {"DSPLPAIN", NULL }, {"DPDMPAIN", "Trooper hurt " }, {"DSDMPAIN", NULL }, {"DPPOPAIN", "Sargeant hurt " }, {"DSPOPAIN", NULL }, {"DPSLOP", "Total slaying " }, {"DSSLOP", NULL }, {"DPITEMUP", "Item picked up " }, {"DSITEMUP", NULL }, {"DPWPNUP", "Weapon picked up " }, {"DSWPNUP", NULL }, {"DPOOF", "Player jumping " }, {"DSOOF", NULL }, {"DPTELEPT", "Teleporter " }, {"DSTELEPT", NULL }, {"DPPOSIT1", "Trooper spots (1)" }, {"DSPOSIT1", NULL }, {"DPPOSIT2", "Trooper spots (2)" }, {"DSPOSIT2", NULL }, {"DPPOSIT3", "Trooper spots (3)" }, {"DSPOSIT3", NULL }, {"DPBGSIT1", "Imp spots (1) " }, {"DSBGSIT1", NULL }, {"DPBGSIT2", "Imp spots (2) " }, {"DSBGSIT2", NULL }, {"DPSGTSIT", "Spectre spots " }, {"DSSGTSIT", NULL }, {"DPBRSSIT", "Baron spots " }, {"DSBRSSIT", NULL }, {"DPSGTATK", "Spectre attacks " }, {"DSSGTATK", NULL }, {"DPCLAW", "Spectre hits " }, {"DSCLAW", NULL }, {"DPPLDETH", "Player died " }, {"DSPLDETH", NULL }, {"DPPODTH1", "Trooper died (1) " }, {"DSPODTH1", NULL }, {"DPPODTH2", "Trooper died (2) " }, {"DSPODTH2", NULL }, {"DPPODTH3", "Trooper died (3) " }, {"DSPODTH3", NULL }, {"DPBGDTH1", "Imp died (1) " }, {"DSBGDTH1", NULL }, {"DPBGDTH2", "Imp died (2) " }, {"DSBGDTH2", NULL }, {"DPSGTDTH", "Spectre died " }, {"DSSGTDTH", NULL }, {"DPBRSDTH", "Baron died " }, {"DSBRSDTH", NULL }, {"DPPOSACT", "Trooper nearby " }, {"DSPOSACT", NULL }, {"DPBGACT", "Imp nearby " }, {"DSBGACT", NULL }, {"DPDMACT", "Spectre nearby " }, {"DSDMACT", NULL }, {"DPNOWAY", "Pushed on wall " }, {"DSNOWAY", NULL }, {"DPBAREXP", "Barrel exploding " }, {"DSBAREXP", NULL }, {"DPPUNCH", "Player punching " }, {"DSPUNCH", NULL }, {"DPPLASMA", "Plasmagun fire " }, {"DSPLASMA", NULL }, {"DPBFG", "BFG9000 fire " }, {"DSBFG", NULL }, {"DPCACSIT", "Caco Demon spots " }, {"DSCACSIT", NULL }, {"DPCYBSIT", "Cyber Demon spots" }, {"DSCYBSIT", NULL }, {"DPSPISIT", "Spider spots " }, {"DSSPISIT", NULL }, {"DPSKLATK", "Lost Soul attacks" }, {"DSSKLATK", NULL }, {"DPCACDTH", "Caco Demon died " }, {"DSCACDTH", NULL }, {"DPSKLDTH", "Lost Soul died " }, {"DSSKLDTH", NULL }, {"DPCYBDTH", "Cyber Demon died " }, {"DSCYBDTH", NULL }, {"DPSPIDTH", "Spider Demon died" }, {"DSSPIDTH", NULL }, {"DPHOOF", "Cyber Demon walks" }, {"DSHOOF", NULL }, {"DPMETAL", "Metal (?) " }, {"DSMETAL", NULL }}; dbyte LineDefDoorLift[] = { 1, 21, 26, 27, 28, 31, 32, 33, 34, 99, 117, 118, 133, 134, 135, 136, 137}; dbyte LineDefSwitch[] = { 7, 9, 14, 15, 18, 20, 21, 23, 29, 41, 42, 43, 45, 50, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 101, 102, 103, 111, 112, 113, 114, 115, 116, 122, 123, 127, 131, 132, 140}; dbyte LineDefEndLevel[] = { 11, 51, 52, 124}; #ifdef _AMIGA_ struct GfxBase *GfxBase; /* Pointer to graphics library */ struct IntuitionBase *IntuitionBase; /* Pointer to intuition library */ struct Screen *Screen; /* Pointer to current screen */ struct Window *Window; /* Pointer to current window */ struct NewScreen FirstScreen = {0, 0, 640, 256, 4, DBLACK, DBLACK, HIRES, CUSTOMSCREEN, NULL, NULL, NULL, NULL}; struct NewScreen SecondScreen = {0, 0, 640, 512, 4, DBLACK, DBLACK, HIRES | LACE, CUSTOMSCREEN, NULL, NULL, NULL, NULL}; struct NewWindow FirstWindow = {0, 0, 640, 256, DBLACK, DBLACK, VANILLAKEY, BORDERLESS | ACTIVATE | SMART_REFRESH, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, CUSTOMSCREEN}; struct NewWindow SecondWindow = {0, 0, 640, 480, DBLACK, DBLACK, VANILLAKEY, BORDERLESS | ACTIVATE | SMART_REFRESH, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, CUSTOMSCREEN}; struct IntuiMessage *IntuiMessage; /* Message from intuition */ unsigned long MessageClass; /* 'From' ID */ unsigned short Code; /* Value of the message */ boolean InLaceMode; #else unsigned int Key; #endif void PrText (short Y0, short X0, unsigned char Color, char *Msg, ...) /**********************************************************************************************************************************/ /* Pre : 'Y0' and 'X0' hold the coordinates, 'Color' holds the (VGA) color and 'Msg' holds the message to print. */ /* Post : If the coordinates were non-zero, then the message is printed at these coordinates in the given color. In case of the */ /* AMIGA, the coordinates have been converted from pixel- to textcoordinates. */ /* If X0 = 0, then the coordinates are not used; */ /* If X0 = -1, then the text is centered on line Y0. */ /* Import: None. */ /**********************************************************************************************************************************/ { char Message[80]; va_list Args; int register X1; int register Y1; va_start (Args, Msg); vsprintf (Message, Msg, Args); /* Convert the message into one string */ va_end (Args); #ifdef _AMIGA_ X1 = X0 * 8; /* Fontwidth is 8 pixels */ Y1 = Y0 * 8 + 18; /* Fontheight is 8 pixels, start past the window titlebar */ if (X0 == -1) X1 = ((80 - strlen (Message)) / 2) * 8; if (X0 != 0) Move (&Screen->RastPort, X1, Y1); SetAPen (&Screen->RastPort, Color); Text (&Screen->RastPort, Message, strlen (Message)); #else if (X0 == -1) _settextposition (Y0, (80 - strlen (Message)) / 2); if (X0 > 0) _settextposition (Y0, X0); _settextcolor (Color); _outtext (Message); #endif } void ClearScreen (void) /**********************************************************************************************************************************/ /* Pre : None. */ /* Post : The screen has been cleared. */ /* Import: PrText. */ /**********************************************************************************************************************************/ { #ifdef _AMIGA_ RectFill (&Screen->RastPort, 0, 0, 640, 256); #else _clearscreen (_GCLEARSCREEN); #endif } #ifdef _AMIGA_ void CloseAllIntuition (void) /********************************************************************************************************************************/ /* Pre : None. */ /* Post : All windows and screens have been closed, all libraries have been released. */ /* Import: None. */ /********************************************************************************************************************************/ { if (Window) CloseWindow (Window); if (Screen) CloseScreen (Screen); if (IntuitionBase) CloseLibrary (IntuitionBase); if (GfxBase) CloseLibrary (GfxBase); } void SwapDbyte (dbyte *Number) /********************************************************************************************************************************/ /* Pre : 'Number' holds a pointer to the dbyte that should be swapped. */ /* Post : The number is converted from Little Endian to Big Endian (or vice versa). */ /* Import: None. */ /********************************************************************************************************************************/ { unsigned char *Cp; unsigned char Temp; Cp = (unsigned char *)Number; Temp = *Cp; *Cp = *(Cp + 1); *(Cp + 1) = Temp; } void SwapLong (unsigned long *Number) /********************************************************************************************************************************/ /* Pre : 'Number' holds a pointer to the long that should be swapped. */ /* Post : The number is converted from Little Endian to Big Endian (or vice versa). */ /* Import: None. */ /********************************************************************************************************************************/ { unsigned char *Cp; unsigned char Temp; Cp = (unsigned char *)Number; Temp = *Cp; /* Swap bytes 0 and 3 */ *Cp = *(Cp + 3); *(Cp + 3) = Temp; Temp = *(Cp + 1); /* Swap bytes 1 and 2 */ *(Cp + 1) = *(Cp + 2); *(Cp + 2) = Temp; } #endif void Bye (char *Message) /**********************************************************************************************************************************/ /* Pre : 'Message' holds the errormessage. */ /* Post : 'Message' has been printed, any open file has been closed and the program is aborted. */ /* Import: CloseAllIntuition. */ /**********************************************************************************************************************************/ { #ifdef _AMIGA_ CloseAllIntuition (); #else fcloseall (); flushall (); _setvideomode (_DEFAULTMODE); #endif fprintf (stderr, "%s\n", Message); exit (0); } #ifdef _AMIGA_ void SetPalette (void) /********************************************************************************************************************************/ /* Pre : None. */ /* Post : The 16-color palette has been loaded for the current screen. The colors should match the default VGA colors from the */ /* PC. */ /* Import: None. */ /********************************************************************************************************************************/ { SetRGB4 (&Screen->ViewPort, DBLACK , 0, 0, 0); /* Convert the palette to standard VGA (PC) */ SetRGB4 (&Screen->ViewPort, DBLUE , 0, 0, 8); SetRGB4 (&Screen->ViewPort, DGREEN , 0, 8, 0); SetRGB4 (&Screen->ViewPort, DCYAN , 0, 8, 8); SetRGB4 (&Screen->ViewPort, DRED , 8, 0, 0); SetRGB4 (&Screen->ViewPort, DMAGENTA, 8, 0, 8); SetRGB4 (&Screen->ViewPort, DYELLOW , 8, 8, 0); SetRGB4 (&Screen->ViewPort, DWHITE , 8, 8, 8); SetRGB4 (&Screen->ViewPort, LBLACK , 5, 5, 5); SetRGB4 (&Screen->ViewPort, LBLUE , 0, 0, 15); SetRGB4 (&Screen->ViewPort, LGREEN , 0, 15, 0); SetRGB4 (&Screen->ViewPort, LCYAN , 0, 15, 15); SetRGB4 (&Screen->ViewPort, LRED , 15, 0, 0); SetRGB4 (&Screen->ViewPort, LMAGENTA, 15, 0, 15); SetRGB4 (&Screen->ViewPort, LYELLOW , 15, 15, 0); SetRGB4 (&Screen->ViewPort, LWHITE , 15, 15, 15); } void OpenAllIntuition (void) /********************************************************************************************************************************/ /* Pre : None. */ /* Post : First the graphics and intuition libraries have been opened. After this a screen has been opened, in a resolution of */ /* 640x256x16, without titlebar. After this has a window been opened with the exact same size, which is layed over the */ /* screen. Finally, the palette has been converted to match the standard VGA colors of the PC. */ /* Import: Bye. */ /********************************************************************************************************************************/ { if (!(GfxBase = (struct GfxBase *)OpenLibrary ("graphics.library", 0L))) /* Open the libraries */ Bye ("ERROR - Graphics Library not found\n"); if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary ("intuition.library", 0L))) Bye ("ERROR - Intuition Library not found\n"); if (!(Screen = (struct Screen *)OpenScreen (&FirstScreen))) /* Open the screen */ Bye ("ERROR - Cannot open screen\n"); FirstWindow.Screen = Screen; /* Link the window to this screen */ if (!(Window = (struct Window *)OpenWindow (&FirstWindow))) /* Open the window */ Bye ("ERROR - Cannot open window\n"); SetPalette (); InLaceMode = FALSE; } #endif void ListSprites (void) /**********************************************************************************************************************************/ /* Pre : None. */ /* Post : The new sprites in this WAD file have been listed on a cleared screen. */ /* Import: ClearScreen, PrText. */ /**********************************************************************************************************************************/ { int register Cnt; int register Xco = 1; int register Yco = 3; boolean Type6Done = FALSE; boolean Type7Done = FALSE; boolean AdjustCo; ClearScreen (); PrText (1, -1, LBLUE, "NEW SPRITES IN THIS WAD FILE:"); for (Cnt = 0 ; Cnt < MAXSPRITES ; Cnt ++) if (Sprites[Cnt].FieldFilled) { AdjustCo = TRUE; switch (Sprites[Cnt].Type) { case 0 : PrText (Yco, Xco, DCYAN, "ENEMY "); PrText ( 0, 0, LCYAN, Sprites[Cnt].Description); break; case 1 : PrText (Yco, Xco, DCYAN, "CARD "); PrText ( 0, 0, LCYAN, Sprites[Cnt].Description); break; case 2 : PrText (Yco, Xco, DCYAN, "WEAPON "); PrText ( 0, 0, LCYAN, Sprites[Cnt].Description); break; case 3 : PrText (Yco, Xco, DCYAN, "AMMO "); PrText ( 0, 0, LCYAN, Sprites[Cnt].Description); break; case 4 : PrText (Yco, Xco, DCYAN, "BONUS "); PrText ( 0, 0, LCYAN, Sprites[Cnt].Description); break; case 5 : PrText (Yco, Xco, DCYAN, "DECOR "); PrText ( 0, 0, LCYAN, Sprites[Cnt].Description); break; case 6 : if (!Type6Done) { PrText (Yco, Xco, LCYAN, "Miscelanious weaponfire"); Type6Done = TRUE; } else AdjustCo = FALSE; break; case 7 : if (!Type7Done) { PrText (Yco, Xco, LCYAN, "Miscelanious decorations"); Type7Done = TRUE; } else AdjustCo = FALSE; break; default: PrText (Yco, Xco, LRED, "Unknown type %d for %s", Sprites[Cnt].Type, Sprites[Cnt].IdName); } if (AdjustCo) if (++ Yco > 26) { Yco = 3; Xco += 26; } } PrText (28, -1, DYELLOW, "Any key to return..."); } void ListMenus (void) /**********************************************************************************************************************************/ /* Pre : None. */ /* Post : The new menu items in this WAD file have been listed on a cleared screen. */ /* Import: ClearScreen, PrText. */ /**********************************************************************************************************************************/ { int register Cnt; int register Xco = 1; int register Yco = 3; ClearScreen (); PrText (1, -1, LBLUE, "NEW MENU ITEMS IN THIS WAD FILE:"); for (Cnt = 0 ; Cnt < MAXMENUS ; Cnt ++) if (Menus[Cnt].FieldFilled) { switch (Menus[Cnt].Type) { case 0 : PrText (Yco, Xco, DCYAN, "MAIN MENU "); PrText ( 0, 0, LCYAN, "\'%s\'", Menus[Cnt].Description); break; case 1 : PrText (Yco, Xco, DCYAN, "SUBMENU "); PrText ( 0, 0, LCYAN, "\'%s\'", Menus[Cnt].Description); break; case 2 : PrText (Yco, Xco, DCYAN, "PLAYING "); PrText ( 0, 0, LCYAN, "\'%s\'", Menus[Cnt].Description); break; case 3 : PrText (Yco, Xco, DCYAN, "MISC "); PrText ( 0, 0, LCYAN, Menus[Cnt].Description); } if (++ Yco > 26) { Yco = 3; Xco += 36; } } PrText (28, -1, DYELLOW, "Any key to return..."); } void ListMusic (void) /**********************************************************************************************************************************/ /* Pre : None. */ /* Post : The new music in this WAD file has been listed on a cleared screen. */ /* Import: ClearScreen, PrText. */ /**********************************************************************************************************************************/ { int register Cnt; int register Xco = 1; int register Yco = 3; ClearScreen (); PrText (1, -1, LBLUE, "NEW MUSIC IN THIS WAD FILE:"); for (Cnt = 0 ; Cnt < MAXMUSIC ; Cnt ++) if (Music[Cnt].FieldFilled) { PrText (Yco, Xco, LCYAN, Music[Cnt].Description); if (++ Yco > 26) { Yco = 3; Xco += 36; } } PrText (28, -1, DYELLOW, "Any key to return..."); } void ListSounds (void) /**********************************************************************************************************************************/ /* Pre : None. */ /* Post : The new sounds in this WAD file have been listed on a cleared screen. */ /* Import: ClearScreen, PrText. */ /**********************************************************************************************************************************/ { int register Cnt; int register Xco = 1; int register Yco = 4; ClearScreen (); PrText (1, -1, LBLUE, "NEW SOUNDS IN THIS WAD FILE:"); PrText (2, -1, LBLUE, "\'Spectre\' means \'Demon & Spectre\', \'spots\' means \'spots player\'"); for (Cnt = 0 ; Cnt < MAXSOUNDS ; Cnt += 2) if (Sounds[Cnt].FieldFilled || Sounds[Cnt + 1].FieldFilled) { PrText (Yco, Xco, DCYAN, "[%2d] ", (Cnt / 2) + 1); PrText ( 0, 0, LCYAN, Sounds[Cnt].Description); if (++ Yco > 26) { Yco = 4; Xco += 27; } } PrText (28, -1, DYELLOW, "Any key to return..."); } void ViewLevel (FILE *Fp, dbyte MemNum) /**********************************************************************************************************************************/ /* Pre : 'Fp' points to the open WAD file, 'MemNum' holds the ('Remember') level number to check. */ /* Post : The map of the pointed level has been drawn, using different colors for all types of the lines. The colors are: */ /* Secret door : DGREEN */ /* Regular door (press the door itself): LYELLOW */ /* Switch : LBLUE */ /* Level 'ender' : LMAGENTA */ /* Regular wall : DRED */ /* All others : LBLACK */ /* Import: ClearScreen, PrText, SwapDbyte, Bye. */ /**********************************************************************************************************************************/ { struct LineDef_s LineDef; struct Vertex_s *VertexInfo; dbyte register N; dbyte register Divider; dbyte register NumberOfVertexes; long register Entries; boolean More; unsigned char Color; short register OffsetX; short register OffsetY; #ifdef _AMIGA_ CloseWindow (Window); /* Close the 'normal' screen */ CloseScreen (Screen); if (!(Screen = (struct Screen *)OpenScreen (&SecondScreen))) /* Open the interlaced (double-height) screen */ Bye ("ERROR - Cannot open screen\n"); SecondWindow.Screen = Screen; if (!(Window = (struct Window *)OpenWindow (&SecondWindow))) Bye ("ERROR - Cannot open window\n"); SetPalette (); InLaceMode = TRUE; #else ClearScreen (); #endif NumberOfVertexes = Remember[MemNum].VertexLoc.Size / sizeof (struct Vertex_s); if ((VertexInfo = ((struct Vertex_s *)malloc ((size_t)(sizeof (struct Vertex_s) * NumberOfVertexes)))) == NULL) Bye ("ERROR - Could not allocate enough memory\n"); if (fseek (Fp, Remember[MemNum].VertexLoc.Start, SEEK_SET)) Bye ("ERROR - File location error\n"); if (fread (VertexInfo, 1, sizeof (struct Vertex_s), Fp) != sizeof (struct Vertex_s)) /* Read first vertex */ Bye ("ERROR - File read error\n"); #ifdef _AMIGA_ SwapDbyte (&VertexInfo->MapX); SwapDbyte (&VertexInfo->MapY); #endif Remember[MemNum].MinMapX = Remember[MemNum].MaxMapX = VertexInfo->MapX; Remember[MemNum].MinMapY = Remember[MemNum].MaxMapY = VertexInfo->MapY; N = 1; Entries = sizeof (struct Vertex_s); while (Entries < Remember[MemNum].VertexLoc.Size) /* Handle all entries */ { if (fread ((VertexInfo + N), 1, sizeof (struct Vertex_s), Fp) != sizeof (struct Vertex_s)) Bye ("ERROR - File read error\n"); #ifdef _AMIGA_ SwapDbyte (&(VertexInfo + N)->MapX); SwapDbyte (&(VertexInfo + N)->MapY); #endif if ((VertexInfo + N)->MapX < Remember[MemNum].MinMapX) Remember[MemNum].MinMapX = (VertexInfo + N)->MapX; if ((VertexInfo + N)->MapX > Remember[MemNum].MaxMapX) Remember[MemNum].MaxMapX = (VertexInfo + N)->MapX; if ((VertexInfo + N)->MapY < Remember[MemNum].MinMapY) Remember[MemNum].MinMapY = (VertexInfo + N)->MapY; if ((VertexInfo + N)->MapY > Remember[MemNum].MaxMapY) Remember[MemNum].MaxMapY = (VertexInfo + N)->MapY; Entries += sizeof (struct Vertex_s); N ++; } Remember[MemNum].MapSizeX = Remember[MemNum].MaxMapX - Remember[MemNum].MinMapX + 1; /* Include BOTH ends */ Remember[MemNum].MapSizeY = Remember[MemNum].MaxMapY - Remember[MemNum].MinMapY + 1; Divider = ceil((double)Remember[MemNum].MapSizeX / 640); if ((ceil ((double)Remember[MemNum].MapSizeY / 480)) > Divider) Divider = ceil ((double)Remember[MemNum].MapSizeY / 480); OffsetX = (640 - (Remember[MemNum].MapSizeX / Divider)) / 2; OffsetY = (480 - (Remember[MemNum].MapSizeY / Divider)) / 2; Entries = 0; if (fseek (Fp, Remember[MemNum].LineDefLoc.Start, SEEK_SET)) Bye ("ERROR - File location error\n"); while (Entries < Remember[MemNum].LineDefLoc.Size) /* Handle all entries */ { if (fread (&LineDef, 1, sizeof (struct LineDef_s), Fp) != sizeof (struct LineDef_s)) Bye ("ERROR - File read error\n"); #ifdef _AMIGA_ SwapDbyte (&LineDef.Start); SwapDbyte (&LineDef.End); SwapDbyte (&LineDef.Flags); SwapDbyte (&LineDef.Type); SwapDbyte (&LineDef.Tag); SwapDbyte (&LineDef.SideDef1); SwapDbyte (&LineDef.SideDef2); #endif if (LineDef.Flags & 0x0020) /* Secret */ Color = DGREEN; else if (LineDef.Flags & 0x0080) /* Not on map */ Color = LBLACK; else if (LineDef.Type) { More = TRUE; Color = LBLACK; for (N = 0 ; N < MAXLINEDRLF && More; N ++) if (LineDef.Type == LineDefDoorLift[N]) { More = FALSE; Color = LYELLOW; } if (More) for (N = 0 ; N < MAXLINESWITCH && More; N ++) if (LineDef.Type == LineDefSwitch[N]) { More = FALSE; Color = LBLUE; } if (More) for (N = 0 ; N < MAXLINEEND && More; N ++) if (LineDef.Type == LineDefEndLevel[N]) { More = FALSE; Color = LMAGENTA; } } else if ((LineDef.Flags & 0x0018) == 0x0018) /* Both upper and lower texture unpegged */ Color = DYELLOW; else if (LineDef.Flags & 0x005E) /* Blocks sound, unpegged and/or two-sided */ Color = LBLACK; else Color = DRED; #ifdef _AMIGA_ SetAPen (&Screen->RastPort, Color); Move (&Screen->RastPort, (short)(((VertexInfo + LineDef.Start)->MapX - Remember[MemNum].MinMapX) / Divider) + OffsetX, (short)(479 - ((VertexInfo + LineDef.Start)->MapY - Remember[MemNum].MinMapY) / Divider) - OffsetY); Draw (&Screen->RastPort, (short)(((VertexInfo + LineDef.End)->MapX - Remember[MemNum].MinMapX) / Divider) + OffsetX, (short)(479 - ((VertexInfo + LineDef.End)->MapY - Remember[MemNum].MinMapY) / Divider) - OffsetY); #else _setcolor (Color); _moveto ((short)(((VertexInfo + LineDef.Start)->MapX - Remember[MemNum].MinMapX) / Divider) + OffsetX, (short)(479 - ((VertexInfo + LineDef.Start)->MapY - Remember[MemNum].MinMapY) / Divider) - OffsetY); _lineto ((short)(((VertexInfo + LineDef.End)->MapX - Remember[MemNum].MinMapX) / Divider) + OffsetX, (short)(479 - ((VertexInfo + LineDef.End)->MapY - Remember[MemNum].MinMapY) / Divider) - OffsetY); #endif Entries += sizeof (struct LineDef_s); } free (VertexInfo); } void CheckLevel (FILE *Fp, dbyte MemNum) /**********************************************************************************************************************************/ /* Pre : 'Fp' points to the open WAD file, 'MemNum' holds the ('Remember') level number to check. */ /* Post : The following tests have been made: */ /* - All LINEDEFS have a length of > 0; */ /* - All LINEDEFS use existing SIDEDEF numbers; */ /* - All LINEDEFS use existing VERTEX numbers for Start and End values; */ /* - The BLOCKMAP start is <= lowest VERTEX number; */ /* - The number of blocks in the BLOCKMAP is enough to fit the map; */ /* - All blocks contents in the BLOCKMAP start with a 0x0000 and end with a 0xFFFF; */ /* - All used LINEDEFS in the BLOCKMAP exist; */ /* - All used LINEDEFS in a block of the BLOCKMAP are indeed in the block (starting, ending or crossing); */ /* - The length of the REJECT data is ((number_of_SECTORS ^ 2) / 8), rounded upwards. */ /* - All THINGS have valid coordinates; */ /* - All THINGS have valid angles of appearance; */ /* - All THINGS are of known type; */ /* Import: PrText, SwapDbyte, Bye. */ /**********************************************************************************************************************************/ { struct BlockMapHeader_s BlockMapHeader; struct LineDef_s LineDef; struct Vertex_s *VertexInfo; struct Check_s *LineInfo; dbyte *BlockInfo; dbyte register BlockOffset; dbyte register BlockNumber; dbyte register N; dbyte TestMapX; dbyte TestMapY; dbyte TestMapX2; dbyte TestMapY2; dbyte NumberOfLineDefs; dbyte NumberOfSideDefs; dbyte NumberOfVertexes; dbyte BlockMinX; dbyte BlockMinY; dbyte BlockMaxX; dbyte BlockMaxY; dbyte register CntX; dbyte register CntY; dbyte LineDefNumber; char NextLine; long Entries; size_t BlockMapInfoSize; boolean More; for (N = 3 ; N <= 30 ; N ++) PrText (N, 40, DBLACK, " "); NextLine = 3; NumberOfLineDefs = Remember[MemNum].LineDefLoc.Size / sizeof (struct LineDef_s); NumberOfSideDefs = Remember[MemNum].SideDefLoc.Size / sizeof (struct SideDef_s); NumberOfVertexes = Remember[MemNum].VertexLoc.Size / sizeof (struct Vertex_s); if ((LineInfo = ((struct Check_s *)malloc ((size_t)(sizeof (struct Check_s) * NumberOfLineDefs)))) == NULL) Bye ("ERROR - Could not allocate enough memory\n"); if ((VertexInfo = ((struct Vertex_s *)malloc ((size_t)(sizeof (struct Vertex_s) * NumberOfVertexes)))) == NULL) Bye ("ERROR - Could not allocate enough memory\n"); PrText (1, 68, DWHITE, "Loading..."); if (fseek (Fp, Remember[MemNum].VertexLoc.Start, SEEK_SET)) Bye ("ERROR - File location error\n"); if (fread (VertexInfo, 1, sizeof (struct Vertex_s), Fp) != sizeof (struct Vertex_s)) /* Read first vertex */ Bye ("ERROR - File read error\n"); #ifdef _AMIGA_ SwapDbyte (&VertexInfo->MapX); SwapDbyte (&VertexInfo->MapY); #endif Remember[MemNum].MinMapX = Remember[MemNum].MaxMapX = VertexInfo->MapX; Remember[MemNum].MinMapY = Remember[MemNum].MaxMapY = VertexInfo->MapY; N = 1; Entries = sizeof (struct Vertex_s); while (Entries < Remember[MemNum].VertexLoc.Size) /* Handle all entries */ { if (fread ((VertexInfo + N), 1, sizeof (struct Vertex_s), Fp) != sizeof (struct Vertex_s)) Bye ("ERROR - File read error\n"); #ifdef _AMIGA_ SwapDbyte (&(VertexInfo + N)->MapX); SwapDbyte (&(VertexInfo + N)->MapY); #endif if ((VertexInfo + N)->MapX < Remember[MemNum].MinMapX) Remember[MemNum].MinMapX = (VertexInfo + N)->MapX; if ((VertexInfo + N)->MapX > Remember[MemNum].MaxMapX) Remember[MemNum].MaxMapX = (VertexInfo + N)->MapX; if ((VertexInfo + N)->MapY < Remember[MemNum].MinMapY) Remember[MemNum].MinMapY = (VertexInfo + N)->MapY; if ((VertexInfo + N)->MapY > Remember[MemNum].MaxMapY) Remember[MemNum].MaxMapY = (VertexInfo + N)->MapY; Entries += sizeof (struct Vertex_s); N ++; } Remember[MemNum].MapSizeX = Remember[MemNum].MaxMapX - Remember[MemNum].MinMapX + 1; /* Include BOTH ends */ Remember[MemNum].MapSizeY = Remember[MemNum].MaxMapY - Remember[MemNum].MinMapY + 1; PrText (NextLine, 40, DMAGENTA, "LINEDEFS consistency check:"); if (fseek (Fp, Remember[MemNum].LineDefLoc.Start, SEEK_SET)) Bye ("ERROR - File location error\n"); Entries = 0; N = 0; More = TRUE; while (Entries < Remember[MemNum].LineDefLoc.Size) /* Handle all entries */ { if (fread (&LineDef, 1, sizeof (struct LineDef_s), Fp) != sizeof (struct LineDef_s)) Bye ("ERROR - File read error\n"); #ifdef _AMIGA_ SwapDbyte (&LineDef.Start); SwapDbyte (&LineDef.End); SwapDbyte (&LineDef.Flags); SwapDbyte (&LineDef.Type); SwapDbyte (&LineDef.Tag); SwapDbyte (&LineDef.SideDef1); SwapDbyte (&LineDef.SideDef2); #endif if (LineDef.Start == LineDef.End) /* A LineDef with zero length */ { PrText (NextLine + 1, 42, LRED, "LineDef %d has zero length", N); More = FALSE; } else if (LineDef.SideDef1 >= NumberOfSideDefs || (LineDef.SideDef2 != 0xFFFF && LineDef.SideDef2 >= NumberOfSideDefs)) { /* Non-existent SideDef ? */ PrText (NextLine + 1, 42, LRED, "LineDef %d has an unknown SideDef", N); More = FALSE; } if (LineDef.Start >= NumberOfVertexes || LineDef.End >= NumberOfVertexes) /* Non-existent Vertex ? */ { if (More) /* Already an error-message printed ? */ PrText (NextLine + 1, 42, LRED, "LineDef %d has an unknown Vertex", N); (LineInfo + N)->StartMapX = 0x8000; /* Ensure that the coordinates are off the map */ (LineInfo + N)->StartMapY = 0x8000; (LineInfo + N)->EndMapX = 0x8000; (LineInfo + N)->EndMapY = 0x8000; More = FALSE; } else { (LineInfo + N)->StartMapX = (VertexInfo + LineDef.Start)->MapX; (LineInfo + N)->StartMapY = (VertexInfo + LineDef.Start)->MapY; (LineInfo + N)->EndMapX = (VertexInfo + LineDef.End)->MapX; (LineInfo + N)->EndMapY = (VertexInfo + LineDef.End)->MapY; } N ++; Entries += sizeof (struct LineDef_s); } if (More) { PrText (NextLine, 73, LMAGENTA, "Passed"); NextLine += 2; } else { PrText (NextLine, 73, LRED, "FAILED"); NextLine += 3; } free (VertexInfo); if (fseek (Fp, Remember[MemNum].BlockMapLoc.Start, SEEK_SET)) Bye ("ERROR - File location error\n"); if (fread (&BlockMapHeader, 1, sizeof (struct BlockMapHeader_s), Fp) != sizeof (struct BlockMapHeader_s)) Bye ("ERROR - File read error\n"); #ifdef _AMIGA_ SwapDbyte (&BlockMapHeader.OriginX); SwapDbyte (&BlockMapHeader.OriginY); SwapDbyte (&BlockMapHeader.BlockCntX); SwapDbyte (&BlockMapHeader.BlockCntY); #endif BlockMapInfoSize = (size_t)(Remember[MemNum].BlockMapLoc.Size - sizeof (struct BlockMapHeader_s)); if ((BlockInfo = ((dbyte *)malloc (BlockMapInfoSize))) == NULL) Bye ("ERROR - Could not allocate enough memory\n"); if (fread (BlockInfo, 1, BlockMapInfoSize, Fp) != BlockMapInfoSize) Bye ("ERROR - File read error\n"); PrText (1, 68, DWHITE, " "); #ifdef _AMIGA_ for (N = 0 ; N < (BlockMapInfoSize / sizeof (dbyte)) ; N ++) SwapDbyte (BlockInfo + N); #endif PrText (NextLine, 40, DMAGENTA, "BLOCKMAP structure check:"); More = TRUE; PrText (NextLine + 2, 40, LGREEN, "Origin (bottom-left) : (%5d, %5d) ", BlockMapHeader.OriginX, BlockMapHeader.OriginY); if (((BlockMapHeader.OriginX <= Remember[MemNum].MinMapX) || (BlockMapHeader.OriginX >= (Remember[MemNum].MinMapX - 0x007F))) && ((BlockMapHeader.OriginY <= Remember[MemNum].MinMapY) || (BlockMapHeader.OriginY >= (Remember[MemNum].MinMapY - 0x007F)))) PrText (0, 0, LMAGENTA, "+"); else { PrText (0, 0, LRED, "X"); More = FALSE; } PrText (NextLine + 3, 40, LGREEN, "Number of blocks : %5d x%5d ", BlockMapHeader.BlockCntX, BlockMapHeader.BlockCntY); TestMapX = Remember[MemNum].MapSizeX / 0x0080 + ((Remember[MemNum].MapSizeX & 0x007F) ? 1 : 0); TestMapY = Remember[MemNum].MapSizeY / 0x0080 + ((Remember[MemNum].MapSizeY & 0x007F) ? 1 : 0); if ((BlockMapHeader.BlockCntX >= TestMapX) && (BlockMapHeader.BlockCntY >= TestMapY)) PrText (0, 0, LMAGENTA, "+"); else { PrText (0, 0, LRED, "X"); More = FALSE; } if (More) PrText (NextLine, 73, LMAGENTA, "Passed"); else PrText (NextLine, 73, LRED, "FAILED"); More = TRUE; NextLine += 5; PrText (NextLine, 40, DMAGENTA, "BLOCKMAP consistency check:"); BlockMinX = BlockMapHeader.OriginX; BlockMaxX = BlockMapHeader.OriginX + 0x007F; BlockMinY = BlockMapHeader.OriginY; BlockMaxY = BlockMapHeader.OriginY + 0x007F; for (CntY = 0 ; CntY < BlockMapHeader.BlockCntY && More ; CntY ++) { for (CntX = 0 ; CntX < BlockMapHeader.BlockCntX && More ; CntX ++) { BlockNumber = CntY * BlockMapHeader.BlockCntX + CntX; BlockOffset = (*(BlockInfo + BlockNumber) - (sizeof (struct BlockMapHeader_s) / sizeof (dbyte))); if (*(BlockInfo + BlockOffset) != 0x0000) { PrText (NextLine + 1, 42, LRED, "Invalid startmarker in block %d", BlockNumber + 1); More = FALSE; } while (*(BlockInfo + (++ BlockOffset)) != 0xFFFF && More) { LineDefNumber = *(BlockInfo + BlockOffset); if (BlockOffset > BlockMapInfoSize) { PrText (NextLine + 1, 42, LRED, "Missing endmarker in block %d", BlockNumber + 1); More = FALSE; } else if (LineDefNumber > NumberOfLineDefs) { PrText (NextLine + 1, 42, LRED, "Unknown LineDef %d in block %d", LineDefNumber, BlockNumber + 1); More = FALSE; } else { TestMapX = (LineInfo + LineDefNumber)->StartMapX; TestMapY = (LineInfo + LineDefNumber)->StartMapY; TestMapX2 = (LineInfo + LineDefNumber)->EndMapX; TestMapY2 = (LineInfo + LineDefNumber)->EndMapY; if (TestMapX < BlockMinX || TestMapX > BlockMaxX) /* Start X is not in this block ? */ { if (TestMapX2 < BlockMinX || TestMapX2 > BlockMaxX) /* End X also not in this block ? */ More = FALSE; /* Signal: LineDef crosses this block */ else if (TestMapY2 < BlockMinY || TestMapY2 > BlockMaxY) /* End Y not in the block ? */ More = FALSE; /* Signal: LineDef crosses this block */ } else if (TestMapY < BlockMinY || TestMapY > BlockMaxY) /* Start Y not in the block ? */ More = FALSE; /* Signal: LineDef crosses this block */ if (!More) /* Crossing LineDef ? */ { /* Test if that is possible */ More = TRUE; if (TestMapX > TestMapX2) /* Line goes from right to left ? */ { /* Then flip the line */ N = TestMapX; TestMapX = TestMapX2; TestMapX2 = N; N = TestMapY; TestMapY = TestMapY2; TestMapY2 = N; } if (TestMapX < BlockMinX) /* Start X lies left */ { if (TestMapX2 < BlockMinX) /* End X also left */ More = FALSE; /* Then the LineDef does NOT cross! */ } else if (TestMapX > BlockMinX) /* Start X lies right */ if (TestMapX > BlockMaxX) /* Even after the block */ More = FALSE; /* Then the LineDef does NOT cross! */ if (TestMapY > TestMapY2) /* Line goes from up to down ? */ { /* Then flip the line */ N = TestMapX; TestMapX = TestMapX2; TestMapX2 = N; N = TestMapY; TestMapY = TestMapY2; TestMapY2 = N; } if (TestMapY < BlockMinY) /* Start Y lies below */ { if (TestMapY2 < BlockMinY) /* End Y also below */ More = FALSE; /* Then the LineDef does NOT cross! */ } else if (TestMapY > BlockMinY) /* Start Y lies above */ if (TestMapY > BlockMaxY) /* Even after the block */ More = FALSE; /* Then the LineDef does NOT cross! */ if (!More) PrText (NextLine + 1, 42, LRED, "Invalid LineDef %d in block %d", LineDefNumber, BlockNumber + 1); } } } BlockMinX += 0x0080; BlockMaxX += 0x0080; } BlockMinY += 0x0080; BlockMaxY += 0x0080; BlockMinX = BlockMapHeader.OriginX; BlockMaxX = BlockMapHeader.OriginX + 0x007F; } if (More) { PrText (NextLine, 73, LMAGENTA, "Passed"); NextLine += 2; } else { PrText (NextLine, 73, LRED, "FAILED"); NextLine += 3; } free (BlockInfo); free (LineInfo); PrText (NextLine, 40, DMAGENTA, "REJECT consistency check:"); if ((long)ceil (pow ((double)(Remember[MemNum].SectorLoc.Size / sizeof (struct Sector_s)), 2) / 8) == Remember[MemNum].RejectDataLoc.Size) PrText (NextLine, 73, LMAGENTA, "Passed"); else PrText (NextLine, 73, LRED, "FAILED"); NextLine += 2; PrText (NextLine, 40, DMAGENTA, "THINGS consistency check:"); PrText (1, 68, DWHITE, "Loading..."); if (fseek (Fp, Remember[MemNum].ThingsLoc.Start, SEEK_SET)) Bye ("ERROR - File location error\n"); More = TRUE; Entries = 0; while (Entries < Remember[MemNum].ThingsLoc.Size && More) /* Handle all entries */ { if (fread (&Thing, 1, sizeof (struct Thing_s), Fp) != sizeof (struct Thing_s)) Bye ("ERROR - File read error\n"); #ifdef _AMIGA_ SwapDbyte (&Thing.Xpos); SwapDbyte (&Thing.Ypos); SwapDbyte (&Thing.Angle); SwapDbyte (&Thing.Type); SwapDbyte (&Thing.When); #endif if (Thing.Xpos < BlockMapHeader.OriginX || Thing.Xpos > (BlockMapHeader.OriginX + 0x0080 * BlockMapHeader.BlockCntX - 1) || Thing.Ypos < BlockMapHeader.OriginY || Thing.Ypos > (BlockMapHeader.OriginY + 0x0080 * BlockMapHeader.BlockCntY - 1)) { PrText (NextLine + 1, 40, LRED, "Thing located outside the map"); More = FALSE; } else if (Thing.Angle >= 360) { PrText (NextLine + 1, 40, LRED, "Unknown angle %d encountered", Thing.Angle); More = FALSE; } else if ((Thing.Type > 0x003F && Thing.Type < 0x07D1) || Thing.Type == 0x07D9 || (Thing.Type > 0x07DF && Thing.Type < 0x07E2) || (Thing.Type > 0x07E3 && Thing.Type < 0x07E6) || Thing.Type == 0x07EB || (Thing.Type > 0x07EC && Thing.Type < 0x07F3) || (Thing.Type > 0x07F3 && Thing.Type < 0x07FD) || (Thing.Type > 0x0801 && Thing.Type < 0x0BB9) || Thing.Type > 0x0BBE) { PrText (NextLine + 1, 40, LRED, "Unknown thing %d encountered", Thing.Type); More = FALSE; } Entries += sizeof (struct Thing_s); } PrText (1, 68, DWHITE, " "); if (More) { PrText (NextLine, 73, LMAGENTA, "Passed"); NextLine += 2; } else { PrText (NextLine, 73, LRED, "FAILED"); NextLine += 3; } } dbyte main (int argc, char *argv[]) /**********************************************************************************************************************************/ /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> MAIN ROUTINE <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ /* Import: Bye, SwapDbyte, SwapLong, OpenAllIntuition, ClearScreen, ListSprites, ListSounds,CheckLevel, ViewLevel, PrText. */ /**********************************************************************************************************************************/ { FILE *Fp; char S[80]; char T[80]; char Last[5]; char ThingMem = -1; char register M; char register N; char register O; char register MemNum; char register Memory; long register Entries; boolean First; boolean New; boolean More; boolean KeyOk; boolean KeySprites = FALSE; boolean KeySounds = FALSE; boolean KeyMenus = FALSE; boolean KeyMusic = FALSE; boolean KeyNext = FALSE; boolean KeyPrevious = FALSE; boolean KeyInfo = FALSE; boolean KeyCheckLevel = FALSE; boolean KeyViewLevel = FALSE; boolean Listing = FALSE; boolean Checked = FALSE; boolean LevelInfoType = TRUE; boolean ReprintAll = TRUE; boolean ReprintLevels = TRUE; boolean ReprintAny = TRUE; #ifdef _AMIGA_ OpenAllIntuition (); #else _setvideomode (_VRES16COLOR); /* Choose video mode 640x480x16 */ #endif if (argc != 2) Bye ("Usage: WADINFO WADfile\n"); if (!(Fp = fopen (argv[1], "rb"))) /* Open the WAD file */ Bye ("ERROR - File does not exist\n"); PrText (1, 1, LWHITE, "Analyzing the WAD file..."); PrText (1, 68, DWHITE, "Loading..."); if (fread (&WadHeader, 1, sizeof (struct WadHeader_s), Fp) != sizeof (struct WadHeader_s)) /* Go to the WAD 'directory' */ Bye ("ERROR - File read error\n"); if (strncmp (WadHeader.Type, "PWAD", 4) && strncmp (WadHeader.Type, "IWAD", 4)) Bye ("ERROR - Not a WAD file\n"); #ifdef _AMIGA_ SwapLong (&WadHeader.DirStart); SwapLong (&WadHeader.DirSize); #endif if (fseek (Fp, WadHeader.DirStart, SEEK_SET)) Bye ("ERROR - File location error\n"); for (M = 0 ; M < 27 ; M ++) { Remember[M].ThingsFilled = FALSE; Remember[M].StatsFilled = FALSE; } WadInfo.NewStuff = 0x00; WadInfo.NewLevels = 0x00000000; WadInfo.NewDemos = 0x0000; Entries = -1; while (++ Entries < WadHeader.DirSize) /* Handle all entries in the 'directory' */ { if (fread (&Directory, 1, sizeof (struct Directory_s), Fp) != sizeof (struct Directory_s)) /* Read an entry */ Bye ("ERROR - File read error\n"); #ifdef _AMIGA_ SwapLong (&Directory.Start); SwapLong (&Directory.Size); #endif for (M = 0 ; M < 8 ; M ++) S[M] = toupper (Directory.Name[M]); S[8] = '\0'; More = TRUE; for (M = 0 ; M < MAXCOLORS && More ; M ++) if (!strncmp (S, Colors[M], strlen (Colors[M]))) { More = FALSE; WadInfo.NewStuff |= NEWCOLORS; } if (More) if (!strncmp (S, "DEMO", 4)) { More = FALSE; WadInfo.NewDemos |= ((dbyte)1 << (S[4]-'1')); } if (More) for (M = 0 ; M < MAXLEVELS && More ; M ++) if (!strncmp (S, Levels[M], strlen (Levels[M]))) { More = FALSE; WadInfo.NewLevels |= ((long)1 << M); strncpy (Last, S, 4); ThingMem ++; Last[4] = '\0'; } if (More) for (M = 0 ; M < MAXSPRITES && More ; M ++) if (!strncmp (S, Sprites[M].IdName, strlen (Sprites[M].IdName))) { More = FALSE; WadInfo.NewStuff |= NEWSPRITES; Sprites[M].FieldFilled = TRUE; } if (More) for (M = 0 ; M < MAXMUSIC && More ; M ++) if (!strncmp (S, Music[M].IdName, strlen (Music[M].IdName))) { More = FALSE; WadInfo.NewStuff |= NEWMUSIC; Music[M].FieldFilled = TRUE; } if (More) for (M = 0 ; M < MAXINSTRUMENTS && More ; M ++) if (!strncmp (S, Instruments[M], strlen (Instruments[M]))) { More = FALSE; WadInfo.NewStuff |= NEWINSTRUMENTS; } if (More) for (M = 0 ; M < MAXSTATUSBAR && More ; M ++) if (!strncmp (S, StatusBar[M], strlen (StatusBar[M]))) { More = FALSE; WadInfo.NewStuff |= NEWSTATUSBAR; } if (More) for (M = 0 ; M < MAXMENUS && More ; M ++) if (!strncmp (S, Menus[M].IdName, strlen (Menus[M].IdName))) { More = FALSE; WadInfo.NewStuff |= NEWMENUS; Menus[M].FieldFilled = TRUE; } if (More) for (M = 0 ; M < MAXSOUNDS && More ; M ++) if (!strncmp (S, Sounds[M].IdName, strlen (Sounds[M].IdName))) { More = FALSE; WadInfo.NewStuff |= NEWSOUNDS; Sounds[M].FieldFilled = TRUE; } if (More && !strncmp (S, "THINGS", 6)) { Remember[ThingMem].ThingsLoc.Start = Directory.Start; /* The "THINGS" part of a level is dealt with later */ Remember[ThingMem].ThingsLoc.Size = Directory.Size; strcpy (Remember[ThingMem].ThingsLoc.Name, Last); More = FALSE; } if (More && !strncmp (S, "VERTEXES", 8)) { Remember[ThingMem].VertexLoc.Start = Directory.Start; Remember[ThingMem].VertexLoc.Size = Directory.Size; strcpy (Remember[ThingMem].VertexLoc.Name, Last); More = FALSE; } if (More && !strncmp (S, "LINEDEFS", 8)) { Remember[ThingMem].LineDefLoc.Start = Directory.Start; Remember[ThingMem].LineDefLoc.Size = Directory.Size; strcpy (Remember[ThingMem].LineDefLoc.Name, Last); More = FALSE; } if (More && !strncmp (S, "SIDEDEFS", 8)) { Remember[ThingMem].SideDefLoc.Start = Directory.Start; Remember[ThingMem].SideDefLoc.Size = Directory.Size; strcpy (Remember[ThingMem].SideDefLoc.Name, Last); More = FALSE; } if (More && !strncmp (S, "SEGS", 4)) { Remember[ThingMem].SegLoc.Start = Directory.Start; Remember[ThingMem].SegLoc.Size = Directory.Size; strcpy (Remember[ThingMem].SegLoc.Name, Last); More = FALSE; } if (More && !strncmp (S, "SECTORS", 7)) { Remember[ThingMem].SectorLoc.Start = Directory.Start; Remember[ThingMem].SectorLoc.Size = Directory.Size; strcpy (Remember[ThingMem].SectorLoc.Name, Last); More = FALSE; } if (More && !strncmp (S, "SSECTORS", 8)) { Remember[ThingMem].SubSectorLoc.Start = Directory.Start; Remember[ThingMem].SubSectorLoc.Size = Directory.Size; strcpy (Remember[ThingMem].SubSectorLoc.Name, Last); More = FALSE; } if (More && !strncmp (S, "NODES", 5)) { Remember[ThingMem].NodeLoc.Start = Directory.Start; Remember[ThingMem].NodeLoc.Size = Directory.Size; strcpy (Remember[ThingMem].NodeLoc.Name, Last); More = FALSE; } if (More && !strncmp (S, "REJECT", 6)) { Remember[ThingMem].RejectDataLoc.Start = Directory.Start; Remember[ThingMem].RejectDataLoc.Size = Directory.Size; strcpy (Remember[ThingMem].RejectDataLoc.Name, Last); More = FALSE; } if (More && !strncmp (S, "BLOCKMAP", 8)) { Remember[ThingMem].BlockMapLoc.Start = Directory.Start; Remember[ThingMem].BlockMapLoc.Size = Directory.Size; strcpy (Remember[ThingMem].BlockMapLoc.Name, Last); More = FALSE; } if (More && Directory.Start != 0 /* If not a field seperator identifier */ && S[0] != '\0' /* And the identifier is not empty */ && strcmp (S, "INFOPACK") /* (These were found in a lot of WAD files but NOT from Id Software!) */ && strcmp (S, "PLATFORM")) WadInfo.NewStuff |= NEWGRAPHS; } PrText (1, 1, LWHITE, " "); PrText (1, 68, DWHITE, " "); ThingMem ++; MemNum = 0; More = TRUE; while (More) { if (ReprintAny) { if (ReprintAll) { #ifdef _AMIGA_ N = strlen (argv[1]); while (-- N >= 0 && argv[1][N] != '/' && argv[1][N] != ':') ; if (N == 0) PrText ( 1, 1, LWHITE, "Filename : %s", argv[1]); else PrText ( 1, 1, LWHITE, "Filename : %s", argv[1] + N + 1); #else N = strlen (argv[1]); while (-- N >= 0 && argv[1][N] != '\\' && argv[1][N] != ':') ; if (N == 0) PrText ( 1, 1, LWHITE, "Filename : %s", strupr (argv[1])); else PrText ( 1, 1, LWHITE, "Filename : %s", strupr (argv[1] + N + 1)); #endif for (N = 0 ; N < 4 ; N ++) /* Convert the type to a string */ S[N] = WadHeader.Type[N]; S[N] = '\0'; PrText ( 2, 1, LWHITE, "Wadfile type : %s", S); /* Print the WAD 'directory' information */ PrText ( 3, 1, LWHITE, "Directory start: %08lX", WadHeader.DirStart); PrText ( 4, 1, LWHITE, "Directory size : %08lX", WadHeader.DirSize); PrText ( 7, 1, LBLUE, "New Colors : %s", WadInfo.NewStuff & NEWCOLORS ? "Yes" : "-"); PrText ( 8, 1, LBLUE, "New Demos :"); if (WadInfo.NewDemos == 0x0000) PrText (0, 0, LBLUE, " -"); for (N = 0 ; N < 10 ; N ++) if (WadInfo.NewDemos & ((dbyte)1 << N)) PrText (0, 0, LBLUE, " %d", N + 1); PrText ( 9, 1, LBLUE, "New Sounds : %s", WadInfo.NewStuff & NEWSOUNDS ? "Yes" : "-"); PrText (10, 1, LBLUE, "New Instruments: %s", WadInfo.NewStuff & NEWINSTRUMENTS ? "Yes" : "-"); PrText (11, 1, LBLUE, "New Music : %s", WadInfo.NewStuff & NEWMUSIC ? "Yes" : "-"); PrText (12, 1, LBLUE, "New Sprites : %s", WadInfo.NewStuff & NEWSPRITES ? "Yes" : "-"); PrText (13, 1, LBLUE, "New Status bar : %s", WadInfo.NewStuff & NEWSTATUSBAR ? "Yes" : "-"); PrText (14, 1, LBLUE, "New Menu items : %s", WadInfo.NewStuff & NEWMENUS ? "Yes" : "-"); PrText (15, 1, LBLUE, "New Graphics : %s", WadInfo.NewStuff & NEWGRAPHS ? "Yes" : "-"); PrText (16, 1, LBLUE, "New Levels :"); if (WadInfo.NewLevels != 0x00000000) /* Are their any patch levels in this file ? */ { S[0] = '\0'; for (N = 0 ; N < NUMEPISODE ; N ++) { Memory = -1; First = TRUE; if ((WadInfo.NewLevels & ((long)0x1ff << (N * NUMLEVEL))) == ((long)0x1ff << (N * NUMLEVEL))) { /* All 9 level-bits of an episode set */ sprintf (T, " E%d-", N + 1); strcat (S, T); } else /* Possibly a partial episode */ for (O = 0 ; O < NUMLEVEL ; O ++) /* Handle all level-bits in this episode */ if (WadInfo.NewLevels & ((long)1 << (N * NUMLEVEL + O))) { if (Memory == -1) if (First) { sprintf (T, " E%dM%d", N + 1, O + 1); strcat (S, T); First = FALSE; Memory = 1; New = FALSE; } else { sprintf (T, ",%d", O + 1); strcat (S, T); Memory = O + 1; New = FALSE; } else { Memory ++; New = TRUE; } } else { if (Memory > 0 && New) { sprintf (T, "-%d", Memory); strcat (S, T); } Memory = -1; } if (Memory > 0 && New) { sprintf (T, "-%d", Memory); strcat (S, T); } } PrText (0, 0, LBLUE, S); } /* No new levels in this WAD file */ else PrText (0, 0, LBLUE, " -"); ReprintLevels = TRUE; } if (ReprintLevels && ThingMem > 0) /* New levels ? */ { PrText (1, 40, LYELLOW, "INFORMATION ON LEVEL %s:", Remember[MemNum].ThingsLoc.Name); if (LevelInfoType) { if (!Remember[MemNum].ThingsFilled) { PrText (1, 68, DWHITE, "Loading..."); for (N = 0 ; N < 4 ; N ++) { Remember[MemNum].PlayerStarts[N] = 0; for (O = 0 ; O < 16 ; O ++) Remember[MemNum].ThingType[O][N] = 0; } Remember[MemNum].PlayerStarts[4] = 0; if (fseek (Fp, Remember[MemNum].ThingsLoc.Start, SEEK_SET)) /* Go to the start of the data */ Bye ("ERROR - File location error\n"); Entries = 0; while (Entries < Remember[MemNum].ThingsLoc.Size) /* Handle all entries */ { if (fread (&Thing, 1, sizeof (struct Thing_s), Fp) != sizeof (struct Thing_s)) /* Read an entry */ Bye ("ERROR - File read error\n"); #ifdef _AMIGA_ SwapDbyte (&Thing.Xpos); SwapDbyte (&Thing.Ypos); SwapDbyte (&Thing.Angle); SwapDbyte (&Thing.Type); SwapDbyte (&Thing.When); #endif switch (Thing.Type) /* Find out if the type is interesting */ { case THING_PLAYER1 : Thing.Type = 0xFFFF; (Remember[MemNum].PlayerStarts[0]) ++; break; /* Handle playerstarts */ case THING_PLAYER2 : Thing.Type = 0xFFFF; (Remember[MemNum].PlayerStarts[1]) ++; break; case THING_PLAYER3 : Thing.Type = 0xFFFF; (Remember[MemNum].PlayerStarts[2]) ++; break; case THING_PLAYER4 : Thing.Type = 0xFFFF; (Remember[MemNum].PlayerStarts[3]) ++; break; case THING_DEATHMATCH : Thing.Type = 0xFFFF; (Remember[MemNum].PlayerStarts[4]) ++; break; case THING_CHAINSAW : Thing.Type = TYPE_CHAINSAW; break; /* Convert type to array index */ case THING_SHOTGUN : Thing.Type = TYPE_SHOTGUN; break; case THING_CHAINGUN : Thing.Type = TYPE_CHAINGUN; break; case THING_LAUNCHER : Thing.Type = TYPE_LAUNCHER; break; case THING_PLASMAGUN : Thing.Type = TYPE_PLASMAGUN; break; case THING_BFG9000 : Thing.Type = TYPE_BFG9000; break; case THING_TROOPER : Thing.Type = TYPE_TROOPER; break; case THING_SARGEANT : Thing.Type = TYPE_SARGEANT; break; case THING_IMP : Thing.Type = TYPE_IMP; break; case THING_DEMON : Thing.Type = TYPE_DEMON; break; case THING_SPECTRE : Thing.Type = TYPE_SPECTRE; break; case THING_CACODEMON : Thing.Type = TYPE_CACODEMON; break; case THING_LOSTSOUL : Thing.Type = TYPE_LOSTSOUL; break; case THING_BARON : Thing.Type = TYPE_BARON; break; case THING_CYBERDEMON : Thing.Type = TYPE_CYBERDEMON; break; case THING_SPIDERBOSS : Thing.Type = TYPE_SPIDERBOSS; break; default : Thing.Type = 0xFFFF; } if (Thing.Type != 0xFFFF) /* Unhandled type ? */ { /* Update array entry, depending on the appearance (difficulty) */ (Remember[MemNum].ThingType[Thing.Type][3]) ++; if ((Thing.When & WHEN_MULTI) != WHEN_MULTI) /* If it appears in multi, then the other bits are undefined */ { if ((Thing.When & WHEN_D12) == WHEN_D12) (Remember[MemNum].ThingType[Thing.Type][0]) ++; if ((Thing.When & WHEN_D3) == WHEN_D3) (Remember[MemNum].ThingType[Thing.Type][1]) ++; if ((Thing.When & WHEN_D45) == WHEN_D45) (Remember[MemNum].ThingType[Thing.Type][2]) ++; } } Entries += sizeof (struct Thing_s); } Remember[MemNum].ThingsFilled = TRUE; PrText (1, 68, DWHITE, " "); } if (Remember[MemNum].PlayerStarts[0]) /* Print number of found starting pads */ if (Remember[MemNum].PlayerStarts[1]) if (Remember[MemNum].PlayerStarts[2]) if (Remember[MemNum].PlayerStarts[3]) PrText (3, 40, LGREEN, "Number of player starts : 4 "); else PrText (3, 40, LGREEN, "Number of player starts : 3 "); else PrText (3, 40, LGREEN, "Number of player starts : 2 "); else PrText (3, 40, LGREEN, "Number of player starts : 1 "); else PrText (3, 40, LGREEN, "Number of player starts : none "); if (Remember[MemNum].PlayerStarts[4] == 0) PrText (4, 40, LGREEN, "Number of deathmatch starts: none "); else if (Remember[MemNum].PlayerStarts[4] == 1) PrText (4, 40, LGREEN, "Number of deathmatch starts: 1 "); else PrText (4, 40, LGREEN, "Number of deathmatch starts: %d ", Remember[MemNum].PlayerStarts[4]); PrText ( 5, 40, DBLACK, " "); PrText ( 6, 40, DBLACK, " "); PrText ( 7, 40, DMAGENTA, "Weapons in this level: D12 D3 D45 MUL "); /* Print the other recorded information */ PrText ( 8, 40, DBLACK, " "); PrText ( 9, 40, LMAGENTA, "(1) Chainsaw %3d %3d %3d %3d ", Remember[MemNum].ThingType[0][0], Remember[MemNum].ThingType[0][1], Remember[MemNum].ThingType[0][2], Remember[MemNum].ThingType[0][3]); PrText (10, 40, LMAGENTA, "(3) Shotgun %3d %3d %3d %3d ", Remember[MemNum].ThingType[1][0], Remember[MemNum].ThingType[1][1], Remember[MemNum].ThingType[1][2], Remember[MemNum].ThingType[1][3]); PrText (11, 40, LMAGENTA, "(4) Chaingun %3d %3d %3d %3d ", Remember[MemNum].ThingType[2][0], Remember[MemNum].ThingType[2][1], Remember[MemNum].ThingType[2][2], Remember[MemNum].ThingType[2][3]); PrText (12, 40, LMAGENTA, "(5) Rocket launcher %3d %3d %3d %3d ", Remember[MemNum].ThingType[3][0], Remember[MemNum].ThingType[3][1], Remember[MemNum].ThingType[3][2], Remember[MemNum].ThingType[3][3]); PrText (13, 40, LMAGENTA, "(6) Plasmagun %3d %3d %3d %3d ", Remember[MemNum].ThingType[4][0], Remember[MemNum].ThingType[4][1], Remember[MemNum].ThingType[4][2], Remember[MemNum].ThingType[4][3]); PrText (14, 40, LMAGENTA, "(7) BFG9000 %3d %3d %3d %3d ", Remember[MemNum].ThingType[5][0], Remember[MemNum].ThingType[5][1], Remember[MemNum].ThingType[5][2], Remember[MemNum].ThingType[5][3]); PrText (15, 40, DBLACK, " "); PrText (16, 40, DMAGENTA, "Enemies in this level: D12 D3 D45 MUL "); PrText (17, 40, DBLACK, " "); PrText (18, 40, LMAGENTA, "Trooper %3d %3d %3d %3d ", Remember[MemNum].ThingType[6][0], Remember[MemNum].ThingType[6][1], Remember[MemNum].ThingType[6][2], Remember[MemNum].ThingType[6][3]); PrText (19, 40, LMAGENTA, "Sargeant %3d %3d %3d %3d ", Remember[MemNum].ThingType[7][0], Remember[MemNum].ThingType[7][1], Remember[MemNum].ThingType[7][2], Remember[MemNum].ThingType[7][3]); PrText (20, 40, LMAGENTA, "Imp %3d %3d %3d %3d ", Remember[MemNum].ThingType[8][0], Remember[MemNum].ThingType[8][1], Remember[MemNum].ThingType[8][2], Remember[MemNum].ThingType[8][3]); PrText (21, 40, LMAGENTA, "Demon %3d %3d %3d %3d ", Remember[MemNum].ThingType[9][0], Remember[MemNum].ThingType[9][1], Remember[MemNum].ThingType[9][2], Remember[MemNum].ThingType[9][3]); PrText (22, 40, LMAGENTA, "Spectre %3d %3d %3d %3d ", Remember[MemNum].ThingType[10][0], Remember[MemNum].ThingType[10][1], Remember[MemNum].ThingType[10][2], Remember[MemNum].ThingType[10][3]); PrText (23, 40, LMAGENTA, "Caco Demon %3d %3d %3d %3d ", Remember[MemNum].ThingType[11][0], Remember[MemNum].ThingType[11][1], Remember[MemNum].ThingType[11][2], Remember[MemNum].ThingType[11][3]); PrText (24, 40, LMAGENTA, "Lost soul %3d %3d %3d %3d ", Remember[MemNum].ThingType[12][0], Remember[MemNum].ThingType[12][1], Remember[MemNum].ThingType[12][2], Remember[MemNum].ThingType[12][3]); PrText (25, 40, LMAGENTA, "Baron of Hell %3d %3d %3d %3d ", Remember[MemNum].ThingType[13][0], Remember[MemNum].ThingType[13][1], Remember[MemNum].ThingType[13][2], Remember[MemNum].ThingType[13][3]); PrText (26, 40, LMAGENTA, "Cyber Demon %3d %3d %3d %3d ", Remember[MemNum].ThingType[14][0], Remember[MemNum].ThingType[14][1], Remember[MemNum].ThingType[14][2], Remember[MemNum].ThingType[14][3]); PrText (27, 40, LMAGENTA, "Spider Demon %3d %3d %3d %3d ", Remember[MemNum].ThingType[15][0], Remember[MemNum].ThingType[15][1], Remember[MemNum].ThingType[15][2], Remember[MemNum].ThingType[15][3]); PrText (28, 40, DBLACK, " "); } else { if (!Remember[MemNum].StatsFilled) { PrText (1, 68, DWHITE, "Loading..."); if (fseek (Fp, Remember[MemNum].VertexLoc.Start, SEEK_SET)) Bye ("ERROR - File location error\n"); if (fread (&Vertex, 1, sizeof (struct Vertex_s), Fp) != sizeof (struct Vertex_s)) /* Read an entry */ Bye ("ERROR - File read error\n"); #ifdef _AMIGA_ SwapDbyte (&Vertex.MapX); SwapDbyte (&Vertex.MapY); #endif Remember[MemNum].MinMapX = Remember[MemNum].MaxMapX = Vertex.MapX; Remember[MemNum].MinMapY = Remember[MemNum].MaxMapY = Vertex.MapY; Entries = sizeof (struct Vertex_s); while (Entries < Remember[MemNum].VertexLoc.Size) /* Handle all entries */ { if (fread (&Vertex, 1, sizeof (struct Vertex_s), Fp) != sizeof (struct Vertex_s)) /* Read an entry */ Bye ("ERROR - File read error\n"); #ifdef _AMIGA_ SwapDbyte (&Vertex.MapX); SwapDbyte (&Vertex.MapY); #endif if (Vertex.MapX < Remember[MemNum].MinMapX) Remember[MemNum].MinMapX = Vertex.MapX; if (Vertex.MapX > Remember[MemNum].MaxMapX) Remember[MemNum].MaxMapX = Vertex.MapX; if (Vertex.MapY < Remember[MemNum].MinMapY) Remember[MemNum].MinMapY = Vertex.MapY; if (Vertex.MapY > Remember[MemNum].MaxMapY) Remember[MemNum].MaxMapY = Vertex.MapY; Entries += sizeof (struct Vertex_s); } Remember[MemNum].MapSizeX = Remember[MemNum].MaxMapX - Remember[MemNum].MinMapX + 1; /* Include BOTH ends */ Remember[MemNum].MapSizeY = Remember[MemNum].MaxMapY - Remember[MemNum].MinMapY + 1; Remember[MemNum].StatsFilled = TRUE; PrText (1, 68, DWHITE, " "); } PrText ( 3, 40, DGREEN, "THINGS start : %08lX ", Remember[MemNum].ThingsLoc.Start); PrText ( 4, 40, DGREEN, " size : %08lX (%4lu) ", Remember[MemNum].ThingsLoc.Size, Remember[MemNum].ThingsLoc.Size / sizeof (struct Thing_s)); PrText ( 5, 40, DGREEN, "VERTEXES start : %08lX ", Remember[MemNum].VertexLoc.Start); PrText ( 6, 40, DGREEN, " size : %08lX (%4lu) ", Remember[MemNum].VertexLoc.Size, Remember[MemNum].VertexLoc.Size / sizeof (struct Vertex_s)); PrText ( 7, 40, DGREEN, "LINEDEFS start : %08lX ", Remember[MemNum].LineDefLoc.Start); PrText ( 8, 40, DGREEN, " size : %08lX (%4lu) ", Remember[MemNum].LineDefLoc.Size, Remember[MemNum].LineDefLoc.Size / sizeof (struct LineDef_s)); PrText ( 9, 40, DGREEN, "SIDEDEFS start : %08lX ", Remember[MemNum].SideDefLoc.Start); PrText (10, 40, DGREEN, " size : %08lX (%4lu) ", Remember[MemNum].SideDefLoc.Size, Remember[MemNum].SideDefLoc.Size / sizeof (struct SideDef_s)); PrText (11, 40, DGREEN, "SEGS start : %08lX ", Remember[MemNum].SegLoc.Start); PrText (12, 40, DGREEN, " size : %08lX (%4lu) ", Remember[MemNum].SegLoc.Size, Remember[MemNum].SegLoc.Size / sizeof (struct Seg_s)); PrText (13, 40, DGREEN, "SECTORS start : %08lX ", Remember[MemNum].SectorLoc.Start); PrText (14, 40, DGREEN, " size : %08lX (%4lu) ", Remember[MemNum].SectorLoc.Size, Remember[MemNum].SectorLoc.Size / sizeof (struct Sector_s)); PrText (15, 40, DGREEN, "SSECTORS start : %08lX ", Remember[MemNum].SubSectorLoc.Start); PrText (16, 40, DGREEN, " size : %08lX (%4lu) ", Remember[MemNum].SubSectorLoc.Size, Remember[MemNum].SubSectorLoc.Size / sizeof (struct SubSector_s)); PrText (17, 40, DGREEN, "NODES start : %08lX ", Remember[MemNum].NodeLoc.Start); PrText (18, 40, DGREEN, " size : %08lX (%4lu) ", Remember[MemNum].NodeLoc.Size, Remember[MemNum].NodeLoc.Size / sizeof (struct Node_s)); PrText (19, 40, DGREEN, "REJECT start : %08lX ", Remember[MemNum].RejectDataLoc.Start); PrText (20, 40, DGREEN, " size : %08lX ", Remember[MemNum].RejectDataLoc.Size); PrText (21, 40, DGREEN, "BLOCKMAP start : %08lX ", Remember[MemNum].BlockMapLoc.Start); PrText (22, 40, DGREEN, " size : %08lX ", Remember[MemNum].BlockMapLoc.Size); PrText (23, 40, DBLACK, " "); PrText (24, 40, LMAGENTA, "Top-left map : (%5d, %5d) ", Remember[MemNum].MinMapX, Remember[MemNum].MinMapY); PrText (25, 40, LMAGENTA, "Bottom-right map : (%5d, %5d) ", Remember[MemNum].MaxMapX, Remember[MemNum].MaxMapY); PrText (26, 40, LMAGENTA, "Center of map : (%5d, %5d) ", Remember[MemNum].MaxMapX - (Remember[MemNum].MapSizeX / 2), Remember[MemNum].MaxMapY - (Remember[MemNum].MapSizeY / 2)); PrText (27, 40, DBLACK, " "); PrText (28, 40, LMAGENTA, "Size of map : %5d x %5d ", Remember[MemNum].MapSizeX, Remember[MemNum].MapSizeY); } } PrText (20, 1, DYELLOW, "Press :"); PrText (21, 1, DYELLOW, " [Q] to quit "); if (ThingMem > 0) { PrText (22, 1, DYELLOW, " [V] to view this level's map "); KeyViewLevel = TRUE; } else { PrText (22, 1, DYELLOW, " "); KeyViewLevel = FALSE; } if (ThingMem > 0) { PrText (23, 1, DYELLOW, " [I] to toggle level info type "); KeyInfo = TRUE; } else { PrText (23, 1, DYELLOW, " "); KeyInfo = FALSE; } if (ThingMem > 0) { PrText (24, 1, DYELLOW, " [C] to check this level "); KeyCheckLevel = TRUE; } else { PrText (24, 1, DYELLOW, " "); KeyCheckLevel = FALSE; } if ((ThingMem > 0) && (MemNum < ThingMem - 1)) { PrText (25, 1, DYELLOW, " [N] for next level "); KeyNext = TRUE; } else { PrText (25, 1, DYELLOW, " "); KeyNext = FALSE; } if ((ThingMem > 0) && (MemNum > 0)) { PrText (26, 1, DYELLOW, " [P] for previous level "); KeyPrevious = TRUE; } else { PrText (26, 1, DYELLOW, " "); KeyPrevious = FALSE; } if ((WadInfo.NewStuff & NEWSPRITES) == NEWSPRITES) { PrText (27, 1, DYELLOW, " [R] to list the sprites "); KeySprites = TRUE; } else KeySprites = FALSE; if ((WadInfo.NewStuff & NEWSOUNDS) == NEWSOUNDS) { PrText (28, 1, DYELLOW, " [S] to list the sounds "); KeySounds = TRUE; } else KeySounds = FALSE; if ((WadInfo.NewStuff & NEWMUSIC) == NEWMUSIC) { PrText (29, 1, DYELLOW, " [M] to list the music "); KeyMusic = TRUE; } else KeyMusic = FALSE; if ((WadInfo.NewStuff & NEWMENUS) == NEWMENUS) { PrText (30, 1, DYELLOW, " [U] to list the menu items "); KeyMenus = TRUE; } else KeyMenus = FALSE; KeyOk = FALSE; ReprintAll = FALSE; ReprintLevels = FALSE; ReprintAny = FALSE; } while (!KeyOk) { KeyOk = TRUE; #ifdef _AMIGA_ while (KeyOk) { if (!(IntuiMessage = (struct IntuiMessage *)GetMsg (Window->UserPort))) /* Wait for a message from intuition */ { Wait (1L << Window->UserPort->mp_SigBit); continue; } MessageClass = IntuiMessage->Class; /* Determine the source of the message */ Code = IntuiMessage->Code; /* Read the data of the message */ ReplyMsg (IntuiMessage); /* Confirm receipt to the operating system */ if (MessageClass == VANILLAKEY) KeyOK = FALSE; } KeyOk = TRUE; if (Checked) { Checked = FALSE; ReprintLevels = TRUE; } else if (Listing) { Listing = FALSE; if (InLaceMode) { CloseWindow (Window); CloseScreen (Screen); if (!(Screen = (struct Screen *)OpenScreen (&FirstScreen))) Bye ("ERROR - Cannot open screen\n"); FirstWindow.Screen = Screen; if (!(Window = (struct Window *)OpenWindow (&FirstWindow))) Bye ("ERROR - Cannot open window\n"); SetPalette () InLaceMode = FALSE; } else ClearScreen (); ReprintAll = TRUE; } else switch (Code) #else Key = getch (); /* Wait for a key */ if (Key == 0x0000 || Key == 0x00E0) /* Non-ASCII keys (cursor, funtion, etc) give 'extended' first */ Key = getch (); if (Checked) { Checked = FALSE; ReprintLevels = TRUE; } else if (Listing) { Listing = FALSE; ClearScreen (); ReprintAll = TRUE; } else switch (tolower ((char)(Key & 0x00FF))) /* Keep only the ASCII part */ #endif { case 'q' : More = FALSE; break; case 'c' : if (KeyCheckLevel) { CheckLevel (Fp, MemNum); KeyOk = FALSE; Checked = TRUE; } else KeyOk = FALSE; break; case 'i' : if (KeyInfo) { LevelInfoType = !LevelInfoType; ReprintLevels = TRUE; } else KeyOk = FALSE; break; case 'n' : if (KeyNext) { MemNum ++; ReprintLevels = TRUE; } else KeyOk = FALSE; break; case 'p' : if (KeyPrevious) { MemNum --; ReprintLevels = TRUE; } else KeyOk = FALSE; break; case 'r' : if (KeySprites) { ListSprites (); Listing = TRUE; KeyOk = FALSE; } else KeyOk = FALSE; break; case 's' : if (KeySounds) { ListSounds (); Listing = TRUE; KeyOk = FALSE; } else KeyOk = FALSE; break; case 'm' : if (KeyMusic) { ListMusic (); Listing = TRUE; KeyOk = FALSE; } else KeyOk = FALSE; break; case 'u' : if (KeyMenus) { ListMenus (); Listing = TRUE; KeyOk = FALSE; } else KeyOk = FALSE; break; case 'v' : if (KeyViewLevel) { ViewLevel (Fp, MemNum); Listing = TRUE; KeyOk = FALSE; } else KeyOk = FALSE; break; default : KeyOk = FALSE; } } ReprintAny = (ReprintAll || ReprintLevels); } fclose (Fp); Bye (""); /* Shutdown */ }