7 =============================================================================
\r
11 =============================================================================
\r
15 statobj_t statobjlist[MAXSTATS],*laststatobj;
\r
24 {SPR_STAT_0}, // puddle spr1v
\r
25 {SPR_STAT_1,block}, // Green Barrel "
\r
26 {SPR_STAT_2,block}, // Table/chairs "
\r
27 {SPR_STAT_3,block}, // Floor lamp "
\r
28 {SPR_STAT_4}, // Chandelier "
\r
29 {SPR_STAT_5,block}, // Hanged man "
\r
30 {SPR_STAT_6,bo_alpo}, // Bad food "
\r
31 {SPR_STAT_7,block}, // Red pillar "
\r
35 {SPR_STAT_8,block}, // Tree spr2v
\r
36 {SPR_STAT_9}, // Skeleton flat "
\r
37 {SPR_STAT_10,block}, // Sink " (SOD:gibs)
\r
38 {SPR_STAT_11,block}, // Potted plant "
\r
39 {SPR_STAT_12,block}, // Urn "
\r
40 {SPR_STAT_13,block}, // Bare table "
\r
41 {SPR_STAT_14}, // Ceiling light "
\r
43 {SPR_STAT_15}, // Kitchen stuff "
\r
45 {SPR_STAT_15,block}, // Gibs!
\r
50 {SPR_STAT_16,block}, // suit of armor spr3v
\r
51 {SPR_STAT_17,block}, // Hanging cage "
\r
52 {SPR_STAT_18,block}, // SkeletoninCage "
\r
53 {SPR_STAT_19}, // Skeleton relax "
\r
54 {SPR_STAT_20,bo_key1}, // Key 1 "
\r
55 {SPR_STAT_21,bo_key2}, // Key 2 "
\r
56 {SPR_STAT_22,block}, // stuff (SOD:gibs)
\r
57 {SPR_STAT_23}, // stuff
\r
61 {SPR_STAT_24,bo_food}, // Good food spr4v
\r
62 {SPR_STAT_25,bo_firstaid}, // First aid "
\r
63 {SPR_STAT_26,bo_clip}, // Clip "
\r
64 {SPR_STAT_27,bo_machinegun}, // Machine gun "
\r
65 {SPR_STAT_28,bo_chaingun}, // Gatling gun "
\r
66 {SPR_STAT_29,bo_cross}, // Cross "
\r
67 {SPR_STAT_30,bo_chalice}, // Chalice "
\r
68 {SPR_STAT_31,bo_bible}, // Bible "
\r
72 {SPR_STAT_32,bo_crown}, // crown spr5v
\r
73 {SPR_STAT_33,bo_fullheal}, // one up "
\r
74 {SPR_STAT_34,bo_gibs}, // gibs "
\r
75 {SPR_STAT_35,block}, // barrel "
\r
76 {SPR_STAT_36,block}, // well "
\r
77 {SPR_STAT_37,block}, // Empty well "
\r
78 {SPR_STAT_38,bo_gibs}, // Gibs 2 "
\r
79 {SPR_STAT_39,block}, // flag "
\r
84 {SPR_STAT_40,block}, // Call Apogee spr7v
\r
86 {SPR_STAT_40}, // Red light
\r
91 {SPR_STAT_41}, // junk "
\r
92 {SPR_STAT_42}, // junk "
\r
93 {SPR_STAT_43}, // junk "
\r
95 {SPR_STAT_44}, // pots "
\r
97 {SPR_STAT_44,block}, // Gibs!
\r
99 {SPR_STAT_45,block}, // stove " (SOD:gibs)
\r
100 {SPR_STAT_46,block}, // spears " (SOD:gibs)
\r
101 {SPR_STAT_47}, // vines "
\r
106 {SPR_STAT_48,block}, // marble pillar
\r
107 {SPR_STAT_49,bo_25clip}, // bonus 25 clip
\r
108 {SPR_STAT_50,block}, // truck
\r
109 {SPR_STAT_51,bo_spear}, // SPEAR OF DESTINY!
\r
112 {SPR_STAT_26,bo_clip2}, // Clip "
\r
124 void InitStaticList (void)
\r
126 laststatobj = &statobjlist[0];
\r
139 void SpawnStatic (int tilex, int tiley, int type)
\r
141 laststatobj->shapenum = statinfo[type].picnum;
\r
142 laststatobj->tilex = tilex;
\r
143 laststatobj->tiley = tiley;
\r
144 laststatobj->visspot = &spotvis[tilex][tiley];
\r
146 switch (statinfo[type].type)
\r
149 (unsigned)actorat[tilex][tiley] = 1; // consider it a blocking tile
\r
151 laststatobj->flags = 0;
\r
160 gamestate.treasuretotal++;
\r
169 case bo_machinegun:
\r
175 laststatobj->flags = FL_BONUS;
\r
176 laststatobj->itemnumber = statinfo[type].type;
\r
182 if (laststatobj == &statobjlist[MAXSTATS])
\r
183 Quit ("Too many static objects!\n");
\r
192 = Called during game play to drop actors' items. It finds the proper
\r
193 = item number based on the item type (bo_???). If there are no free item
\r
194 = spots, nothing is done.
\r
199 void PlaceItemType (int itemtype, int tilex, int tiley)
\r
205 // find the item number
\r
207 for (type=0 ; ; type++)
\r
209 if (statinfo[type].picnum == -1) // end of list
\r
210 Quit ("PlaceItemType: couldn't find type!");
\r
211 if (statinfo[type].type == itemtype)
\r
216 // find a spot in statobjlist to put it in
\r
218 for (spot=&statobjlist[0] ; ; spot++)
\r
220 if (spot==laststatobj)
\r
222 if (spot == &statobjlist[MAXSTATS])
\r
223 return; // no free spots
\r
224 laststatobj++; // space at end
\r
228 if (spot->shapenum == -1) // -1 is a free spot
\r
234 spot->shapenum = statinfo[type].picnum;
\r
235 spot->tilex = tilex;
\r
236 spot->tiley = tiley;
\r
237 spot->visspot = &spotvis[tilex][tiley];
\r
238 spot->flags = FL_BONUS;
\r
239 spot->itemnumber = statinfo[type].type;
\r
245 =============================================================================
\r
249 doorobjlist[] holds most of the information for the doors
\r
251 doorposition[] holds the amount the door is open, ranging from 0 to 0xffff
\r
252 this is directly accessed by AsmRefresh during rendering
\r
254 The number of doors is limited to 64 because a spot in tilemap holds the
\r
255 door number in the low 6 bits, with the high bit meaning a door center
\r
256 and bit 6 meaning a door side tile
\r
258 Open doors conect two areas, so sounds will travel between them and sight
\r
259 will be checked when the player is in a connected area.
\r
261 Areaconnect is incremented/decremented by each door. If >0 they connect
\r
263 Every time a door opens or closes the areabyplayer matrix gets recalculated.
\r
264 An area is true if it connects with the player's current spor.
\r
266 =============================================================================
\r
269 #define DOORWIDTH 0x7800
\r
270 #define OPENTICS 300
\r
272 doorobj_t doorobjlist[MAXDOORS],*lastdoorobj;
\r
275 unsigned doorposition[MAXDOORS]; // leading edge of door 0=closed
\r
276 // 0xffff = fully open
\r
278 byte far areaconnect[NUMAREAS][NUMAREAS];
\r
280 boolean areabyplayer[NUMAREAS];
\r
288 = Scans outward from playerarea, marking all connected areas
\r
293 void RecursiveConnect (int areanumber)
\r
297 for (i=0;i<NUMAREAS;i++)
\r
299 if (areaconnect[areanumber][i] && !areabyplayer[i])
\r
301 areabyplayer[i] = true;
\r
302 RecursiveConnect (i);
\r
308 void ConnectAreas (void)
\r
310 memset (areabyplayer,0,sizeof(areabyplayer));
\r
311 areabyplayer[player->areanumber] = true;
\r
312 RecursiveConnect (player->areanumber);
\r
316 void InitAreas (void)
\r
318 memset (areabyplayer,0,sizeof(areabyplayer));
\r
319 areabyplayer[player->areanumber] = true;
\r
332 void InitDoorList (void)
\r
334 memset (areabyplayer,0,sizeof(areabyplayer));
\r
335 _fmemset (areaconnect,0,sizeof(areaconnect));
\r
337 lastdoorobj = &doorobjlist[0];
\r
350 void SpawnDoor (int tilex, int tiley, boolean vertical, int lock)
\r
356 Quit ("64+ doors on level!");
\r
358 doorposition[doornum] = 0; // doors start out fully closed
\r
359 lastdoorobj->tilex = tilex;
\r
360 lastdoorobj->tiley = tiley;
\r
361 lastdoorobj->vertical = vertical;
\r
362 lastdoorobj->lock = lock;
\r
363 lastdoorobj->action = dr_closed;
\r
365 (unsigned)actorat[tilex][tiley] = doornum | 0x80; // consider it a solid wall
\r
368 // make the door tile a special tile, and mark the adjacent tiles
\r
371 tilemap[tilex][tiley] = doornum | 0x80;
\r
372 map = mapsegs[0] + farmapylookup[tiley]+tilex;
\r
375 *map = *(map-1); // set area number
\r
376 tilemap[tilex][tiley-1] |= 0x40;
\r
377 tilemap[tilex][tiley+1] |= 0x40;
\r
381 *map = *(map-mapwidth); // set area number
\r
382 tilemap[tilex-1][tiley] |= 0x40;
\r
383 tilemap[tilex+1][tiley] |= 0x40;
\r
390 //===========================================================================
\r
393 =====================
\r
397 =====================
\r
400 void OpenDoor (int door)
\r
402 if (doorobjlist[door].action == dr_open)
\r
403 doorobjlist[door].ticcount = 0; // reset open time
\r
405 doorobjlist[door].action = dr_opening; // start it opening
\r
410 =====================
\r
414 =====================
\r
417 void CloseDoor (int door)
\r
419 int tilex,tiley,area;
\r
423 // don't close on anything solid
\r
425 tilex = doorobjlist[door].tilex;
\r
426 tiley = doorobjlist[door].tiley;
\r
428 if (actorat[tilex][tiley])
\r
431 if (player->tilex == tilex && player->tiley == tiley)
\r
434 if (doorobjlist[door].vertical)
\r
436 if ( player->tiley == tiley )
\r
438 if ( ((player->x+MINDIST) >>TILESHIFT) == tilex )
\r
440 if ( ((player->x-MINDIST) >>TILESHIFT) == tilex )
\r
443 check = actorat[tilex-1][tiley];
\r
444 if (check && ((check->x+MINDIST) >> TILESHIFT) == tilex )
\r
446 check = actorat[tilex+1][tiley];
\r
447 if (check && ((check->x-MINDIST) >> TILESHIFT) == tilex )
\r
450 else if (!doorobjlist[door].vertical)
\r
452 if (player->tilex == tilex)
\r
454 if ( ((player->y+MINDIST) >>TILESHIFT) == tiley )
\r
456 if ( ((player->y-MINDIST) >>TILESHIFT) == tiley )
\r
459 check = actorat[tilex][tiley-1];
\r
460 if (check && ((check->y+MINDIST) >> TILESHIFT) == tiley )
\r
462 check = actorat[tilex][tiley+1];
\r
463 if (check && ((check->y-MINDIST) >> TILESHIFT) == tiley )
\r
469 // play door sound if in a connected area
\r
471 area = *(mapsegs[0] + farmapylookup[doorobjlist[door].tiley]
\r
472 +doorobjlist[door].tilex)-AREATILE;
\r
473 if (areabyplayer[area])
\r
475 PlaySoundLocTile(CLOSEDOORSND,doorobjlist[door].tilex,doorobjlist[door].tiley); // JAB
\r
478 doorobjlist[door].action = dr_closing;
\r
480 // make the door space solid
\r
482 (unsigned)actorat[tilex][tiley]
\r
489 =====================
\r
493 = The player wants to change the door's direction
\r
495 =====================
\r
498 void OperateDoor (int door)
\r
502 lock = doorobjlist[door].lock;
\r
503 if (lock >= dr_lock1 && lock <= dr_lock4)
\r
505 if ( ! (gamestate.keys & (1 << (lock-dr_lock1) ) ) )
\r
507 SD_PlaySound (NOWAYSND); // locked
\r
512 switch (doorobjlist[door].action)
\r
526 //===========================================================================
\r
533 = Close the door after three seconds
\r
538 void DoorOpen (int door)
\r
540 if ( (doorobjlist[door].ticcount += tics) >= OPENTICS)
\r
554 void DoorOpening (int door)
\r
560 position = doorposition[door];
\r
564 // door is just starting to open, so connect the areas
\r
566 map = mapsegs[0] + farmapylookup[doorobjlist[door].tiley]
\r
567 +doorobjlist[door].tilex;
\r
569 if (doorobjlist[door].vertical)
\r
576 area1 = *(map-mapwidth);
\r
577 area2 = *(map+mapwidth);
\r
581 areaconnect[area1][area2]++;
\r
582 areaconnect[area2][area1]++;
\r
584 if (areabyplayer[area1])
\r
586 PlaySoundLocTile(OPENDOORSND,doorobjlist[door].tilex,doorobjlist[door].tiley); // JAB
\r
591 // slide the door by an adaptive amount
\r
593 position += tics<<10;
\r
594 if (position >= 0xffff)
\r
597 // door is all the way open
\r
600 doorobjlist[door].ticcount = 0;
\r
601 doorobjlist[door].action = dr_open;
\r
602 actorat[doorobjlist[door].tilex][doorobjlist[door].tiley] = 0;
\r
605 doorposition[door] = position;
\r
617 void DoorClosing (int door)
\r
619 int area1,area2,move;
\r
624 tilex = doorobjlist[door].tilex;
\r
625 tiley = doorobjlist[door].tiley;
\r
627 if ( ((unsigned)actorat[tilex][tiley] != (door | 0x80))
\r
628 || (player->tilex == tilex && player->tiley == tiley) )
\r
629 { // something got inside the door
\r
634 position = doorposition[door];
\r
637 // slide the door by an adaptive amount
\r
639 position -= tics<<10;
\r
643 // door is closed all the way, so disconnect the areas
\r
647 doorobjlist[door].action = dr_closed;
\r
649 map = mapsegs[0] + farmapylookup[doorobjlist[door].tiley]
\r
650 +doorobjlist[door].tilex;
\r
652 if (doorobjlist[door].vertical)
\r
659 area1 = *(map-mapwidth);
\r
660 area2 = *(map+mapwidth);
\r
664 areaconnect[area1][area2]--;
\r
665 areaconnect[area2][area1]--;
\r
670 doorposition[door] = position;
\r
677 =====================
\r
681 = Called from PlayLoop
\r
683 =====================
\r
686 void MoveDoors (void)
\r
690 if (gamestate.victoryflag) // don't move door during victory sequence
\r
693 for (door = 0 ; door < doornum ; door++)
\r
694 switch (doorobjlist[door].action)
\r
712 =============================================================================
\r
716 =============================================================================
\r
719 unsigned pwallstate;
\r
720 unsigned pwallpos; // amount a pushable wall has been moved (0-63)
\r
721 unsigned pwallx,pwally;
\r
732 void PushWall (int checkx, int checky, int dir)
\r
740 oldtile = tilemap[checkx][checky];
\r
747 if (actorat[checkx][checky-1])
\r
749 SD_PlaySound (NOWAYSND);
\r
752 (unsigned)actorat[checkx][checky-1] =
\r
753 tilemap[checkx][checky-1] = oldtile;
\r
757 if (actorat[checkx+1][checky])
\r
759 SD_PlaySound (NOWAYSND);
\r
762 (unsigned)actorat[checkx+1][checky] =
\r
763 tilemap[checkx+1][checky] = oldtile;
\r
767 if (actorat[checkx][checky+1])
\r
769 SD_PlaySound (NOWAYSND);
\r
772 (unsigned)actorat[checkx][checky+1] =
\r
773 tilemap[checkx][checky+1] = oldtile;
\r
777 if (actorat[checkx-1][checky])
\r
779 SD_PlaySound (NOWAYSND);
\r
782 (unsigned)actorat[checkx-1][checky] =
\r
783 tilemap[checkx-1][checky] = oldtile;
\r
787 gamestate.secretcount++;
\r
793 tilemap[pwallx][pwally] |= 0xc0;
\r
794 *(mapsegs[1]+farmapylookup[pwally]+pwallx) = 0; // remove P tile info
\r
796 SD_PlaySound (PUSHWALLSND);
\r
809 void MovePWalls (void)
\r
811 int oldblock,oldtile;
\r
816 oldblock = pwallstate/128;
\r
818 pwallstate += tics;
\r
820 if (pwallstate/128 != oldblock)
\r
822 // block crossed into a new block
\r
823 oldtile = tilemap[pwallx][pwally] & 63;
\r
826 // the tile can now be walked into
\r
828 tilemap[pwallx][pwally] = 0;
\r
829 (unsigned)actorat[pwallx][pwally] = 0;
\r
830 *(mapsegs[0]+farmapylookup[pwally]+pwallx) = player->areanumber+AREATILE;
\r
833 // see if it should be pushed farther
\r
835 if (pwallstate>256)
\r
838 // the block has been pushed two tiles
\r
849 if (actorat[pwallx][pwally-1])
\r
854 (unsigned)actorat[pwallx][pwally-1] =
\r
855 tilemap[pwallx][pwally-1] = oldtile;
\r
860 if (actorat[pwallx+1][pwally])
\r
865 (unsigned)actorat[pwallx+1][pwally] =
\r
866 tilemap[pwallx+1][pwally] = oldtile;
\r
871 if (actorat[pwallx][pwally+1])
\r
876 (unsigned)actorat[pwallx][pwally+1] =
\r
877 tilemap[pwallx][pwally+1] = oldtile;
\r
882 if (actorat[pwallx-1][pwally])
\r
887 (unsigned)actorat[pwallx-1][pwally] =
\r
888 tilemap[pwallx-1][pwally] = oldtile;
\r
892 tilemap[pwallx][pwally] = oldtile | 0xc0;
\r
897 pwallpos = (pwallstate/2)&63;
\r