/****************************************************************************/ /* */ /* Layer Editor for Greed I */ /* */ /* Copyright(C) 1995 by Robert Morgan of Channel 7 */ /* */ /****************************************************************************/ #include #include #include #include #include #include /**** CONSTANTS ****/ #define VERSION "1.017" #define NUMLAYERS 18 #define XMAX 64 #define YMAX 64 #define TEXTMODE 0x03 #define VGAMODE 0x13 #define PEL_WRITE_ADR 0x3c8 #define PEL_READ_ADR 0x3c7 #define PEL_DATA 0x3c9 #define SCREEN 0xA000 #define SCREENWIDTH 320 #define SCREENHEIGHT 200 #define OUTBYTE(x,y) (outp((unsigned)(x),(unsigned)(y))) #define OUTWORD(x,y) (outpw((unsigned)(x),(unsigned)(y))) #define INBYTE(x) (inp((unsigned)(x))) #define INWORD(x) (inpw((unsigned)(x))) #define CLI _disable() #define STI _enable() #define MAXFONTCHARS 94 #define FONTWIDTH 5 #define TEXTCOLOR 5 #define BUFX 190 #define BUFY 190 /* text modes */ #define TEXT_NORMAL 0 #define TEXT_NOOVERWRITE 1 #define TEXT_CENTER 2 /* flags */ #define F_RIGHT (1<<0) #define F_LEFT (1<<1) #define F_UP (1<<2) #define F_DOWN (1<<3) #define F_TRANSPARENT (1<<4) #define F_NOCLIP (1<<5) #define F_NOBULLETCLIP (1<<6) #define F_DAMAGE (1<<7) /* layer names */ #define NORTHWALL 0 #define NORTHFLAGS 1 #define WESTWALL 2 #define WESTFLAGS 3 #define FLOOR 4 #define FLOORFLAGS 5 #define CEILING 6 #define CEILINGFLAGS 7 #define FLOORHEIGHT 8 #define CEILINGHEIGHT 9 #define FLOORDEF 10 #define FLOORDEFFLAGS 11 #define CEILINGDEF 12 #define CEILINGDEFFLAGS 13 #define LIGHTS 14 #define EFFECTS 15 #define SPRITES 16 #define SLOPES 17 char *layernames[NUMLAYERS]= { "NORTHWALL ", "", "WESTWALL ", "", "FLOOR ", "", "CEILING ", "", "FLOORHEIGHT ", "CEILINGHEIGHT", "FLOORDEF ", "", "CEILINGDEF ", "", "LIGHTS ", "EFFECTS ", "SPRITES ", "SLOPES " }; /**** TYPES ****/ typedef unsigned char byte; typedef byte layerdata_t; typedef layerdata_t layer_t[YMAX][XMAX]; typedef enum {false,true} boolean; typedef short word; typedef unsigned long longint; /* CPR file format header */ typedef struct { int signature; byte version; int width, height; byte flags, headersize; byte indicator; int orgx, orgy; } CPR_HEADER; /* FON character */ typedef struct { byte width; word lines[16]; } fontchartype; /* FON file format header */ typedef struct { char signature[4]; int height; int asciistart; int nchars; fontchartype fontchar[MAXFONTCHARS]; } fonttype; /**** VARIABLES ****/ layer_t far *layers[NUMLAYERS]; // map layers char filename[13], printstr[128]; boolean quit, messageready; byte colors[768]; byte far *screen, *ylookup[SCREENHEIGHT], buffer[BUFY][BUFX], *bufylookup[BUFY]; fonttype font; int tcolor, bkcolor, fontmode, fontavgwidth, currentvalue[NUMLAYERS], currentx, currenty, currentlayer; /**** FUNCTIONS ****/ /* protos */ void Error(char *error,...); void ReadFile(char *filename,word length,void *buffer); /* GRAPHICS *****************************************************************/ void SetPalette(byte *palette) { int i; while (inp(0x3da) & 0x08) ; while (!(inp(0x3da) & 0x08)) ; while (!(inp(0x3da) & 0x01)) ; OUTBYTE(PEL_WRITE_ADR,0); for (i=0;i<768;i++) OUTBYTE(PEL_DATA,*palette++); } void FillPalette(int red, int green, int blue) { int i; while (inp(0x3da) & 0x08) ; while (!(inp(0x3da) & 0x08)) ; while (!(inp(0x3da) & 0x01)) ; OUTBYTE(PEL_WRITE_ADR,0); for (i=0;i<256;i++) { OUTBYTE(PEL_DATA,red); OUTBYTE(PEL_DATA,green); OUTBYTE(PEL_DATA,blue); } } void LoadCPR(char *s) { int x, y, i, data, count, orgx, orgy, indicator; char str1[14]; FILE *f; CPR_HEADER h; byte far *t; FillPalette(0,0,0); f=fopen(s,"rb"); if (f==NULL) Error("%s not found"); if (!fread(&h,sizeof(CPR_HEADER),1,f) || h.signature!=19794 || fseek(f,h.headersize,0) || ((h.flags & 1) && !fread(colors,768,1,f))) Error("Error reading %s"); if (h.version==4) { indicator=255; orgx=0; orgy=0; } else if (h.version==5) { indicator=h.indicator; orgx=h.orgx; orgy=h.orgy; memset(screen,0,SCREENHEIGHT*SCREENWIDTH); } else Error("Invalid %s CPR file version",s); y=orgy; x=orgx; t=ylookup[y]+x; while (y=0) { *t++=data; ++x; if (x==h.width) { x=orgx; ++y; t=ylookup[y]+x; } } else Error("%s corrupted",s); } fclose(f); SetPalette(colors); } void LoadFON(char *s,int setwidth) { ReadFile(s,sizeof(fonttype),&font); fontavgwidth=setwidth; } int FontStrLen(char *s) { int i, j, result; i=0; result=0; j=font.asciistart; while (s[i]) { result+=font.fontchar[s[i]-j].width; ++i; } return result; } void PrintXY(int x1,int y1,char *s) { int i, h, j, k, width, lines; int x, y, l, letter; fontchartype *f; byte *dest; if (fontmode & TEXT_CENTER) { i=FontStrLen(s)>>1; x1-=i; } l=strlen(s); x=x1; h=font.height; for (k=0; kwidth; for (i=0;ilines[i]; dest=ylookup[y]+x; for (j=0;jcindex && str[cursor]==' ') --cursor; ++cursor; while (1) { DeleteMessage(); str[cursor]='_'; Message(str); ans=ReadKey(); c=ans & 255; switch (c) { case 0x00: case 0xE0: c=(word)ans>>8; switch (c) { case 75: case 83: if (cursor>cindex) { str[cursor]=' '; --cursor; str[cursor]='_'; } break; default: break; } break; case 8: if (cursor>cindex) { str[cursor]=' '; --cursor; str[cursor]='_'; } break; case 13: str[cursor]=' '; strcpy(name,&str[strlen(s)]); DeleteMessage(); return true; case 27: DeleteMessage(); return false; default: str[cursor]=c; if (cursor-cindex<12) cursor++; str[cursor]='_'; break; } } } /* CONVERSION ***************************************************************/ void Convert1(char *s) { FILE *f; int result, dest, source, i, j; layer_t *l[4]; if (stricmp(s,"IGNORE")==0) return; for (i=0;i<4;i++) { l[i]=(layer_t*)malloc(sizeof(layer_t)); if (l[i]==NULL) Error("Out of memory in Convert"); memset(l[i],0,sizeof(layer_t)); } f=fopen(s,"rt"); if (f==NULL) Error("Error loading %s",s); do { result=fscanf(f,"%i %i\n",&dest,&source); for (i=0;i>=8; flags=0; if (l & 0x1) flags|=F_TRANSPARENT; if (l & 0x2) flags|=F_NOCLIP; if (l & 0x4) flags|=F_LEFT; if (l & 0x8) flags|=F_RIGHT; if (l & 0x10) flags|=F_NOBULLETCLIP; (*layers[WESTFLAGS])[i][j]=flags; } for (i=0;i>=8; flags=0; if (l & 0x1) flags|=F_TRANSPARENT; if (l & 0x2) flags|=F_NOCLIP; if (l & 0x4) flags|=F_LEFT; if (l & 0x8) flags|=F_RIGHT; if (l & 0x10) flags|=F_NOBULLETCLIP; (*layers[NORTHFLAGS])[i][j]=flags; } for (i=0;i>=8; flags=0; (*layers[FLOORFLAGS])[i][j]=flags; } for (i=0;i>=8; flags=0; if (l & 0x1) flags|=F_TRANSPARENT; (*layers[CEILINGFLAGS])[i][j]=flags; } for (i=0;i='a' && fname[i]<='z') fname[i]+='A'-'a'; i++; } /* find filename extention */ i=0; while (fname[i]!=0 && fname[i]!='.') i++; if (fname[i]==0) strcat(fname,".LAY"); // assume new file format else if (strcmp(&fname[i],".LVL")==0) // old file format { CreateNewLAY(); ConvertLVL(fname); strcpy(&fname[i],".LAY"); sprintf(filename,"%-13s",fname); PrintfXY(233,10,filename); return; } sprintf(filename,"%-13s",fname); PrintfXY(233,10,filename); /* open and read */ f=fopen(fname,"rb+"); if (f==NULL) { CreateNewLAY(); return; } for (i=0;i='a' && filename[i]<='z') filename[i]+='A'-'a'; i++; } PrintfXY(233,10,filename); f=fopen(filename,"wb"); if (f==NULL) Error("Error saving %s",filename); for (i=0;i='a' && filename[i]<='z') filename[i]+='A'-'a'; i++; } PrintfXY(233,10,filename); f=fopen(filename,"rb"); if (f==NULL) Message("%s not found",filename); for (i=0;i=0 && tiley=0 && tilex0;j--) *(bufylookup[y+i]+x+j)=color; } color=(*layers[NORTHWALL])[tiley][tilex]; if (color) { if (lower!=FLOOR) color=5; else color=(color%240) + 16; memset(bufylookup[y]+x,color,10); memset(bufylookup[y+1]+x,color,10); } color=(*layers[WESTWALL])[tiley][tilex]; if (color) { if (lower!=FLOOR) color=5; else color=(color%240) + 16; for (i=0;i<10;i++) *(bufylookup[y+i]+x)=color; for (i=0;i<10;i++) *(bufylookup[y+i]+x+1)=color; } color=(*layers[SPRITES])[tiley][tilex]; if (color) { color=(color%240) + 16; *(bufylookup[y+4]+x+4)=color; *(bufylookup[y+5]+x+4)=color; *(bufylookup[y+6]+x+4)=color; *(bufylookup[y+4]+x+5)=color; *(bufylookup[y+5]+x+5)=color; *(bufylookup[y+6]+x+5)=color; *(bufylookup[y+4]+x+6)=color; *(bufylookup[y+5]+x+6)=color; *(bufylookup[y+6]+x+6)=color; } if ((*layers[SLOPES])[tiley][tilex]) *(bufylookup[y+5]+x+5)=3; } else for (i=0;i<10;i++) memset(bufylookup[y+i]+x,0,10); } else for (i=0;i<10;i++) memset(bufylookup[y+i],0,BUFX); if (currentlayer==WESTWALL) { cw=4; ch=12; } else if (currentlayer==NORTHWALL) { cw=12; ch=4; } else { cw=13; ch=13; } memset(bufylookup[89]+89,6,cw); memset(bufylookup[88+ch]+89,6,cw); for (i=90;i<89+ch;i++) { *(bufylookup[i]+89)=6; *(bufylookup[i]+88+cw)=6; } } /* Edit Functions ***********************************************************/ void FloodFill(void) { byte *x, *y, *processed; int index, total, curx, cury; index=0; total=1; x=(byte *)malloc(YMAX*XMAX); if (x==NULL) Error("Out of memory for flood fill (1)"); y=(byte *)malloc(YMAX*XMAX); if (y==NULL) Error("Out of memory for flood fill (2)"); processed=(byte *)malloc(YMAX*XMAX); if (processed==NULL) Error("Out of memory for flood fill (3)"); memset(x,0,XMAX*YMAX); memset(y,0,XMAX*YMAX); memset(processed,0,XMAX*YMAX); x[0]=currentx; y[0]=currenty; processed[currenty*XMAX+currentx]=1; while (index=0) { if (!processed[(cury-1)*XMAX+curx]) { x[total]=curx; y[total]=cury-1; total++; processed[(cury-1)*XMAX+curx]=1; } } if (!(*layers[WESTWALL])[cury][curx] && curx-1>=0) { if (!processed[(cury)*XMAX+curx-1]) { x[total]=curx-1; y[total]=cury; total++; processed[(cury)*XMAX+curx-1]=1; } } if (cury=XMAX*YMAX) Error("Flood fill overflow"); (*layers[currentlayer])[cury][curx]=currentvalue[currentlayer]; } free(x); free(y); free(processed); } void UpdateLocalInfo(void) { char *s; byte flags; PrintXY(233,20,layernames[currentlayer]); PrintfXY(233,30,"%3i",currentvalue[currentlayer]); PrintfXY(263,30,"%2i",currentx); PrintfXY(288,30,"%2i",currenty); PrintfXY(236,52,"%3i",(*layers[NORTHWALL])[currenty][currentx]); PrintfXY(255,52,"%3i",(*layers[WESTWALL])[currenty][currentx]); PrintfXY(236,63,"%3i",(*layers[FLOOR])[currenty][currentx]); PrintfXY(255,63,"%3i",(*layers[CEILING])[currenty][currentx]); PrintfXY(236,74,"%3i",(*layers[FLOORHEIGHT])[currenty][currentx]); PrintfXY(255,74,"%3i",(*layers[CEILINGHEIGHT])[currenty][currentx]); PrintfXY(236,85,"%3i",(*layers[FLOORDEF])[currenty][currentx]); PrintfXY(255,85,"%3i",(*layers[CEILINGDEF])[currenty][currentx]); PrintfXY(236,96,"%3i",(*layers[LIGHTS])[currenty][currentx]); PrintfXY(255,96,"%3i",(*layers[EFFECTS])[currenty][currentx]); PrintfXY(236,107,"%3i",(*layers[SPRITES])[currenty][currentx]); PrintfXY(255,107,"%3i",(*layers[SLOPES])[currenty][currentx]); switch (currentlayer) { case NORTHWALL: case WESTWALL: case FLOORDEF: case CEILINGDEF: case FLOOR: case CEILING: flags=(*layers[currentlayer+1])[currenty][currentx]; if (flags & F_RIGHT) s="Yes"; else s="No "; PrintXY(236,130,s); if (flags & F_LEFT) s="Yes"; else s="No "; PrintXY(255,130,s); if (flags & F_UP) s="Yes"; else s="No "; PrintXY(236,141,s); if (flags & F_DOWN) s="Yes"; else s="No "; PrintXY(255,141,s); if (flags & F_TRANSPARENT) s="Yes"; else s="No "; PrintXY(236,152,s); if (flags & F_NOCLIP) s="Yes"; else s="No "; PrintXY(255,152,s); if (flags & F_NOBULLETCLIP) s="Yes"; else s="No "; PrintXY(236,163,s); if (flags & F_DAMAGE) s="Yes"; else s="No "; PrintXY(255,163,s); break; default: PrintXY(236,130,"No "); PrintXY(255,130,"No "); PrintXY(236,141,"No "); PrintXY(255,141,"No "); PrintXY(236,152,"No "); PrintXY(255,152,"No "); PrintXY(236,163,"No "); PrintXY(255,163,"No "); break; } } /* MAIN *********************************************************************/ void MainLoop(void) { int c, ans, i; UpdateLocalInfo(); DrawBuffer(); BlitBuffer(); while (!quit) { ans=ReadKey(); if (messageready) DeleteMessage(); c=ans & 255; switch (c) { case 0x00: case 0xE0: c=(word)ans>>8; switch (c) { /* keypad controls */ case 75: if (currentx>0) { --currentx; if (*(byte*)MK_FP(0x0040,0x0017)&64) (*layers[currentlayer])[currenty][currentx]=currentvalue[currentlayer]; UpdateLocalInfo(); DrawBuffer(); BlitBuffer(); } break; case 77: if (currentx0) { --currenty; if (*(byte*)MK_FP(0x0040,0x0017)&64) (*layers[currentlayer])[currenty][currentx]=currentvalue[currentlayer]; UpdateLocalInfo(); DrawBuffer(); BlitBuffer(); } break; case 80: if (currenty=YMAX) currenty=YMAX; if (*(byte*)MK_FP(0x0040,0x0017)&64) (*layers[currentlayer])[currenty][currentx]=currentvalue[currentlayer]; UpdateLocalInfo(); DrawBuffer(); BlitBuffer(); break; case 71: currentx-=10; if (currentx<0) currentx=0; if (*(byte*)MK_FP(0x0040,0x0017)&64) (*layers[currentlayer])[currenty][currentx]=currentvalue[currentlayer]; UpdateLocalInfo(); DrawBuffer(); BlitBuffer(); break; case 79: currentx+=10; if (currentx>=YMAX) currentx=YMAX; if (*(byte*)MK_FP(0x0040,0x0017)&64) (*layers[currentlayer])[currenty][currentx]=currentvalue[currentlayer]; UpdateLocalInfo(); DrawBuffer(); BlitBuffer(); break; /* flood/fill commands */ case 33: // alt-f if (AskQuestion("Fill? (y/n)")) { memset(layers[currentlayer],currentvalue[currentlayer],sizeof(layer_t)); UpdateLocalInfo(); Drawbuffer(); BlitBuffer(); } break; case 36: // alt-j if (AskQuestion("Flood? (y/n)")) { FloodFill(); UpdateLocalInfo(); Drawbuffer(); BlitBuffer(); } break; /* flag setting commands */ case 59: switch (currentlayer) { case NORTHWALL: case WESTWALL: case FLOORDEF: case CEILINGDEF: case FLOOR: case CEILING: (*layers[currentlayer+1])[currenty][currentx]^=F_RIGHT; UpdateLocalInfo(); break; } break; case 60: switch (currentlayer) { case NORTHWALL: case WESTWALL: case FLOORDEF: case CEILINGDEF: case FLOOR: case CEILING: (*layers[currentlayer+1])[currenty][currentx]^=F_LEFT; UpdateLocalInfo(); break; } break; case 61: switch (currentlayer) { case NORTHWALL: case WESTWALL: case FLOORDEF: case CEILINGDEF: case FLOOR: case CEILING: (*layers[currentlayer+1])[currenty][currentx]^=F_UP; UpdateLocalInfo(); break; } break; case 62: switch (currentlayer) { case NORTHWALL: case WESTWALL: case FLOORDEF: case CEILINGDEF: case FLOOR: case CEILING: (*layers[currentlayer+1])[currenty][currentx]^=F_DOWN; UpdateLocalInfo(); break; } break; case 64: switch (currentlayer) { case NORTHWALL: case WESTWALL: (*layers[currentlayer+1])[currenty][currentx]^=F_NOCLIP; UpdateLocalInfo(); break; } break; case 63: switch (currentlayer) { case NORTHWALL: case WESTWALL: case FLOORDEF: case CEILINGDEF: case CEILING: (*layers[currentlayer+1])[currenty][currentx]^=F_TRANSPARENT; UpdateLocalInfo(); break; } break; case 65: switch (currentlayer) { case NORTHWALL: case WESTWALL: (*layers[currentlayer+1])[currenty][currentx]^=F_NOBULLETCLIP; UpdateLocalInfo(); break; } break; case 66: switch (currentlayer) { case NORTHWALL: case WESTWALL: case FLOOR: case CEILING: (*layers[currentlayer+1])[currenty][currentx]^=F_DAMAGE; UpdateLocalInfo(); break; } break; /* file commands */ case 31: // alt-s SaveLAYFile(); break; case 38: // alt-l LoadLayFile(); UpdateLocalInfo(); Drawbuffer(); BlitBuffer(); break; /* quit command */ case 45: // alt-x case 16: // alt-q if (AskQuestion("Quit? (y/n)")) quit=true; break; } break; /* value commands */ case ' ': (*layers[currentlayer])[currenty][currentx]=currentvalue[currentlayer]; UpdateLocalInfo(); Drawbuffer(); BlitBuffer(); break; case '.': case '+': currentvalue[currentlayer]++; currentvalue[currentlayer]&=255; UpdateLocalInfo(); break; case ',': case '-': currentvalue[currentlayer]--; currentvalue[currentlayer]&=255; UpdateLocalInfo(); break; case 'z': case 'Z': currentvalue[currentlayer]=(*layers[currentlayer])[currenty][currentx]; UpdateLocalInfo(); break; case 'x': case 'X': (*layers[currentlayer])[currenty][currentx]=0; UpdateLocalInfo(); DrawBuffer(); BlitBuffer(); break; case 'c': case 'C': for (i=0;i4) Error("Too many parameters"); else { ReadLevel(argv[1]); if (argc>=3) Convert1(argv[2]); if (argc>=4) Convert2(argv[3]); MainLoop(); } /* end message */ SetVidMode(TEXTMODE); printf("MEDIT (v%s)\n" "LAY/LVL File Editor\n" "Copyright (C) 1995 by Robert Morgan of Channel 7\n" "All rights reserved.\n\n",VERSION); }