From 3f59fc8b771625aca9c3aefe03cf1038d8461963 Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Sun, 7 Jul 2019 22:00:20 -0400 Subject: Wolfenstein 3-D! This is a port of Wolf4SDL, which is derived from the original id software source release. The port runs on top of the SDL plugin runtime and is loaded as an overlay. Licensing of the game code is not an issue, as discussed below (essentially, the Debian project treats Wolf4SDL as GPLv2, with an email from John Carmack backing it up): http://forums.rockbox.org/index.php?topic=52872 Included is a copy of MAME's Yamaha OPL sound chip emulator (fmopl_gpl.c). This file was not part of the original Wolf4SDL source (which includes a non-GPL'd version), but was rather rebased from from a later MAME source which had been relicensed to GPLv2. Change-Id: I64c2ba035e0be7e2f49252f40640641416613439 --- apps/plugins/sdl/progs/wolf3d/wl_act1.c | 859 ++++++++++++++++++++++++++++++++ 1 file changed, 859 insertions(+) create mode 100644 apps/plugins/sdl/progs/wolf3d/wl_act1.c (limited to 'apps/plugins/sdl/progs/wolf3d/wl_act1.c') 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;iareanumber] = 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<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<= 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<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<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<tiley<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<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; +} -- cgit v1.2.3