This repository has been archived by the owner on Mar 23, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
/
Level.c
732 lines (621 loc) · 16.6 KB
/
Level.c
1
#include "wolfdef.h"#include <string.h>/* static object info*//* List of bad guy sprites */static Word DKnightSprs[] = {S_DKNIGHT_ATK1,S_DKNIGHT_ATK2,S_DKNIGHT_ATK3,S_DKNIGHT_ATK4,S_DKNIGHT_WLK1,S_DKNIGHT_WLK2,S_DKNIGHT_WLK3,S_DKNIGHT_WLK4,S_DKNIGHT_DTH1,S_DKNIGHT_DTH2,S_DKNIGHT_DTH3,S_G_KEY,0};static Word DogSprs[] = {S_DOG_ATK1,S_DOG_ATK2,S_DOG_ATK3,S_DOG_WLK1,S_DOG_WLK2,S_DOG_WLK3,S_DOG_WLK4,S_DOG_DTH1,S_DOG_DTH2,S_DOG_DTH3,0};static Word NaziSprs[] = {S_GUARD_ATK1,S_GUARD_ATK2,S_GUARD_ATK3,S_GUARD_WLK1,S_GUARD_WLK2,S_GUARD_WLK3,S_GUARD_WLK4,S_GUARD_PAIN,S_GUARD_DTH1,S_GUARD_DTH2,S_GUARD_DTH3,S_AMMO,0};static Word HansSprs[] = {S_HANS_ATK1,S_HANS_ATK2,S_HANS_ATK3,S_HANS_WLK1,S_HANS_WLK2,S_HANS_WLK3,S_HANS_WLK4,S_HANS_DTH1,S_HANS_DTH2,S_HANS_DTH3,S_G_KEY,0};static Word HitlerSprs[] = {S_HITLER_ATK1,S_HITLER_ATK2,S_HITLER_ATK3,S_HITLER_WLK1,S_HITLER_WLK2,S_HITLER_WLK3,S_HITLER_WLK4,S_HITLER_DTH1,S_HITLER_DTH2,S_HITLER_DTH3,S_MHITLER_ATK1,S_MHITLER_ATK2,S_MHITLER_ATK3,S_MHITLER_DIE1,S_MHITLER_DIE2,S_MHITLER_DIE3,S_MHITLER_DIE4,S_MHITLER_WLK1,S_MHITLER_WLK2,S_MHITLER_WLK3,S_MHITLER_WLK4,0};static Word UberSprs[] = {S_UBER_ATK1,S_UBER_ATK2,S_UBER_ATK3,S_UBER_ATK4,S_UBER_WLK1,S_UBER_WLK2,S_UBER_WLK3,S_UBER_WLK4,S_UBER_DTH1,S_UBER_DTH2,S_UBER_DTH3,S_G_KEY,0};static Word MutantSprs[] = {S_MUTANT_ATK1,S_MUTANT_ATK2,S_MUTANT_ATK3,S_MUTANT_WLK1,S_MUTANT_WLK2,S_MUTANT_WLK3,S_MUTANT_WLK4,S_MUTANT_PAIN,S_MUTANT_DTH1,S_MUTANT_DTH2,S_MUTANT_DTH3,S_AMMO,0};static Word OfficerSprs[] = {S_OFFICER_ATK1,S_OFFICER_ATK2,S_OFFICER_ATK3,S_OFFICER_WLK1,S_OFFICER_WLK2,S_OFFICER_WLK3,S_OFFICER_WLK4,S_OFFICER_PAIN,S_OFFICER_DTH1,S_OFFICER_DTH2,S_OFFICER_DTH3,S_AMMO,0};static Word SchabbsSpr[] = {S_SCHABBS_ATK1,S_SCHABBS_ATK2,S_SCHABBS_WLK1,S_SCHABBS_WLK2,S_SCHABBS_WLK3,S_SCHABBS_WLK4,S_SCHABBS_DTH1,S_SCHABBS_DTH2,S_SCHABBS_DTH3,S_G_KEY,0};static Word SSSprs[] = {S_SS_ATK1,S_SS_ATK2,S_SS_ATK3,S_SS_WLK1,S_SS_WLK2,S_SS_WLK3,S_SS_WLK4,S_SS_PAIN,S_SS_DTH1,S_SS_DTH2,S_SS_DTH3,S_MACHINEGUN,S_AMMO,0};static Word TransSprs[] = {S_TRANS_ATK1,S_TRANS_ATK2,S_TRANS_ATK3,S_TRANS_WLK1,S_TRANS_WLK2,S_TRANS_WLK3,S_TRANS_WLK4,S_TRANS_DTH1,S_TRANS_DTH2,S_TRANS_DTH3,S_G_KEY,0};static Byte EnemyHits[16];static Word *EnemySprs[] = { /* This list MUST match class_t! */NaziSprs,OfficerSprs,SSSprs,DogSprs,MutantSprs,HansSprs,SchabbsSpr,TransSprs,UberSprs,DKnightSprs,HitlerSprs,HitlerSprs};static Byte WallHits[256];Word staticflags[] = {0, /*S_WATER_PUDDLE,*/TI_BLOCKMOVE, /*S_GREEN_BARREL,*/TI_BLOCKMOVE, /*S_CHAIR_TABLE,*/TI_BLOCKMOVE, /*S_FLOOR_LAMP,*/0, /*S_CHANDELIER,*/TI_GETABLE, /*S_DOG_FOOD,*/TI_BLOCKMOVE, /*S_COLUMN,*/TI_BLOCKMOVE, /*S_POTTED_TREE,*/TI_BLOCKMOVE, /*S_FLAG,*/TI_BLOCKMOVE, /*S_POTTED_PLANT,*/TI_BLOCKMOVE, /*S_BLUE_POT,*/0, /*S_DEBRIS1,*/0, /*S_LIGHT,*/0, /*S_BUCKET,*/TI_BLOCKMOVE, /*S_ARMOUR,*/TI_BLOCKMOVE, /*S_CAGE,*/TI_GETABLE, /*S_G_KEY,*/TI_GETABLE, /*S_S_KEY,*/TI_GETABLE, /*S_BANDOLIER*/TI_GETABLE, /*S_AMMOCASE,*/TI_GETABLE, /*S_FOOD,*/TI_GETABLE, /*S_HEALTH,*/TI_GETABLE, /*S_AMMO,*/TI_GETABLE, /*S_MACHINEGUN,*/TI_GETABLE, /*S_CHAINGUN,*/TI_GETABLE, /*S_CROSS,*/TI_GETABLE, /*S_CHALICE,*/TI_GETABLE, /*S_CHEST,*/TI_GETABLE, /*S_CROWN,*/TI_GETABLE, /*S_ONEUP,*/TI_BLOCKMOVE, /*S_WOOD_BARREL,*/TI_BLOCKMOVE, /*S_WATER_WELL,*/TI_GETABLE, /*S_FLAMETHROWER */TI_GETABLE, /*S_GASCAN */TI_GETABLE, /*S_LAUNCHER */TI_GETABLE /*S_MISSILES */};/********************************** Spawn a static object at x,y**********************************/void SpawnStatic(Word x,Word y,Word shape){ Word *TilePtr; static_t *StatPtr; if (numstatics>=MAXSTATICS) { return; /* Oh oh!! */ } TilePtr = &tilemap[y][x]; /* Precalc tile pointer */ StatPtr = &statics[numstatics]; StatPtr->x = (x<<FRACBITS)+0x80; /* Set the pixel X */ StatPtr->y = (y<<FRACBITS)+0x80; /* Set the pixel Y */ StatPtr->areanumber = TilePtr[0] & TI_NUMMASK; /* Mask off the area number */ TilePtr[0] |= staticflags[shape]; shape += S_WATER_PUDDLE; /* Init the shape number */ WallHits[shape] = 1; /* Load in this shape */ StatPtr->pic = shape; /* Set the object's shape */ switch (shape) { case S_CROSS: case S_CHALICE: case S_CHEST: case S_CROWN: case S_ONEUP: ++gamestate.treasuretotal; /* Mark this as treasure */ } ++numstatics; /* I have one more item */}/********************************** Spawn the player at x,y**********************************/void SpawnPlayer(Word x,Word y,Word dir){ gamestate.viewangle = (1-dir)*ANGLES/4; /* Get the basic viewing angle */ actors[0].x = (x<<FRACBITS)+0x80; /* Save the X coord */ actors[0].y = (y<<FRACBITS)+0x80; /* Save the Y coord */ actors[0].class = CL_PLAYER; /* This is the player */ actors[0].areanumber = tilemap[y][x]&TI_NUMMASK; /* Which area? */ ConnectCount = 0; /* Zap the interconnects */ ConnectAreas(); /* Init the area table */}/********************************** Spawn an actor at a specific x,y**********************************/void SpawnStand(Word x,Word y,class_t which){ stateindex_t state; classinfo_t *info; actor_t *ActorPtr; Word *TilePtr; Word tile; if (numactors==MAXACTORS) { /* Too many actors already? */ return; /* Exit */ } EnemyHits[which] = 1; info = &classinfo[which]; /* Get the pointer to the basic info */ state = info->standstate; /* Get the state logic value */ ActorPtr = &actors[numactors]; /* Get the pointer to the new actor entry */ TilePtr = &tilemap[y][x]; /* Pointer to the current tile */ tile = TilePtr[0]; /* What's in the tile? */ ActorPtr->x = (x<<FRACBITS)+0x80; /* Init the x and y */ ActorPtr->y = (y<<FRACBITS)+0x80; ActorPtr->pic = states[state].shapenum; /* What picture to display? */ ActorPtr->ticcount = states[state].tictime; /* Initial tick count */ ActorPtr->state = state; ActorPtr->flags = FL_SHOOTABLE | FL_NOTMOVING; /* You can shoot it */ ActorPtr->distance = 0; /* No distance to travel */ ActorPtr->dir = nodir; /* No direction of travel */ ActorPtr->areanumber = tile&TI_NUMMASK; /* Area in */ ActorPtr->reacttime = 0; /* Reaction time */ TilePtr[0] = tile | TI_ACTOR; /* Mark as a bad guy */ MapPtr->tilemap[y][x] = numactors; /* Save the actor # */ ActorPtr->goalx = x; /* Don't travel anywhere */ ActorPtr->goaly = y; ActorPtr->class = which; /* Actor type */ ActorPtr->speed = info->speed; /* Basic speed */ ActorPtr->hitpoints = info->hitpoints; /* Starting hit points */ ++numactors; /* I now add one more actor to the list */ ++gamestate.killtotal; /* Another critter must die! */}/********************************** Spawn an actor at a specific x,y and ALSO set the ambush flag**********************************/void SpawnAmbush(Word x,Word y,class_t which){ actor_t *ActorPtr; ActorPtr = &actors[numactors]; /* Get the pointer to the new actor entry */ SpawnStand(x,y,which); /* Fill in all the entries */ ActorPtr->flags |= FL_AMBUSH; /* Set the ambush flag */}/********************************** Spawn a door at the specified x,y**********************************/void SpawnDoor(Word x,Word y,Word type){ door_t *door; Word *TilePtr; if (numdoors==MAXDOORS) { return; } TilePtr = &tilemap[y-1][x]; /* Pointer to the tile (-1 y) for door->area index */ door = &doors[numdoors]; /* Pointer to the door record */ door->position = 0; /* doors start out fully closed*/ door->tilex = x; door->tiley = y; door->info = type-90; /* Set the door type */ door->action = DR_CLOSED; /* Mark as closed */ TilePtr[MAPSIZE] = (TI_DOOR|TI_BLOCKMOVE|TI_BLOCKSIGHT)| numdoors; if (type & 1) { /* horizontal*/ door->area1 = TilePtr[MAPSIZE*2] & TI_NUMMASK; /* One cell below */ door->area2 = TilePtr[0] & TI_NUMMASK; /* One cell above */ } else { door->area1 = TilePtr[MAPSIZE-1] & TI_NUMMASK; /* One cell left */ door->area2 = TilePtr[MAPSIZE+1] & TI_NUMMASK; /* One cell right */ } ++numdoors;}/********************************** Spawn a pushwall track at the specified x,y**********************************/void AddPWallTrack(Word x,Word y,Word tile){ Byte *TextPtr; if (x>=MAPSIZE || y>=MAPSIZE) { return; /* pushwall is off the edge of a map*/ } TextPtr = &textures[MAPSIZE+x][y]; if (TextPtr[0] != 0xff) { /* Already marked? */ return; /* solid wall*/ } TextPtr[0] = tile + 1; /* Save the tile # */ textures[y][x] = tile; /* Mark the texture index */}/********************************** Spawn a pushwall at the specified x,y**********************************/void SpawnPushwall(Word x,Word y,Word tile){ ++gamestate.secrettotal; /* Secret area! */ tilemap[y][x] |= (TI_BLOCKMOVE | TI_BLOCKSIGHT | TI_PUSHWALL);/* directly set texture values for rendering*/ tile = (tile-1)<<1; AddPWallTrack(x, y, tile); AddPWallTrack(x-1, y, tile); AddPWallTrack(x-2, y, tile); AddPWallTrack(x+1, y, tile); AddPWallTrack(x+2, y, tile); AddPWallTrack(x, y-1, tile); AddPWallTrack(x, y-2, tile); AddPWallTrack(x, y+1, tile); AddPWallTrack(x, y+2, tile);}/********************************** Spawn an elevator at the specified x,y**********************************/void SpawnElevator(Word x,Word y){ elevatorx = x; /* for easy mode cheating*/ elevatory = y; tilemap[y][x] |= TI_BLOCKMOVE | TI_SWITCH;}/********************************** Spawn the outside at the specified x,y**********************************/void SpawnOut(Word x,Word y){ /*tilemap[y][x] |= TI_BLOCKMOVE | TI_SWITCH;*/}/********************************** Spawn a secret item at the specified x,y**********************************/void SpawnSecret(Word x,Word y){ tilemap[y][x] |= TI_BLOCKMOVE | TI_SECRET;}/********************************** Spawn all actors and mark down special places A spawn record is (x,y,type) **********************************/void SpawnThings(void){ Word x,y; /* Temp x,y */ Word type; /* Item to spawn */ Byte *spawn_p; Word Count; /* Number of items to create */ Word *EnemyPtr; memset(EnemyHits,0,sizeof(EnemyHits)); spawn_p = (Byte *)MapPtr+MapPtr->spawnlistofs; /* Point to the spawn table */ Count = MapPtr->numspawn; /* How many items to spawn? */ if (!Count) { return; } do { x = spawn_p[0]; /* Get the X */ y = spawn_p[1]; /* Get the y */ type = spawn_p[2]; /* Get the type */ spawn_p+=3; /* Index past the record */ if (type<19) { continue; } else if (type<23) { /* 19-22 */ SpawnPlayer(x,y,type-19); } else if (type<59) { /* 23-58 */ SpawnStatic(x,y,type-23); } else if (type<90) { /* 59-89 */ continue; } else if (type<98) { /* 90-97 */ SpawnDoor(x,y,type); } else if (type == 98) { /* 98 */ SpawnPushwall(x,y,spawn_p[0]); ++spawn_p; } else if (type == 99) { /* 99 */ SpawnOut(x,y); } else if (type == 100) { /* 100 */ SpawnElevator(x,y); } else if (type == 101) { /* 101 */ SpawnSecret(x,y); } else if (type<108) { /* 102-107 */ continue; } else if (type<123) { /* 108-122 */ SpawnStand(x,y,(class_t) (type-108)); } else if (type<126) { /* 123-125 */ continue; } else if (type<140) { /* 126-139 */ SpawnAmbush(x,y,(class_t) (type-126)); } } while (--Count); Count = 0; do { if (EnemyHits[Count]) { x = 0; EnemyPtr = EnemySprs[Count]; do { WallHits[EnemyPtr[x]] = 1; ++x; } while (EnemyPtr[x]); } } while (++Count<16);}/********************************** Release the map data **********************************/void ReleaseMap(void){ Word i; if (OldMapNum) { KillAResource(OldMapNum); /* Make SURE it's purged! */ OldMapNum = 0; /* Nothing loaded */ MapPtr = 0; /* No data available */ } i = 0; do { if (ArtData[i]) { FreeSomeMem(ArtData[i]); /* Release the wall art */ ArtData[i] = 0; } } while (++i<64); /* All walls done? */ i = 1; do { if (SpriteArray[i]) { /* Is this sprite loaded? */ FreeSomeMem(SpriteArray[i]); /* Release the memory */ SpriteArray[i] = 0; } } while (++i<S_LASTONE); /* All done? */}/********************************** Load and initialize everything for current game level Spawnlist 0-(numusable-1) are the usable (door/pushwall) spawn objects Polysegs 0-(numpushwalls-1) are four sided pushwall segs **********************************/Boolean SetupGameLevel(void){ Byte *src; Word *dest; Word tile; Word Count; /* clear counts*/ gamestate.secrettotal=0; /* No secret items found */ gamestate.killtotal=0; /* Noone killed */ gamestate.treasuretotal=0; /* No treasure found */ gamestate.secretcount=0; /* No secret areas found */ gamestate.killcount=0; /* Noone to kill on this level */ gamestate.treasurecount = 0; /* No treasures laid *//* Load a level */ ReleaseMap(); /* Free up any previous map */ OldMapNum = (MapListPtr->MapRezNum)+gamestate.mapon; /* Which map to load */ MapPtr = LoadAResource(OldMapNum); /* Load in the map */ if (!MapPtr) { return FALSE; /* Uh.. yeah... */ } DrawPsyched(1); /* First stage done */#ifdef __BIGENDIAN__ MapPtr->numspawn = SwapUShort(MapPtr->numspawn); /* Fix for 68000 machines */ MapPtr->spawnlistofs = SwapUShort(MapPtr->spawnlistofs); MapPtr->numnodes = SwapUShort(MapPtr->numnodes); MapPtr->nodelistofs = SwapUShort(MapPtr->nodelistofs);#endif numstatics = 0; /* Clear out the static array */ numdoors = 0; /* Clear out the door array */ numactors = 1; /* player has spot 0*/ nummissiles = 0; /* Clear out the missile array */ /* expand the byte width map to word width*/ memset(WallHits,0,sizeof(WallHits)); src = &MapPtr->tilemap[0][0]; dest = &tilemap[0][0]; Count = 0; do { tile = src[Count]; /* Get the byte tile */ if (tile & TI_BLOCKMOVE) { tile |= TI_BLOCKSIGHT; /* Mark as blocking my sight */ WallHits[(tile-1)&0x1F]=1; } dest[Count] = tile; /* Save the new tile */ } while (++Count<MAPSIZE*MAPSIZE); /* let the rendering engine know about the new map*/ NewMap(); /* Set the variables */ DrawPsyched(2); /* Second stage */ if (!LoadWallArt()) { /* Get the wall shapes */ return FALSE; }/* map.tilemap is now used to hold actor numbers if the TI_ACTOR bit is set in the word tilemap*/ memset(WallHits,0,sizeof(WallHits)); /* Init the wall table */ Count = 1; do { WallHits[Count] = 1; /* Force the permanent sprites to load */ } while (++Count<S_VICTORY+1); SpawnThings(); /* Create all the characters in the game level */ return LoadSpriteArt(); /* Load in the sprite art */}/************************************ Load in a single wall shape************************************/static Boolean LoadWallShape(Word Index,Byte *DarkPtr){ Byte *WallPtr; Byte *Buffer; Word WallVal; Word j; Buffer = AllocSomeMem(0x4000); /* Get memory for wall */ if (!Buffer) { return FALSE; } WallVal = WallListPtr[Index+1]; /* Which resource is it? */ WallPtr = LoadAResource(WallVal&0x3fff); /* Load the shape */ if (!WallPtr) { FreeSomeMem(Buffer); return FALSE; } DLZSS(Buffer,WallPtr,0x4000); /* Decompress it */ if (WallVal & 0x8000) { /* Do I need to darken it? */ j = 0; do { Buffer[j] = DarkPtr[Buffer[j]]; /* Use a lookup table to darken it */ } while (++j<0x4000); } ArtData[Index] = Buffer; /* Save the pointer */ ReleaseAResource(WallVal&0x3fff); /* Purge the data */ return TRUE;}/************************************ Load in all the wall art************************************/Word LoadWallArt(void){ Word i; Word j; Word RetVal; Byte *DarkPtr; RetVal = FALSE; DarkPtr = LoadAResource(MyDarkData); /* Get my darken table */ i = 0; do { if (WallHits[i]) { j = i*2; if (!LoadWallShape(j,DarkPtr) || !LoadWallShape(j+1,DarkPtr) ) { goto Abort; } DrawPsyched(j+2); } } while (++i<29); i = 59; do { if (!LoadWallShape(i,DarkPtr)) { goto Abort; } DrawPsyched(i+2); } while (++i<64); RetVal = TRUE;Abort: ReleaseAResource(MyDarkData); return RetVal; /* No errors */}/*************************** Load in all the sprites***************************/Word LoadSpriteArt(void){ Word i; Word Length; Byte *MyPtr; Byte *MyNewPtr; i=1; do { if (WallHits[i]) { MyPtr = LoadAResource(i+(428-1)); /* Get the packed file */ if (!MyPtr) { return FALSE; } Length = MyPtr[0]; /* Get the length unpacked */ Length |= MyPtr[1]<<8; MyNewPtr = (Byte *)AllocSomeMem(Length); /* Get memory for the sprite */ if (!MyNewPtr) { ReleaseAResource(i+(428-1)); return FALSE; } DLZSS(MyNewPtr,&MyPtr[2],Length); /* Unpack it */ SpriteArray[i] = MyNewPtr; /* Save the pointer */ ReleaseAResource(i+(428-1)); /* Release the resource */ DrawPsyched(i+66); } } while (++i<S_LASTONE); DrawPsyched(66+S_LASTONE); return TRUE;}