2 Copyright (C) 1998 BJ Eirich (aka vecna)
\r
3 This program is free software; you can redistribute it and/or
\r
4 modify it under the terms of the GNU General Public License
\r
5 as published by the Free Software Foundation; either version 2
\r
6 of the License, or (at your option) any later version.
\r
7 This program is distributed in the hope that it will be useful,
\r
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
\r
10 See the GNU General Public Lic
\r
11 See the GNU General Public License for more details.
\r
12 You should have received a copy of the GNU General Public License
\r
13 along with this program; if not, write to the Free Software
\r
14 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
\r
17 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
\r
20 // + added ScreenShot() on F11
\r
21 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
\r
27 // ================================= Data ====================================
\r
31 word start; // strand start
\r
32 word finish; // strand end
\r
33 word delay; // tile-switch delay
\r
34 word mode; // tile-animation mode
\r
39 char pmultx,pdivx; // parallax multiplier/divisor for X
\r
40 char pmulty,pdivy; // parallax multiplier/divisor for Y
\r
41 unsigned short sizex, sizey; // layer dimensions.
\r
42 unsigned char trans, hline; // transparency flag | hline (raster fx)
\r
47 char name[40]; // zone name/desc
\r
48 unsigned short script; // script to call thingy
\r
49 unsigned short percent; // chance of executing
\r
50 unsigned short delay; // step-delay
\r
51 unsigned short aaa; // Accept Adjacent Activation
\r
52 unsigned short entityscript; // script to call for entities
\r
55 zoneinfo zones[256]; // zone data records
\r
56 layer_r layer[6]; // Array of layer data
\r
57 vspanim_r vspanim[100]; // tile animation data
\r
58 unsigned short vadelay[100]; // Tile animation delay ctr
\r
60 char mapname[60]; // MAP filename
\r
61 char vspname[60]; // VSP filemap
\r
62 char musname[60]; // MAP bkgrd music default filename
\r
63 char rstring[20]; // render-order string
\r
64 char numlayers; // number of layers in map
\r
65 byte *obstruct, *zone; // obstruction and zone buffers
\r
66 char layertoggle[8]; // layer visible toggles
\r
67 word xstart, ystart; // MAP start x/y location
\r
68 int bufsize; // how many bytes need to be written
\r
69 int numzones; // number of active zones
\r
71 word *layers[6]; // Raw layer data
\r
72 int xwin=0, ywin=0; // camera offset
\r
76 byte *vsp=0,*vspmask; // VSP data buffer.
\r
77 unsigned short numtiles; // number of tiles in VSP.
\r
78 unsigned short *tileidx; // tile index thingamajig
\r
79 char *flipped; // bi-direction looping flag
\r
83 char *msbuf[100]; // ptr-table to script offset
\r
84 char *ms; // script text buffer
\r
85 byte nms; // number of movescripts
\r
87 char numfollowers=0; // number of party followers
\r
88 byte follower[10]; // maximum of 10 followers.
\r
89 char laststeps[10]={ 0 }; // record of last movements
\r
94 byte movegranularity; // means nothing now, please remove
\r
97 byte phantom=0; // walk-through-walls
\r
98 byte speeddemon=0; // doublespeed cheat
\r
99 int bindarray[128]; // bind script offset
\r
101 // ================================= Code ====================================
\r
103 void ReadCompressedLayer1(byte *dest, int len, char *buf)
\r
116 for (j=0; j<run; j++)
\r
128 void ReadCompressedLayer2(word *dest, int len, word *buf)
\r
138 if ((w & 0xFF00)==0xFF00)
\r
142 for(j=0; j<run; j++)
\r
154 void LoadVSP(char *fname)
\r
161 // Mwahaha! The Indefatigable Grue has snuck into the V2 source code! It is forever corrupted by his evil touch! Cower in fear, oh yes, FEAR! MwahahaHA..ha...hem...
\r
163 if (!(f=vopen(fname))) err("*error* Could not open VSP file %s.",fname);
\r
165 vread(&pal, 768, f);
\r
166 vread(&numtiles, 2, f);
\r
168 vsp=(byte *) valloc(numtiles*256, "vsp", OID_IMAGE);
\r
171 vread(vsp, (256*numtiles), f);
\r
176 cb=(char *) valloc(i, "LoadVSP:cb", OID_TEMP);
\r
178 ReadCompressedLayer1(vsp, 256*numtiles, cb);
\r
181 vread(&vspanim, sizeof vspanim, f);
\r
184 // Now calculate VSP transparency mask.
\r
186 vspmask=(byte *) valloc(numtiles*256, "vspmask", OID_MISC);
\r
187 for (i=0; i<(numtiles*256); i++)
\r
189 if (vsp[i]) vspmask[i]=0;
\r
190 else vspmask[i]=255;
\r
193 // Allocate and build tileidx.
\r
195 tileidx=(unsigned short *) valloc(numtiles*2, "tileidx", OID_MISC);
\r
196 for (i=0; i<numtiles; i++)
\r
199 flipped=(char *) valloc(numtiles, "flipped", OID_MISC);
\r
213 void LoadMAP(char *fname)
\r
219 // No matter where you go, you're there.
\r
221 Logp("Loading MAP %s.",fname);
\r
222 memcpy(mapname, fname, strlen(fname)+1);
\r
223 memcpy(strbuf, "MAPù5", 6);
\r
224 if (!(f=vopen(fname))) err("Could not find %s.",fname);
\r
225 vread(strbuf, 6, f);
\r
226 if (strcmp(strbuf,"MAPù5"))
\r
227 err("%s is not a recognized MAP file.",fname);
\r
229 // Lalala! Can you find Waldo hiding in the code? Here's a hint, he likes to dress like a candy-cane.
\r
232 vread(vspname, 60, f);
\r
233 vread(musname, 60, f);
\r
234 vread(rstring, 20, f);
\r
235 vread(&xstart, 2, f);
\r
236 vread(&ystart, 2, f);
\r
237 vread(strbuf, 51, f);
\r
238 vread(&numlayers, 1, f);
\r
239 for (i=0; i<numlayers; i++)
\r
240 vread(&layer[i], 12, f);
\r
242 memset(&layertoggle, 0, 8);
\r
243 for (i=0; i<numlayers; i++)
\r
245 vread(&bufsize, 4, f);
\r
246 layers[i]=(unsigned short *) valloc(layer[i].sizex*(layer[i].sizey+2)*2, "LoadMAP:layers[i]", OID_MAP);
\r
247 cb=(char *) valloc(bufsize, "LoadMAP:cb", OID_TEMP);
\r
248 vread(cb, bufsize, f);
\r
249 ReadCompressedLayer2(layers[i],(layer[i].sizex * layer[i].sizey), (word *) cb);
\r
253 obstruct=(byte *) valloc(layer[0].sizex*(layer[0].sizey+2), "obstruct", OID_MAP);
\r
254 zone=(byte *) valloc(layer[0].sizex*(layer[0].sizey+2), "zone", OID_MAP);
\r
256 vread(&bufsize, 4, f);
\r
257 cb=(char *) valloc(bufsize, "LoadMAP:cb (2)", OID_TEMP);
\r
258 vread(cb, bufsize, f);
\r
259 ReadCompressedLayer1(obstruct,(layer[0].sizex * layer[0].sizey), cb);
\r
261 vread(&bufsize, 4, f);
\r
262 cb=(char *) valloc(bufsize, "LoadMAP:cb (3)", OID_TEMP);
\r
263 vread(cb, bufsize, f);
\r
264 ReadCompressedLayer1(zone,(layer[0].sizex * layer[0].sizey), cb);
\r
266 memset(&zones, 0, sizeof zones);
\r
267 vread(&numzones, 4, f);
\r
268 vread(&zones, numzones*50, f);
\r
270 memset(&chrlist, 0, sizeof chrlist);
\r
271 vread(&nmchr, 1, f);
\r
272 vread(&chrlist, 60*nmchr, f);
\r
274 // Cheese is good, cheese is nice. Cheese is better, than body lice.
\r
276 memset(&entity, 0, sizeof entity);
\r
277 vread(&entities, 1, f);
\r
278 vread(&entity, (sizeof(entity)/256*entities), f);
\r
279 for (i=0; i<entities; i++)
\r
281 entity[i].tx=entity[i].x;
\r
282 entity[i].ty=entity[i].y;
\r
289 vread(&msbuf, nms*4, f);
\r
292 ms=(char *) valloc(i, "LoadMAP:ms", OID_MAP);
\r
298 ms=(char *) malloc(16);
\r
300 vread(&i, 4, f); // # of things
\r
304 memset(&chr, 0, sizeof chr);
\r
307 Logp(" [%d] ",mapevents);
\r
308 if (strlen(musname))
\r
309 PlayMusic(musname);
\r
320 for (i=0; i<numlayers; i++)
\r
324 memset(&entity, 0, sizeof entity);
\r
325 entities=0; nmchr=0; numchrs=0;
\r
335 memcpy(startmap, (char *) args[1], strlen((char *) args[1]));
\r
336 key[SCAN_RQUOTA]=1;
\r
340 // The_Edge rules. Really. I mean it. Wyrdwad too. They're as cool as Omniphile!
\r
346 Con_Printf("{||||||||||||||||||||}");
\r
347 sprintf(strbuf,"MAP stats for
\80%s~ -
\81%d~ layers",mapname,numlayers); Con_Printf(strbuf);
\r
348 sprintf(strbuf,"Base dimensions
\81%d~ x
\81%d~", layer[0].sizex, layer[0].sizey);
\r
349 Con_Printf(strbuf); a=layer[0].sizex*layer[0].sizey;
\r
350 sprintf(strbuf,"MAP using
\81%d~ bytes of memory",
\r
351 a*(2+(numlayers*2))); Con_Printf(strbuf);
\r
352 sprintf(strbuf,"
\81%d~ active zones.",numzones); Con_Printf(strbuf);
\r
353 Con_Printf("{||||||||||||||||||||}");
\r
354 sprintf(strbuf,"VSP file:
\80%s~",vspname); Con_Printf(strbuf);
\r
355 sprintf(strbuf,"VSP has
\81%d~ tiles using
\81%d~ bytes",numtiles,
\r
356 (numtiles*256)+800+(numtiles*3)); Con_Printf(strbuf);
\r
357 Con_Printf("{||||||||||||||||||||}");
\r
360 int PlayerObstructed(char dir)
\r
362 if (phantom) return 0;
\r
365 case 0: if (ObstructionAt(player->tx, player->ty+1)) return 1; break;
\r
366 case 1: if (ObstructionAt(player->tx, player->ty-1)) return 1; break;
\r
367 case 2: if (ObstructionAt(player->tx-1, player->ty)) return 1; break;
\r
368 case 3: if (ObstructionAt(player->tx+1, player->ty)) return 1; break;
\r
372 case 0: if (EntityObsAt(player->tx, player->ty+1)) return 1; break;
\r
373 case 1: if (EntityObsAt(player->tx, player->ty-1)) return 1; break;
\r
374 case 2: if (EntityObsAt(player->tx-1, player->ty)) return 1; break;
\r
375 case 3: if (EntityObsAt(player->tx+1, player->ty)) return 1; break;
\r
383 static int lz=0, zonedelay=0;
\r
385 curzone=zone[(player->ty * layer[0].sizex) + player->tx];
\r
391 if (!zones[curzone].percent) return;
\r
392 if (zonedelay < zones[curzone].delay)
\r
398 if (zones[curzone].script &&
\r
399 zones[curzone].percent >= rnd(0,255))
\r
401 ExecuteEvent(zones[curzone].script);
\r
408 switch(player -> facing)
\r
423 switch(player->facing)
\r
425 case 0: ax=player->tx; ay=player->ty+1; break;
\r
426 case 1: ax=player->tx; ay=player->ty-1; break;
\r
427 case 2: ax=player->tx-1; ay=player->ty; break;
\r
428 case 3: ax=player->tx+1; ay=player->ty; break;
\r
430 tz=zone[(ay*layer[0].sizex)+ax];
\r
433 ExecuteEvent(zones[tz].script);
\r
436 if ((tz=EntityAt(ax, ay)))
\r
439 if (entity[tz].face)
\r
441 entity[tz].facing=InvFace();
\r
442 AnimateEntity(&entity[tz]);
\r
444 if (entity[tz].actscript)
\r
447 ExecuteEvent(entity[tz].actscript);
\r
452 void ResetFollowers()
\r
456 player->x=player->tx<<4;
\r
457 player->y=player->ty<<4;
\r
461 for (i=0; i<numfollowers; i++)
\r
463 entity[follower[i]].x=player->x;
\r
464 entity[follower[i]].y=player->y;
\r
465 entity[follower[i]].tx=player->tx;
\r
466 entity[follower[i]].ty=player->ty;
\r
467 entity[follower[i]].facing=player->facing;
\r
468 entity[follower[i]].reset=1;
\r
470 memset(laststeps, 0, 10);
\r
473 void MoveFollowers()
\r
477 for (i=0; i<numfollowers; i++)
\r
479 entity[follower[i]].moving=laststeps[i+1];
\r
480 entity[follower[i]].movecnt=15;
\r
481 if (entity[follower[i]].reset ||
\r
482 entity[follower[i]].facing != laststeps[i+1]-1)
\r
484 //player->animofs=chr[player->chrindex].uanim;
\r
485 entity[follower[i]].delayct=0;
\r
486 entity[follower[i]].reset=0;
\r
488 entity[follower[i]].facing=laststeps[i+1]-1;
\r
494 void WritePalette(FILE *f)
\r
499 for (i=0; i<768; i++)
\r
500 pal3[i]=pal2[i] << 2;
\r
502 b=12; fwrite(&b, 1, 1, f);
\r
503 fwrite(pal3, 1, 768, f);
\r
506 void WritePCXLine(unsigned char *p,int len,FILE *pcxf)
\r
508 unsigned char byt, samect, repcode;
\r
514 while (samect<(unsigned) 63 && i<len && byt==p[i])
\r
519 if (samect>1 || (byt & 0xC0) != 0)
\r
521 repcode=0xC0 | samect;
\r
522 fwrite(&repcode,1,1,pcxf);
\r
524 fwrite(&byt,1,1,pcxf);
\r
532 unsigned short int w1;
\r
541 sprintf(fnamestr,"%d.pcx",n);
\r
542 pcxf=fopen(fnamestr,"r");
\r
544 if(pcxf) fclose(pcxf);
\r
549 // Takes a snapshot of the current screen.
\r
551 sprintf(fnamestr,"%d.pcx",n);
\r
553 pcxf=fopen(fnamestr,"wb");
\r
556 // Write PCX header
\r
558 b1=10; fwrite(&b1, 1, 1, pcxf); // manufacturer always = 10
\r
559 b1=5; fwrite(&b1, 1, 1, pcxf); // version = 3.0, >16 colors
\r
560 b1=1; fwrite(&b1, 1, 1, pcxf); // encoding always = 1
\r
561 b1=8; fwrite(&b1, 1, 1, pcxf); // 8 bits per pixel, for 256 colors
\r
562 w1=0; fwrite(&w1, 1, 2, pcxf); // xmin = 0;
\r
563 w1=0; fwrite(&w1, 1, 2, pcxf); // ymin = 0;
\r
564 w1=sx-1; fwrite(&w1, 1, 2, pcxf); // xmax = 319;
\r
565 w1=sy-1; fwrite(&w1, 1, 2, pcxf); // ymax = 199;
\r
566 w1=sx; fwrite(&w1, 1, 2, pcxf); // hres = 320;
\r
567 w1=sy; fwrite(&w1, 1, 2, pcxf); // vres = 200;
\r
569 fwrite(screen,1,48,pcxf);
\r
571 b1=0; fwrite(&b1, 1, 1, pcxf); // reserved always = 0.
\r
572 b1=1; fwrite(&b1, 1, 1, pcxf); // number of color planes. Just 1 for 8bit.
\r
573 w1=sx; fwrite(&w1, 1, 2, pcxf); // number of bytes per line
\r
575 w1=0; fwrite(&w1, 1, 1, pcxf);
\r
576 fwrite(screen, 1, 59, pcxf); // filler
\r
578 for (w1=0; w1<sy; w1++)
\r
579 WritePCXLine(screen+w1*tsx, sx, pcxf);
\r
581 WritePalette(pcxf);
\r
588 void LastMove(char dir)
\r
590 laststeps[9]=laststeps[8];
\r
591 laststeps[8]=laststeps[7];
\r
592 laststeps[7]=laststeps[6];
\r
593 laststeps[6]=laststeps[5];
\r
594 laststeps[5]=laststeps[4];
\r
595 laststeps[4]=laststeps[3];
\r
596 laststeps[3]=laststeps[2];
\r
597 laststeps[2]=laststeps[1];
\r
598 laststeps[1]=laststeps[0];
\r
604 void ProcessControls1()
\r
606 if (!player->moving)
\r
608 if (down && !PlayerObstructed(0))
\r
612 player->movecnt=15;
\r
614 if (player->reset || player->facing != 0)
\r
616 player->animofs=chr[player->chrindex].danim;
\r
624 if (up && !PlayerObstructed(1))
\r
628 player->movecnt=15;
\r
630 if (player->reset || player->facing != 1)
\r
632 player->animofs=chr[player->chrindex].uanim;
\r
640 if (left && !PlayerObstructed(2))
\r
644 player->movecnt=15;
\r
646 if (player->reset || player->facing != 2)
\r
648 player->animofs=chr[player->chrindex].lanim;
\r
656 if (right && !PlayerObstructed(3))
\r
660 player->movecnt=15;
\r
662 if (player->reset || player->facing != 3)
\r
664 player->animofs=chr[player->chrindex].ranim;
\r
672 if (down) player->facing=0;
\r
673 if (up) player->facing=1;
\r
674 if (left) player->facing=2;
\r
675 if (right) player->facing=3;
\r
678 switch (player->moving)
\r
680 case 0: player->reset=1; player->animofs=0; player->delayct=0; break;
\r
681 case 1: player->y++; player->movecnt--; break;
\r
682 case 2: player->y--; player->movecnt--; break;
\r
683 case 3: player->x--; player->movecnt--; break;
\r
684 case 4: player->x++; player->movecnt--; break;
\r
686 if (!player->movecnt && player->moving)
\r
691 if (!player->movecnt && b1) Activate();
\r
694 void ProcessControls()
\r
697 if (key[SCAN_RQUOTA])
\r
699 key[SCAN_RQUOTA]=0; last_pressed=0;
\r
702 if (key[SCAN_ALT] && key[SCAN_X]) err("Exiting: ALT-X pressed.");
\r
711 if (!player) return;
\r
713 if (player->speed<4)
\r
715 switch (player->speed)
\r
717 case 1: if (player->speedct<3) { player->speedct++; return; } break;
\r
718 case 2: if (player->speedct<2) { player->speedct++; return; } break;
\r
719 case 3: if (player->speedct<1) { player->speedct++; return; } break;
\r
722 if (player->speed<5)
\r
724 ProcessControls1();
\r
726 AnimateEntity(player);
\r
728 switch (player->speed)
\r
730 case 5: for (i=0; i<2; i++) { ProcessControls1(); AnimateEntity(player); } return;
\r
731 case 6: for (i=0; i<3; i++) { ProcessControls1(); AnimateEntity(player); } return;
\r
732 case 7: for (i=0; i<4; i++) { ProcessControls1(); AnimateEntity(player); } return;
\r
740 if (bindarray[last_pressed])
\r
741 HookKey(bindarray[last_pressed]);
\r
743 if (speeddemon && key[SCAN_CTRL]) ProcessControls();
\r