diff options
Diffstat (limited to 'apps/plugins/sdl/progs/wolf3d/wl_act1.c')
-rw-r--r-- | apps/plugins/sdl/progs/wolf3d/wl_act1.c | 859 |
1 files changed, 859 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/wolf3d/wl_act1.c b/apps/plugins/sdl/progs/wolf3d/wl_act1.c new file mode 100644 index 0000000000..e9553c97c5 --- /dev/null +++ b/apps/plugins/sdl/progs/wolf3d/wl_act1.c @@ -0,0 +1,859 @@ +// WL_ACT1.C + +#include "wl_def.h" +#pragma hdrstop + +/* +============================================================================= + + STATICS + +============================================================================= +*/ + + +statobj_t statobjlist[MAXSTATS]; +statobj_t *laststatobj; + + +struct +{ + short picnum; + wl_stat_t type; + uint32_t specialFlags; // they are ORed to the statobj_t flags +} statinfo[] = +{ + {SPR_STAT_0}, // puddle spr1v + {SPR_STAT_1,block}, // Green Barrel " + {SPR_STAT_2,block}, // Table/chairs " + {SPR_STAT_3,block,FL_FULLBRIGHT}, // Floor lamp " + {SPR_STAT_4,none,FL_FULLBRIGHT}, // Chandelier " + {SPR_STAT_5,block}, // Hanged man " + {SPR_STAT_6,bo_alpo}, // Bad food " + {SPR_STAT_7,block}, // Red pillar " + // + // NEW PAGE + // + {SPR_STAT_8,block}, // Tree spr2v + {SPR_STAT_9}, // Skeleton flat " + {SPR_STAT_10,block}, // Sink " (SOD:gibs) + {SPR_STAT_11,block}, // Potted plant " + {SPR_STAT_12,block}, // Urn " + {SPR_STAT_13,block}, // Bare table " + {SPR_STAT_14,none,FL_FULLBRIGHT}, // Ceiling light " + #ifndef SPEAR + {SPR_STAT_15}, // Kitchen stuff " + #else + {SPR_STAT_15,block}, // Gibs! + #endif + // + // NEW PAGE + // + {SPR_STAT_16,block}, // suit of armor spr3v + {SPR_STAT_17,block}, // Hanging cage " + {SPR_STAT_18,block}, // SkeletoninCage " + {SPR_STAT_19}, // Skeleton relax " + {SPR_STAT_20,bo_key1}, // Key 1 " + {SPR_STAT_21,bo_key2}, // Key 2 " + {SPR_STAT_22,block}, // stuff (SOD:gibs) + {SPR_STAT_23}, // stuff + // + // NEW PAGE + // + {SPR_STAT_24,bo_food}, // Good food spr4v + {SPR_STAT_25,bo_firstaid}, // First aid " + {SPR_STAT_26,bo_clip}, // Clip " + {SPR_STAT_27,bo_machinegun}, // Machine gun " + {SPR_STAT_28,bo_chaingun}, // Gatling gun " + {SPR_STAT_29,bo_cross}, // Cross " + {SPR_STAT_30,bo_chalice}, // Chalice " + {SPR_STAT_31,bo_bible}, // Bible " + // + // NEW PAGE + // + {SPR_STAT_32,bo_crown}, // crown spr5v + {SPR_STAT_33,bo_fullheal,FL_FULLBRIGHT},// one up " + {SPR_STAT_34,bo_gibs}, // gibs " + {SPR_STAT_35,block}, // barrel " + {SPR_STAT_36,block}, // well " + {SPR_STAT_37,block}, // Empty well " + {SPR_STAT_38,bo_gibs}, // Gibs 2 " + {SPR_STAT_39,block}, // flag " + // + // NEW PAGE + // + #ifndef SPEAR + {SPR_STAT_40,block}, // Call Apogee spr7v + #else + {SPR_STAT_40}, // Red light + #endif + // + // NEW PAGE + // + {SPR_STAT_41}, // junk " + {SPR_STAT_42}, // junk " + {SPR_STAT_43}, // junk " + #ifndef SPEAR + {SPR_STAT_44}, // pots " + #else + {SPR_STAT_44,block}, // Gibs! + #endif + {SPR_STAT_45,block}, // stove " (SOD:gibs) + {SPR_STAT_46,block}, // spears " (SOD:gibs) + {SPR_STAT_47}, // vines " + // + // NEW PAGE + // + #ifdef SPEAR + {SPR_STAT_48,block}, // marble pillar + {SPR_STAT_49,bo_25clip}, // bonus 25 clip + {SPR_STAT_50,block}, // truck + {SPR_STAT_51,bo_spear}, // SPEAR OF DESTINY! + #endif + + {SPR_STAT_26,bo_clip2}, // Clip " +#ifdef USE_DIR3DSPR + // These are just two examples showing the new way of using dir 3d sprites. + // You can find the allowed values in the objflag_t enum in wl_def.h. + {SPR_STAT_47,none,FL_DIR_VERT_MID}, + {SPR_STAT_47,block,FL_DIR_HORIZ_MID}, +#endif + {-1} // terminator +}; + +/* +=============== += += InitStaticList += +=============== +*/ + +void InitStaticList (void) +{ + laststatobj = &statobjlist[0]; +} + + + +/* +=============== += += SpawnStatic += +=============== +*/ + +void SpawnStatic (int tilex, int tiley, int type) +{ + laststatobj->shapenum = statinfo[type].picnum; + laststatobj->tilex = tilex; + laststatobj->tiley = tiley; + laststatobj->visspot = &spotvis[tilex][tiley]; + + switch (statinfo[type].type) + { + case block: + actorat[tilex][tiley] = (objtype *) 64; // consider it a blocking tile + case none: + laststatobj->flags = 0; + break; + + case bo_cross: + case bo_chalice: + case bo_bible: + case bo_crown: + case bo_fullheal: + if (!loadedgame) + gamestate.treasuretotal++; + + case bo_firstaid: + case bo_key1: + case bo_key2: + case bo_key3: + case bo_key4: + case bo_clip: + case bo_25clip: + case bo_machinegun: + case bo_chaingun: + case bo_food: + case bo_alpo: + case bo_gibs: + case bo_spear: + laststatobj->flags = FL_BONUS; + laststatobj->itemnumber = statinfo[type].type; + break; + } + + laststatobj->flags |= statinfo[type].specialFlags; + + laststatobj++; + + if (laststatobj == &statobjlist[MAXSTATS]) + Quit ("Too many static objects!\n"); +} + + +/* +=============== += += PlaceItemType += += Called during game play to drop actors' items. It finds the proper += item number based on the item type (bo_???). If there are no free item += spots, nothing is done. += +=============== +*/ + +void PlaceItemType (int itemtype, int tilex, int tiley) +{ + int type; + statobj_t *spot; + + // + // find the item number + // + for (type=0; ; type++) + { + if (statinfo[type].picnum == -1) // end of list + Quit ("PlaceItemType: couldn't find type!"); + if (statinfo[type].type == itemtype) + break; + } + + // + // find a spot in statobjlist to put it in + // + for (spot=&statobjlist[0]; ; spot++) + { + if (spot==laststatobj) + { + if (spot == &statobjlist[MAXSTATS]) + return; // no free spots + laststatobj++; // space at end + break; + } + + if (spot->shapenum == -1) // -1 is a free spot + break; + } + // + // place it + // + spot->shapenum = statinfo[type].picnum; + spot->tilex = tilex; + spot->tiley = tiley; + spot->visspot = &spotvis[tilex][tiley]; + spot->flags = FL_BONUS | statinfo[type].specialFlags; + spot->itemnumber = statinfo[type].type; +} + + + +/* +============================================================================= + + DOORS + +doorobjlist[] holds most of the information for the doors + +doorposition[] holds the amount the door is open, ranging from 0 to 0xffff + this is directly accessed by AsmRefresh during rendering + +The number of doors is limited to 64 because a spot in tilemap holds the + door number in the low 6 bits, with the high bit meaning a door center + and bit 6 meaning a door side tile + +Open doors conect two areas, so sounds will travel between them and sight + will be checked when the player is in a connected area. + +Areaconnect is incremented/decremented by each door. If >0 they connect + +Every time a door opens or closes the areabyplayer matrix gets recalculated. + An area is true if it connects with the player's current spor. + +============================================================================= +*/ + +#define DOORWIDTH 0x7800 +#define OPENTICS 300 + +doorobj_t doorobjlist[MAXDOORS],*lastdoorobj; +short doornum; + +word doorposition[MAXDOORS]; // leading edge of door 0=closed + // 0xffff = fully open + +byte areaconnect[NUMAREAS][NUMAREAS]; + +boolean areabyplayer[NUMAREAS]; + + +/* +============== += += ConnectAreas += += Scans outward from playerarea, marking all connected areas += +============== +*/ + +void RecursiveConnect (int areanumber) +{ + int i; + + for (i=0;i<NUMAREAS;i++) + { + if (areaconnect[areanumber][i] && !areabyplayer[i]) + { + areabyplayer[i] = true; + RecursiveConnect (i); + } + } +} + + +void ConnectAreas (void) +{ + memset (areabyplayer,0,sizeof(areabyplayer)); + areabyplayer[player->areanumber] = true; + RecursiveConnect (player->areanumber); +} + + +void InitAreas (void) +{ + memset (areabyplayer,0,sizeof(areabyplayer)); + if (player->areanumber < NUMAREAS) + areabyplayer[player->areanumber] = true; +} + + + +/* +=============== += += InitDoorList += +=============== +*/ + +void InitDoorList (void) +{ + memset (areabyplayer,0,sizeof(areabyplayer)); + memset (areaconnect,0,sizeof(areaconnect)); + + lastdoorobj = &doorobjlist[0]; + doornum = 0; +} + + +/* +=============== += += SpawnDoor += +=============== +*/ + +void SpawnDoor (int tilex, int tiley, boolean vertical, int lock) +{ + word *map; + + if (doornum==MAXDOORS) + Quit ("64+ doors on level!"); + + doorposition[doornum] = 0; // doors start out fully closed + lastdoorobj->tilex = tilex; + lastdoorobj->tiley = tiley; + lastdoorobj->vertical = vertical; + lastdoorobj->lock = lock; + lastdoorobj->action = dr_closed; + + actorat[tilex][tiley] = (objtype *)(uintptr_t)(doornum | 0x80); // consider it a solid wall + + // + // make the door tile a special tile, and mark the adjacent tiles + // for door sides + // + tilemap[tilex][tiley] = doornum | 0x80; + map = mapsegs[0] + (tiley<<mapshift) +tilex; + if (vertical) + { + *map = *(map-1); // set area number + tilemap[tilex][tiley-1] |= 0x40; + tilemap[tilex][tiley+1] |= 0x40; + } + else + { + *map = *(map-mapwidth); // set area number + tilemap[tilex-1][tiley] |= 0x40; + tilemap[tilex+1][tiley] |= 0x40; + } + + doornum++; + lastdoorobj++; +} + +//=========================================================================== + +/* +===================== += += OpenDoor += +===================== +*/ + +void OpenDoor (int door) +{ + if (doorobjlist[door].action == dr_open) + doorobjlist[door].ticcount = 0; // reset open time + else + doorobjlist[door].action = dr_opening; // start it opening +} + + +/* +===================== += += CloseDoor += +===================== +*/ + +void CloseDoor (int door) +{ + int tilex,tiley,area; + objtype *check; + + // + // don't close on anything solid + // + tilex = doorobjlist[door].tilex; + tiley = doorobjlist[door].tiley; + + if (actorat[tilex][tiley]) + return; + + if (player->tilex == tilex && player->tiley == tiley) + return; + + if (doorobjlist[door].vertical) + { + if ( player->tiley == tiley ) + { + if ( ((player->x+MINDIST) >>TILESHIFT) == tilex ) + return; + if ( ((player->x-MINDIST) >>TILESHIFT) == tilex ) + return; + } + check = actorat[tilex-1][tiley]; + if (ISPOINTER(check) && ((check->x+MINDIST) >> TILESHIFT) == tilex ) + return; + check = actorat[tilex+1][tiley]; + if (ISPOINTER(check) && ((check->x-MINDIST) >> TILESHIFT) == tilex ) + return; + } + else if (!doorobjlist[door].vertical) + { + if (player->tilex == tilex) + { + if ( ((player->y+MINDIST) >>TILESHIFT) == tiley ) + return; + if ( ((player->y-MINDIST) >>TILESHIFT) == tiley ) + return; + } + check = actorat[tilex][tiley-1]; + if (ISPOINTER(check) && ((check->y+MINDIST) >> TILESHIFT) == tiley ) + return; + check = actorat[tilex][tiley+1]; + if (ISPOINTER(check) && ((check->y-MINDIST) >> TILESHIFT) == tiley ) + return; + } + + + // + // play door sound if in a connected area + // + area = *(mapsegs[0] + (doorobjlist[door].tiley<<mapshift) + +doorobjlist[door].tilex)-AREATILE; + if (areabyplayer[area]) + { + PlaySoundLocTile(CLOSEDOORSND,doorobjlist[door].tilex,doorobjlist[door].tiley); // JAB + } + + doorobjlist[door].action = dr_closing; + // + // make the door space solid + // + actorat[tilex][tiley] = (objtype *)(uintptr_t)(door | 0x80); +} + + + +/* +===================== += += OperateDoor += += The player wants to change the door's direction += +===================== +*/ + +void OperateDoor (int door) +{ + int lock; + + lock = doorobjlist[door].lock; + if (lock >= dr_lock1 && lock <= dr_lock4) + { + if ( ! (gamestate.keys & (1 << (lock-dr_lock1) ) ) ) + { + SD_PlaySound (NOWAYSND); // locked + return; + } + } + + switch (doorobjlist[door].action) + { + case dr_closed: + case dr_closing: + OpenDoor (door); + break; + case dr_open: + case dr_opening: + CloseDoor (door); + break; + } +} + + +//=========================================================================== + +/* +=============== += += DoorOpen += += Close the door after three seconds += +=============== +*/ + +void DoorOpen (int door) +{ + if ( (doorobjlist[door].ticcount += (short) tics) >= OPENTICS) + CloseDoor (door); +} + + + +/* +=============== += += DoorOpening += +=============== +*/ + +void DoorOpening (int door) +{ + unsigned area1,area2; + word *map; + int32_t position; + + position = doorposition[door]; + if (!position) + { + // + // door is just starting to open, so connect the areas + // + map = mapsegs[0] + (doorobjlist[door].tiley<<mapshift) + +doorobjlist[door].tilex; + + if (doorobjlist[door].vertical) + { + area1 = *(map+1); + area2 = *(map-1); + } + else + { + area1 = *(map-mapwidth); + area2 = *(map+mapwidth); + } + area1 -= AREATILE; + area2 -= AREATILE; + + if (area1 < NUMAREAS && area2 < NUMAREAS) + { + areaconnect[area1][area2]++; + areaconnect[area2][area1]++; + + if (player->areanumber < NUMAREAS) + ConnectAreas (); + + if (areabyplayer[area1]) + PlaySoundLocTile(OPENDOORSND,doorobjlist[door].tilex,doorobjlist[door].tiley); // JAB + } + } + + // + // slide the door by an adaptive amount + // + position += tics<<10; + if (position >= 0xffff) + { + // + // door is all the way open + // + position = 0xffff; + doorobjlist[door].ticcount = 0; + doorobjlist[door].action = dr_open; + actorat[doorobjlist[door].tilex][doorobjlist[door].tiley] = 0; + } + + doorposition[door] = (word) position; +} + + +/* +=============== += += DoorClosing += +=============== +*/ + +void DoorClosing (int door) +{ + unsigned area1,area2; + word *map; + int32_t position; + int tilex,tiley; + + tilex = doorobjlist[door].tilex; + tiley = doorobjlist[door].tiley; + + if ( ((int)(uintptr_t)actorat[tilex][tiley] != (door | 0x80)) + || (player->tilex == tilex && player->tiley == tiley) ) + { // something got inside the door + OpenDoor (door); + return; + }; + + position = doorposition[door]; + + // + // slide the door by an adaptive amount + // + position -= tics<<10; + if (position <= 0) + { + // + // door is closed all the way, so disconnect the areas + // + position = 0; + + doorobjlist[door].action = dr_closed; + + map = mapsegs[0] + (doorobjlist[door].tiley<<mapshift) + doorobjlist[door].tilex; + + if (doorobjlist[door].vertical) + { + area1 = *(map+1); + area2 = *(map-1); + } + else + { + area1 = *(map-mapwidth); + area2 = *(map+mapwidth); + } + area1 -= AREATILE; + area2 -= AREATILE; + + if (area1 < NUMAREAS && area2 < NUMAREAS) + { + areaconnect[area1][area2]--; + areaconnect[area2][area1]--; + + if (player->areanumber < NUMAREAS) + ConnectAreas (); + } + } + + doorposition[door] = (word) position; +} + + + + +/* +===================== += += MoveDoors += += Called from PlayLoop += +===================== +*/ + +void MoveDoors (void) +{ + int door; + + if (gamestate.victoryflag) // don't move door during victory sequence + return; + + for (door = 0; door < doornum; door++) + { + switch (doorobjlist[door].action) + { + case dr_open: + DoorOpen (door); + break; + + case dr_opening: + DoorOpening(door); + break; + + case dr_closing: + DoorClosing(door); + break; + } + } +} + + +/* +============================================================================= + + PUSHABLE WALLS + +============================================================================= +*/ + +word pwallstate; +word pwallpos; // amount a pushable wall has been moved (0-63) +word pwallx,pwally; +byte pwalldir,pwalltile; +int dirs[4][2]={{0,-1},{1,0},{0,1},{-1,0}}; + +/* +=============== += += PushWall += +=============== +*/ + +void PushWall (int checkx, int checky, int dir) +{ + int oldtile, dx, dy; + + if (pwallstate) + return; + + oldtile = tilemap[checkx][checky]; + if (!oldtile) + return; + + dx = dirs[dir][0]; + dy = dirs[dir][1]; + + if (actorat[checkx+dx][checky+dy]) + { + SD_PlaySound (NOWAYSND); + return; + } + actorat[checkx+dx][checky+dy] = (objtype *)(uintptr_t) (tilemap[checkx+dx][checky+dy] = oldtile); + + gamestate.secretcount++; + pwallx = checkx; + pwally = checky; + pwalldir = dir; + pwallstate = 1; + pwallpos = 0; + pwalltile = tilemap[pwallx][pwally]; + tilemap[pwallx][pwally] = 64; + tilemap[pwallx+dx][pwally+dy] = 64; + *(mapsegs[1]+(pwally<<mapshift)+pwallx) = 0; // remove P tile info + *(mapsegs[0]+(pwally<<mapshift)+pwallx) = *(mapsegs[0]+(player->tiley<<mapshift)+player->tilex); // set correct floorcode (BrotherTank's fix) + + SD_PlaySound (PUSHWALLSND); +} + + + +/* +================= += += MovePWalls += +================= +*/ + +void MovePWalls (void) +{ + int oldblock,oldtile; + + if (!pwallstate) + return; + + oldblock = pwallstate/128; + + pwallstate += (word)tics; + + if (pwallstate/128 != oldblock) + { + // block crossed into a new block + oldtile = pwalltile; + + // + // the tile can now be walked into + // + tilemap[pwallx][pwally] = 0; + actorat[pwallx][pwally] = 0; + *(mapsegs[0]+(pwally<<mapshift)+pwallx) = player->areanumber+AREATILE; + + int dx=dirs[pwalldir][0], dy=dirs[pwalldir][1]; + // + // see if it should be pushed farther + // + if (pwallstate>=256) // only move two tiles fix + { + // + // the block has been pushed two tiles + // + pwallstate = 0; + tilemap[pwallx+dx][pwally+dy] = oldtile; + return; + } + else + { + int xl,yl,xh,yh; + xl = (player->x-PLAYERSIZE) >> TILESHIFT; + yl = (player->y-PLAYERSIZE) >> TILESHIFT; + xh = (player->x+PLAYERSIZE) >> TILESHIFT; + yh = (player->y+PLAYERSIZE) >> TILESHIFT; + + pwallx += dx; + pwally += dy; + + if (actorat[pwallx+dx][pwally+dy] + || xl<=pwallx+dx && pwallx+dx<=xh && yl<=pwally+dy && pwally+dy<=yh) + { + pwallstate = 0; + tilemap[pwallx][pwally] = oldtile; + return; + } + actorat[pwallx+dx][pwally+dy] = (objtype *)(uintptr_t) (tilemap[pwallx+dx][pwally+dy] = oldtile); + tilemap[pwallx+dx][pwally+dy] = 64; + } + } + + pwallpos = (pwallstate/2)&63; +} |