From: sparky4 Date: Wed, 5 Sep 2018 02:44:08 +0000 (-0500) Subject: going to start wolf3d core core (loop with input only) work soon. I was mostly brains... X-Git-Url: http://git.osdn.net/view?p=proj16%2F16.git;a=commitdiff_plain;h=9a536e7ada5a442984a3becef9e492b44eb5b101 going to start wolf3d core core (loop with input only) work soon. I was mostly brainstorming and planning today wwww i will work on it possibly day after tomarrow --- diff --git a/src/core/_demowl.c b/src/core/_demowl.c new file mode 100755 index 00000000..85958eff --- /dev/null +++ b/src/core/_demowl.c @@ -0,0 +1,170 @@ +/* +===================== += += DemoLoop += +===================== +*/ + +static char *ParmStrings[] = {"baby","easy","normal","hard",""}; + +void DemoLoop (void) +{ + static int LastDemo; + int i,level; + long nsize; + memptr nullblock; + +// +// check for launch from ted +// + if (tedlevel) + { + NoWait = true; + NewGame(1,0); + + for (i = 1;i < _argc;i++) + { + if ( (level = US_CheckParm(_argv[i],ParmStrings)) != -1) + { + gamestate.difficulty=level; + break; + } + } + +#ifndef SPEAR + gamestate.episode = tedlevelnum/10; + gamestate.mapon = tedlevelnum%10; +#else + gamestate.episode = 0; + gamestate.mapon = tedlevelnum; +#endif + GameLoop(); + Quit (NULL); + } + + +// +// main game cycle +// + + +// nsize = (long)40*1024; +// MM_GetPtr(&nullblock,nsize); + +#ifndef DEMOTEST + + #ifndef UPLOAD + + #ifndef GOODTIMES + #ifndef SPEAR + #ifndef JAPAN + if (!NoWait) + NonShareware(); + #endif + #else + + #ifndef GOODTIMES + #ifndef SPEARDEMO + CopyProtection(); + #endif + #endif + + #endif + #endif + #endif + + StartCPMusic(INTROSONG); + +#ifndef JAPAN + if (!NoWait) + PG13 (); +#endif + +#endif + + while (1) + { + while (!NoWait) + { +// +// title page +// + MM_SortMem (); +#ifndef DEMOTEST + +#ifdef SPEAR + CA_CacheGrChunk (TITLEPALETTE); + + CA_CacheGrChunk (TITLE1PIC); + VWB_DrawPic (0,0,TITLE1PIC); + UNCACHEGRCHUNK (TITLE1PIC); + + CA_CacheGrChunk (TITLE2PIC); + VWB_DrawPic (0,80,TITLE2PIC); + UNCACHEGRCHUNK (TITLE2PIC); + VW_UpdateScreen (); + VL_FadeIn(0,255,grsegs[TITLEPALETTE],30); + + UNCACHEGRCHUNK (TITLEPALETTE); +#else + CA_CacheScreen (TITLEPIC); + VW_UpdateScreen (); + VW_FadeIn(); +#endif + if (IN_UserInput(TickBase*15)) + break; + VW_FadeOut(); +// +// credits page +// + CA_CacheScreen (CREDITSPIC); + VW_UpdateScreen(); + VW_FadeIn (); + if (IN_UserInput(TickBase*10)) + break; + VW_FadeOut (); +// +// high scores +// + DrawHighScores (); + VW_UpdateScreen (); + VW_FadeIn (); + + if (IN_UserInput(TickBase*10)) + break; +#endif +// +// demo +// + + #ifndef SPEARDEMO + PlayDemo (LastDemo++%4); + #else + PlayDemo (0); + #endif + + if (playstate == ex_abort) + break; + StartCPMusic(INTROSONG); + } + + VW_FadeOut (); + +#ifndef SPEAR + if (Keyboard[sc_Tab] && MS_CheckParm("goobers")) +#else + if (Keyboard[sc_Tab] && MS_CheckParm("debugmode")) +#endif + RecordDemo (); + else + US_ControlPanel (0); + + if (startgame || loadedgame) + { + GameLoop (); + VW_FadeOut(); + StartCPMusic(INTROSONG); + } + } +} diff --git a/src/lib/hb/wl_act1.c b/src/core/wl_act1.c similarity index 100% rename from src/lib/hb/wl_act1.c rename to src/core/wl_act1.c diff --git a/src/lib/hb/wl_act2.c b/src/core/wl_act2.c similarity index 100% rename from src/lib/hb/wl_act2.c rename to src/core/wl_act2.c diff --git a/src/core/wl_agent.c b/src/core/wl_agent.c new file mode 100755 index 00000000..631478d0 --- /dev/null +++ b/src/core/wl_agent.c @@ -0,0 +1,1421 @@ +// WL_AGENT.C + +#include "WL_DEF.H" +#pragma hdrstop + + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +#define MAXMOUSETURN 10 + + +#define MOVESCALE 150l +#define BACKMOVESCALE 100l +#define ANGLESCALE 20 + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + + +// +// player state info +// +boolean running; +long thrustspeed; + +unsigned plux,pluy; // player coordinates scaled to unsigned + +int anglefrac; +int gotgatgun; // JR + +objtype *LastAttacker; + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +void T_Player (objtype *ob); +void T_Attack (objtype *ob); + +statetype s_player = {false,0,0,T_Player,NULL,NULL}; +statetype s_attack = {false,0,0,T_Attack,NULL,NULL}; + + +long playerxmove,playerymove; + +struct atkinf +{ + char tics,attack,frame; // attack is 1 for gun, 2 for knife +} attackinfo[4][14] = + +{ +{ {6,0,1},{6,2,2},{6,0,3},{6,-1,4} }, +{ {6,0,1},{6,1,2},{6,0,3},{6,-1,4} }, +{ {6,0,1},{6,1,2},{6,3,3},{6,-1,4} }, +{ {6,0,1},{6,1,2},{6,4,3},{6,-1,4} }, +}; + + +int strafeangle[9] = {0,90,180,270,45,135,225,315,0}; + +void DrawWeapon (void); +void GiveWeapon (int weapon); +void GiveAmmo (int ammo); + +//=========================================================================== + +//---------- + +void Attack (void); +void Use (void); +void Search (objtype *ob); +void SelectWeapon (void); +void SelectItem (void); + +//---------- + +boolean TryMove (objtype *ob); +void T_Player (objtype *ob); + +void ClipMove (objtype *ob, long xmove, long ymove); + +/* +============================================================================= + + CONTROL STUFF + +============================================================================= +*/ + +/* +====================== += += CheckWeaponChange += += Keys 1-4 change weapons += +====================== +*/ + +void CheckWeaponChange (void) +{ + int i,buttons; + + if (!gamestate.ammo) // must use knife with no ammo + return; + + for (i=wp_knife ; i<=gamestate.bestweapon ; i++) + if (buttonstate[bt_readyknife+i-wp_knife]) + { + gamestate.weapon = gamestate.chosenweapon = i; + DrawWeapon (); + return; + } +} + + +/* +======================= += += ControlMovement += += Takes controlx,controly, and buttonstate[bt_strafe] += += Changes the player's angle and position += += There is an angle hack because when going 70 fps, the roundoff becomes += significant += +======================= +*/ + +void ControlMovement (objtype *ob) +{ + long oldx,oldy; + int angle,maxxmove; + int angleunits; + long speed; + + thrustspeed = 0; + + oldx = player->x; + oldy = player->y; + +// +// side to side move +// + if (buttonstate[bt_strafe]) + { + // + // strafing + // + // + if (controlx > 0) + { + angle = ob->angle - ANGLES/4; + if (angle < 0) + angle += ANGLES; + Thrust (angle,controlx*MOVESCALE); // move to left + } + else if (controlx < 0) + { + angle = ob->angle + ANGLES/4; + if (angle >= ANGLES) + angle -= ANGLES; + Thrust (angle,-controlx*MOVESCALE); // move to right + } + } + else + { + // + // not strafing + // + anglefrac += controlx; + angleunits = anglefrac/ANGLESCALE; + anglefrac -= angleunits*ANGLESCALE; + ob->angle -= angleunits; + + if (ob->angle >= ANGLES) + ob->angle -= ANGLES; + if (ob->angle < 0) + ob->angle += ANGLES; + + } + +// +// forward/backwards move +// + if (controly < 0) + { + Thrust (ob->angle,-controly*MOVESCALE); // move forwards + } + else if (controly > 0) + { + angle = ob->angle + ANGLES/2; + if (angle >= ANGLES) + angle -= ANGLES; + Thrust (angle,controly*BACKMOVESCALE); // move backwards + } + + if (gamestate.victoryflag) // watching the BJ actor + return; + +// +// calculate total move +// + playerxmove = player->x - oldx; + playerymove = player->y - oldy; +} + +/* +============================================================================= + + STATUS WINDOW STUFF + +============================================================================= +*/ + + +/* +================== += += StatusDrawPic += +================== +*/ + +void StatusDrawPic (unsigned x, unsigned y, unsigned picnum) +{ + unsigned temp; + + temp = bufferofs; + bufferofs = 0; + + bufferofs = PAGE1START+(200-STATUSLINES)*SCREENWIDTH; + LatchDrawPic (x,y,picnum); + bufferofs = PAGE2START+(200-STATUSLINES)*SCREENWIDTH; + LatchDrawPic (x,y,picnum); + bufferofs = PAGE3START+(200-STATUSLINES)*SCREENWIDTH; + LatchDrawPic (x,y,picnum); + + bufferofs = temp; +} + + +/* +================== += += DrawFace += +================== +*/ + +void DrawFace (void) +{ + if (gamestate.health) + { + #ifdef SPEAR + if (godmode) + StatusDrawPic (17,4,GODMODEFACE1PIC+gamestate.faceframe); + else + #endif + StatusDrawPic (17,4,FACE1APIC+3*((100-gamestate.health)/16)+gamestate.faceframe); + } + else + { +#ifndef SPEAR + if (LastAttacker->obclass == needleobj) + StatusDrawPic (17,4,MUTANTBJPIC); + else +#endif + StatusDrawPic (17,4,FACE8APIC); + } +} + + +/* +=============== += += UpdateFace += += Calls draw face if time to change += +=============== +*/ + +#define FACETICS 70 + +int facecount; + +void UpdateFace (void) +{ + + if (SD_SoundPlaying() == GETGATLINGSND) + return; + + facecount += tics; + if (facecount > US_RndT()) + { + gamestate.faceframe = (US_RndT()>>6); + if (gamestate.faceframe==3) + gamestate.faceframe = 1; + + facecount = 0; + DrawFace (); + } +} + + + +/* +=============== += += LatchNumber += += right justifies and pads with blanks += +=============== +*/ + +void LatchNumber (int x, int y, int width, long number) +{ + unsigned length,c; + char str[20]; + + ltoa (number,str,10); + + length = strlen (str); + + while (length>=2; + + if (!godmode) + gamestate.health -= points; + + if (gamestate.health<=0) + { + gamestate.health = 0; + playstate = ex_died; + killerobj = attacker; + } + + StartDamageFlash (points); + + gotgatgun=0; + + DrawHealth (); + DrawFace (); + + // + // MAKE BJ'S EYES BUG IF MAJOR DAMAGE! + // + #ifdef SPEAR + if (points > 30 && gamestate.health!=0 && !godmode) + { + StatusDrawPic (17,4,BJOUCHPIC); + facecount = 0; + } + #endif + +} + + +/* +=============== += += HealSelf += +=============== +*/ + +void HealSelf (int points) +{ + gamestate.health += points; + if (gamestate.health>100) + gamestate.health = 100; + + DrawHealth (); + gotgatgun = 0; // JR + DrawFace (); +} + + +//=========================================================================== + + +/* +=============== += += DrawLevel += +=============== +*/ + +void DrawLevel (void) +{ +#ifdef SPEAR + if (gamestate.mapon == 20) + LatchNumber (2,16,2,18); + else +#endif + LatchNumber (2,16,2,gamestate.mapon+1); +} + +//=========================================================================== + + +/* +=============== += += DrawLives += +=============== +*/ + +void DrawLives (void) +{ + LatchNumber (14,16,1,gamestate.lives); +} + + +/* +=============== += += GiveExtraMan += +=============== +*/ + +void GiveExtraMan (void) +{ + if (gamestate.lives<9) + gamestate.lives++; + DrawLives (); + SD_PlaySound (BONUS1UPSND); +} + +//=========================================================================== + +/* +=============== += += DrawScore += +=============== +*/ + +void DrawScore (void) +{ + LatchNumber (6,16,6,gamestate.score); +} + +/* +=============== += += GivePoints += +=============== +*/ + +void GivePoints (long points) +{ + gamestate.score += points; + while (gamestate.score >= gamestate.nextextra) + { + gamestate.nextextra += EXTRAPOINTS; + GiveExtraMan (); + } + DrawScore (); +} + +//=========================================================================== + +/* +================== += += DrawWeapon += +================== +*/ + +void DrawWeapon (void) +{ + StatusDrawPic (32,8,KNIFEPIC+gamestate.weapon); +} + + +/* +================== += += DrawKeys += +================== +*/ + +void DrawKeys (void) +{ + if (gamestate.keys & 1) + StatusDrawPic (30,4,GOLDKEYPIC); + else + StatusDrawPic (30,4,NOKEYPIC); + + if (gamestate.keys & 2) + StatusDrawPic (30,20,SILVERKEYPIC); + else + StatusDrawPic (30,20,NOKEYPIC); +} + + + +/* +================== += += GiveWeapon += +================== +*/ + +void GiveWeapon (int weapon) +{ + GiveAmmo (6); + + if (gamestate.bestweapon 99) + gamestate.ammo = 99; + DrawAmmo (); +} + +//=========================================================================== + +/* +================== += += GiveKey += +================== +*/ + +void GiveKey (int key) +{ + gamestate.keys |= (1<itemnumber) + { + case bo_firstaid: + if (gamestate.health == 100) + return; + + SD_PlaySound (HEALTH2SND); + HealSelf (25); + break; + + case bo_key1: + case bo_key2: + case bo_key3: + case bo_key4: + GiveKey (check->itemnumber - bo_key1); + SD_PlaySound (GETKEYSND); + break; + + case bo_cross: + SD_PlaySound (BONUS1SND); + GivePoints (100); + gamestate.treasurecount++; + break; + case bo_chalice: + SD_PlaySound (BONUS2SND); + GivePoints (500); + gamestate.treasurecount++; + break; + case bo_bible: + SD_PlaySound (BONUS3SND); + GivePoints (1000); + gamestate.treasurecount++; + break; + case bo_crown: + SD_PlaySound (BONUS4SND); + GivePoints (5000); + gamestate.treasurecount++; + break; + + case bo_clip: + if (gamestate.ammo == 99) + return; + + SD_PlaySound (GETAMMOSND); + GiveAmmo (8); + break; + case bo_clip2: + if (gamestate.ammo == 99) + return; + + SD_PlaySound (GETAMMOSND); + GiveAmmo (4); + break; + +#ifdef SPEAR + case bo_25clip: + if (gamestate.ammo == 99) + return; + + SD_PlaySound (GETAMMOBOXSND); + GiveAmmo (25); + break; +#endif + + case bo_machinegun: + SD_PlaySound (GETMACHINESND); + GiveWeapon (wp_machinegun); + break; + case bo_chaingun: + SD_PlaySound (GETGATLINGSND); + GiveWeapon (wp_chaingun); + + StatusDrawPic (17,4,GOTGATLINGPIC); + facecount = 0; + gotgatgun = 1; + break; + + case bo_fullheal: + SD_PlaySound (BONUS1UPSND); + HealSelf (99); + GiveAmmo (25); + GiveExtraMan (); + gamestate.treasurecount++; + break; + + case bo_food: + if (gamestate.health == 100) + return; + + SD_PlaySound (HEALTH1SND); + HealSelf (10); + break; + + case bo_alpo: + if (gamestate.health == 100) + return; + + SD_PlaySound (HEALTH1SND); + HealSelf (4); + break; + + case bo_gibs: + if (gamestate.health >10) + return; + + SD_PlaySound (SLURPIESND); + HealSelf (1); + break; + + case bo_spear: + spearflag = true; + spearx = player->x; + speary = player->y; + spearangle = player->angle; + playstate = ex_completed; + } + + StartBonusFlash (); + check->shapenum = -1; // remove from list +} + + +/* +=================== += += TryMove += += returns true if move ok += debug: use pointers to optimize +=================== +*/ + +boolean TryMove (objtype *ob) +{ + int xl,yl,xh,yh,x,y; + objtype *check; + long deltax,deltay; + + xl = (ob->x-PLAYERSIZE) >>TILESHIFT; + yl = (ob->y-PLAYERSIZE) >>TILESHIFT; + + xh = (ob->x+PLAYERSIZE) >>TILESHIFT; + yh = (ob->y+PLAYERSIZE) >>TILESHIFT; + +// +// check for solid walls +// + for (y=yl;y<=yh;y++) + for (x=xl;x<=xh;x++) + { + check = actorat[x][y]; + if (check && check0) + yl--; + if (yh0) + xl--; + if (xh objlist + && (check->flags & FL_SHOOTABLE) ) + { + deltax = ob->x - check->x; + if (deltax < -MINACTORDIST || deltax > MINACTORDIST) + continue; + deltay = ob->y - check->y; + if (deltay < -MINACTORDIST || deltay > MINACTORDIST) + continue; + + return false; + } + } + + return true; +} + + +/* +=================== += += ClipMove += +=================== +*/ + +void ClipMove (objtype *ob, long xmove, long ymove) +{ + long basex,basey; + + basex = ob->x; + basey = ob->y; + + ob->x = basex+xmove; + ob->y = basey+ymove; + if (TryMove (ob)) + return; + + if (noclip && ob->x > 2*TILEGLOBAL && ob->y > 2*TILEGLOBAL && + ob->x < (((long)(mapwidth-1))<y < (((long)(mapheight-1))<x = basex+xmove; + ob->y = basey; + if (TryMove (ob)) + return; + + ob->x = basex; + ob->y = basey+ymove; + if (TryMove (ob)) + return; + + ob->x = basex; + ob->y = basey; +} + +//========================================================================== + +/* +=================== += += VictoryTile += +=================== +*/ + +void VictoryTile (void) +{ +#ifndef SPEAR + SpawnBJVictory (); +#endif + + gamestate.victoryflag = true; +} + + +/* +=================== += += Thrust += +=================== +*/ + +void Thrust (int angle, long speed) +{ + long xmove,ymove; + long slowmax; + unsigned offset; + + + // + // ZERO FUNNY COUNTER IF MOVED! + // + #ifdef SPEAR + if (speed) + funnyticount = 0; + #endif + + thrustspeed += speed; +// +// moving bounds speed +// + if (speed >= MINDIST*2) + speed = MINDIST*2-1; + + xmove = FixedByFrac(speed,costable[angle]); + ymove = -FixedByFrac(speed,sintable[angle]); + + ClipMove(player,xmove,ymove); + + player->tilex = player->x >> TILESHIFT; // scale to tile values + player->tiley = player->y >> TILESHIFT; + + offset = farmapylookup[player->tiley]+player->tilex; + player->areanumber = *(mapsegs[0] + offset) -AREATILE; + + if (*(mapsegs[1] + offset) == EXITTILE) + VictoryTile (); +} + + +/* +============================================================================= + + ACTIONS + +============================================================================= +*/ + + +/* +=============== += += Cmd_Fire += +=============== +*/ + +void Cmd_Fire (void) +{ + buttonheld[bt_attack] = true; + + gamestate.weaponframe = 0; + + player->state = &s_attack; + + gamestate.attackframe = 0; + gamestate.attackcount = + attackinfo[gamestate.weapon][gamestate.attackframe].tics; + gamestate.weaponframe = + attackinfo[gamestate.weapon][gamestate.attackframe].frame; +} + +//=========================================================================== + +/* +=============== += += Cmd_Use += +=============== +*/ + +void Cmd_Use (void) +{ + objtype *check; + int checkx,checky,doornum,dir; + boolean elevatorok; + + +// +// find which cardinal direction the player is facing +// + if (player->angle < ANGLES/8 || player->angle > 7*ANGLES/8) + { + checkx = player->tilex + 1; + checky = player->tiley; + dir = di_east; + elevatorok = true; + } + else if (player->angle < 3*ANGLES/8) + { + checkx = player->tilex; + checky = player->tiley-1; + dir = di_north; + elevatorok = false; + } + else if (player->angle < 5*ANGLES/8) + { + checkx = player->tilex - 1; + checky = player->tiley; + dir = di_west; + elevatorok = true; + } + else + { + checkx = player->tilex; + checky = player->tiley + 1; + dir = di_south; + elevatorok = false; + } + + doornum = tilemap[checkx][checky]; + if (*(mapsegs[1]+farmapylookup[checky]+checkx) == PUSHABLETILE) + { + // + // pushable wall + // + + PushWall (checkx,checky,dir); + return; + } + if (!buttonheld[bt_use] && doornum == ELEVATORTILE && elevatorok) + { + // + // use elevator + // + buttonheld[bt_use] = true; + + tilemap[checkx][checky]++; // flip switch + if (*(mapsegs[0]+farmapylookup[player->tiley]+player->tilex) == ALTELEVATORTILE) + playstate = ex_secretlevel; + else + playstate = ex_completed; + SD_PlaySound (LEVELDONESND); + SD_WaitSoundDone(); + } + else if (!buttonheld[bt_use] && doornum & 0x80) + { + buttonheld[bt_use] = true; + OperateDoor (doornum & ~0x80); + } + else + SD_PlaySound (DONOTHINGSND); + +} + +/* +============================================================================= + + PLAYER CONTROL + +============================================================================= +*/ + + + +/* +=============== += += SpawnPlayer += +=============== +*/ + +void SpawnPlayer (int tilex, int tiley, int dir) +{ + player->obclass = playerobj; + player->active = true; + player->tilex = tilex; + player->tiley = tiley; + player->areanumber = + *(mapsegs[0] + farmapylookup[player->tiley]+player->tilex); + player->x = ((long)tilex<y = ((long)tiley<state = &s_player; + player->angle = (1-dir)*90; + if (player->angle<0) + player->angle += ANGLES; + player->flags = FL_NEVERMARK; + Thrust (0,0); // set some variables + + InitAreas (); +} + + +//=========================================================================== + +/* +=============== += += T_KnifeAttack += += Update player hands, and try to do damage when the proper frame is reached += +=============== +*/ + +void KnifeAttack (objtype *ob) +{ + objtype *check,*closest; + long dist; + + SD_PlaySound (ATKKNIFESND); +// actually fire + dist = 0x7fffffff; + closest = NULL; + for (check=ob->next ; check ; check=check->next) + if ( (check->flags & FL_SHOOTABLE) + && (check->flags & FL_VISABLE) + && abs (check->viewx-centerx) < shootdelta + ) + { + if (check->transx < dist) + { + dist = check->transx; + closest = check; + } + } + + if (!closest || dist> 0x18000l) + { + // missed + + return; + } + +// hit something + DamageActor (closest,US_RndT() >> 4); +} + + + +void GunAttack (objtype *ob) +{ + objtype *check,*closest,*oldclosest; + int damage; + int dx,dy,dist; + long viewdist; + + switch (gamestate.weapon) + { + case wp_pistol: + SD_PlaySound (ATKPISTOLSND); + break; + case wp_machinegun: + SD_PlaySound (ATKMACHINEGUNSND); + break; + case wp_chaingun: + SD_PlaySound (ATKGATLINGSND); + break; + } + + madenoise = true; + +// +// find potential targets +// + viewdist = 0x7fffffffl; + closest = NULL; + + while (1) + { + oldclosest = closest; + + for (check=ob->next ; check ; check=check->next) + if ( (check->flags & FL_SHOOTABLE) + && (check->flags & FL_VISABLE) + && abs (check->viewx-centerx) < shootdelta + ) + { + if (check->transx < viewdist) + { + viewdist = check->transx; + closest = check; + } + } + + if (closest == oldclosest) + return; // no more targets, all missed + + // + // trace a line from player to enemey + // + if (CheckLine(closest)) + break; + + } + +// +// hit something +// + dx = abs(closest->tilex - player->tilex); + dy = abs(closest->tiley - player->tiley); + dist = dx>dy ? dx:dy; + + if (dist<2) + damage = US_RndT() / 4; + else if (dist<4) + damage = US_RndT() / 6; + else + { + if ( (US_RndT() / 12) < dist) // missed + return; + damage = US_RndT() / 6; + } + + DamageActor (closest,damage); +} + +//=========================================================================== + +/* +=============== += += VictorySpin += +=============== +*/ + +void VictorySpin (void) +{ + long desty; + + if (player->angle > 270) + { + player->angle -= tics * 3; + if (player->angle < 270) + player->angle = 270; + } + else if (player->angle < 270) + { + player->angle += tics * 3; + if (player->angle > 270) + player->angle = 270; + } + + desty = (((long)player->tiley-5)<y > desty) + { + player->y -= tics*4096; + if (player->y < desty) + player->y = desty; + } +} + + +//=========================================================================== + +/* +=============== += += T_Attack += +=============== +*/ + +void T_Attack (objtype *ob) +{ + struct atkinf *cur; + + UpdateFace (); + + if (gamestate.victoryflag) // watching the BJ actor + { + VictorySpin (); + return; + } + + if ( buttonstate[bt_use] && !buttonheld[bt_use] ) + buttonstate[bt_use] = false; + + if ( buttonstate[bt_attack] && !buttonheld[bt_attack]) + buttonstate[bt_attack] = false; + + ControlMovement (ob); + if (gamestate.victoryflag) // watching the BJ actor + return; + + plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned + pluy = player->y >> UNSIGNEDSHIFT; + player->tilex = player->x >> TILESHIFT; // scale to tile values + player->tiley = player->y >> TILESHIFT; + +// +// change frame and fire +// + gamestate.attackcount -= tics; + while (gamestate.attackcount <= 0) + { + cur = &attackinfo[gamestate.weapon][gamestate.attackframe]; + switch (cur->attack) + { + case -1: + ob->state = &s_player; + if (!gamestate.ammo) + { + gamestate.weapon = wp_knife; + DrawWeapon (); + } + else + { + if (gamestate.weapon != gamestate.chosenweapon) + { + gamestate.weapon = gamestate.chosenweapon; + DrawWeapon (); + } + }; + gamestate.attackframe = gamestate.weaponframe = 0; + return; + + case 4: + if (!gamestate.ammo) + break; + if (buttonstate[bt_attack]) + gamestate.attackframe -= 2; + case 1: + if (!gamestate.ammo) + { // can only happen with chain gun + gamestate.attackframe++; + break; + } + GunAttack (ob); + gamestate.ammo--; + DrawAmmo (); + break; + + case 2: + KnifeAttack (ob); + break; + + case 3: + if (gamestate.ammo && buttonstate[bt_attack]) + gamestate.attackframe -= 2; + break; + } + + gamestate.attackcount += cur->tics; + gamestate.attackframe++; + gamestate.weaponframe = + attackinfo[gamestate.weapon][gamestate.attackframe].frame; + } + +} + + + +//=========================================================================== + +/* +=============== += += T_Player += +=============== +*/ + +void T_Player (objtype *ob) +{ + if (gamestate.victoryflag) // watching the BJ actor + { + VictorySpin (); + return; + } + + UpdateFace (); + CheckWeaponChange (); + + if ( buttonstate[bt_use] ) + Cmd_Use (); + + if ( buttonstate[bt_attack] && !buttonheld[bt_attack]) + Cmd_Fire (); + + ControlMovement (ob); + if (gamestate.victoryflag) // watching the BJ actor + return; + + + plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned + pluy = player->y >> UNSIGNEDSHIFT; + player->tilex = player->x >> TILESHIFT; // scale to tile values + player->tiley = player->y >> TILESHIFT; +} + + diff --git a/src/lib/hb/wl_asm.asm b/src/core/wl_asm.asm similarity index 100% rename from src/lib/hb/wl_asm.asm rename to src/core/wl_asm.asm diff --git a/src/lib/hb/wl_debug.c b/src/core/wl_debug.c similarity index 100% rename from src/lib/hb/wl_debug.c rename to src/core/wl_debug.c diff --git a/src/lib/hb/wl_def.h b/src/core/wl_def.h similarity index 100% rename from src/lib/hb/wl_def.h rename to src/core/wl_def.h diff --git a/src/core/wl_dr_a.asm b/src/core/wl_dr_a.asm new file mode 100755 index 00000000..aec139a1 --- /dev/null +++ b/src/core/wl_dr_a.asm @@ -0,0 +1,795 @@ + IDEAL + MODEL MEDIUM,C + P286 + +SCREENSEG = 0a000h + +FINEANGLES = 3600 +DEG90 = 900 +DEG180 = 1800 +DEG270 = 2700 +DEG360 = 3600 + +OP_JLE = 07eh +OP_JGE = 07dh + +EXTRN finetangent:DWORD ; far array, starts at offset 0 + +EXTRN HitHorizWall:FAR +EXTRN HitVertWall:FAR +EXTRN HitHorizDoor:FAR +EXTRN HitVertDoor:FAR +EXTRN HitHorizPWall:FAR +EXTRN HitVertPWall:FAR + + +DATASEG + +EXTRN viewwidth:WORD + +EXTRN tilemap:BYTE +EXTRN spotvis:BYTE +EXTRN pixelangle:WORD + + +EXTRN midangle:WORD +EXTRN angle:WORD + +EXTRN focaltx:WORD +EXTRN focalty:WORD +EXTRN viewtx:WORD +EXTRN viewty:WORD +EXTRN viewx:DWORD +EXTRN viewy:DWORD + +EXTRN xpartialup:WORD +EXTRN ypartialup:WORD +EXTRN xpartialdown:WORD +EXTRN ypartialdown:WORD + +EXTRN tilehit:WORD +EXTRN pixx:WORD +EXTRN wallheight:WORD ; array of VIEWWIDTH entries + +EXTRN xtile:WORD +EXTRN ytile:WORD +EXTRN xtilestep:WORD +EXTRN ytilestep:WORD +EXTRN xintercept:DWORD +EXTRN yintercept:DWORD +EXTRN xstep:DWORD +EXTRN ystep:DWORD + +EXTRN doorposition:WORD ; table of door position values + + +EXTRN pwallpos:WORD ; amound a pushable wall has been moved + +CODESEG + +;------------------- +; +; xpartialbyystep +; +; multiplies long [ystep] (possibly negative), by word [xpartial] (in BX) +; +; returns dx:ax +; trashes bx,cx,di +; +;------------------- + +PROC xpartialbyystep NEAR +; +; setup +; + mov ax,[WORD ystep] + mov cx,[WORD ystep+2] + or cx,cx ; is ystep negatice? + jns @@multpos +; +; multiply negative cx:ax by bx +; + neg cx + neg ax + sbb cx,0 + + mul bx ; fraction*fraction + mov di,dx ; di is low word of result + mov ax,cx ; + mul bx ; units*fraction + add ax,di + adc dx,0 + + neg dx + neg ax + sbb dx,0 + ret +; +; multiply positive cx:ax by bx +; +EVEN +@@multpos: + mul bx ; fraction*fraction + mov di,dx ; di is low word of result + mov ax,cx ; + mul bx ; units*fraction + add ax,di + adc dx,0 + + ret + +ENDP + + + +;------------------- +; +; ypartialbyxstep +; +; multiplies long [xstep] (possibly negative), by word [ypartial] (in BP) +; +; returns dx:ax +; trashes cx,di,bp +; +;------------------- + +PROC ypartialbyxstep NEAR +; +; setup +; + mov ax,[WORD xstep] + mov cx,[WORD xstep+2] + or cx,cx ; is ystep negatice? + jns @@multpos +; +; multiply negative cx:ax by bx +; + neg cx + neg ax + sbb cx,0 + + mul bp ; fraction*fraction + mov di,dx ; di is low word of result + mov ax,cx ; + mul bp ; units*fraction + add ax,di + adc dx,0 + + neg dx + neg ax + sbb dx,0 + ret +; +; multiply positive cx:ax by bx +; +EVEN +@@multpos: + mul bp ; fraction*fraction + mov di,dx ; di is low word of result + mov ax,cx ; + mul bp ; units*fraction + add ax,di + adc dx,0 + ret + +ENDP + + +;============================ +; +; AsmRefresh +; +; +;============================ + +PROC AsmRefresh +PUBLIC AsmRefresh + + push si + push di + push bp + + mov [pixx],0 +;--------------------------------------------------------------------------- +; +; Setup to trace a ray through pixx view pixel +; +; CX : angle of the ray through pixx +; ES : points to segment of finetangent array for this block of code +; +; Upon entrance to initialize block +; +; BX : xpartial +; BP : ypartial +; +;--------------------------------------------------------------------------- + EVEN +pixxloop: + mov ax,SEG finetangent + mov es,ax + mov cx,[midangle] ; center of view area + mov bx,[pixx] + shl bx,1 + add cx,[pixelangle+bx] ; delta for this pixel + cmp cx,0 + jge not0 +;---------- +; +; -90 - -1 degree arc +; +;---------- + add cx,FINEANGLES ; -90 is the same as 270 + jmp entry360 + +not0: + cmp cx,DEG90 + jge not90 +;---------- +; +; 0-89 degree arc +; +;---------- +entry90: + mov [xtilestep],1 ; xtilestep = 1 + mov [ytilestep],-1 ; ytilestep = -1 + mov [BYTE cs:horizop],OP_JGE ; patch a jge in + mov [BYTE cs:vertop],OP_JLE ; patch a jle in + mov bx,DEG90-1 + sub bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + mov [WORD xstep],ax + mov [WORD xstep+2],dx ; xstep = finetangent[DEG90-1-angle] + mov bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + neg dx + neg ax + sbb dx,0 + mov [WORD ystep],ax + mov [WORD ystep+2],dx ; ystep = -finetangent[angle] + + mov bx,[xpartialup] ; xpartial = xpartialup + mov bp,[ypartialdown] ; ypartial = ypartialdown + jmp initvars + +not90: + cmp cx,DEG180 + jge not180 +;---------- +; +; 90-179 degree arc +; +;---------- + mov ax,-1 + mov [xtilestep],ax ; xtilestep = -1 + mov [ytilestep],ax ; ytilestep = -1 + mov [BYTE cs:horizop],OP_JLE ; patch a jle in + mov [BYTE cs:vertop],OP_JLE ; patch a jle in + + mov bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx-DEG90*4] + mov dx,[es:bx+2-DEG90*4] + neg dx + neg ax + sbb dx,0 + mov [WORD xstep],ax + mov [WORD xstep+2],dx ; xstep = -finetangent[angle-DEG90] + mov bx,DEG180-1 + sub bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + neg dx + neg ax + sbb dx,0 + mov [WORD ystep],ax + mov [WORD ystep+2],dx ; ystep = -finetangent[DEG180-1-angle] + + mov bx,[xpartialdown] ; xpartial = xpartialdown + mov bp,[ypartialdown] ; ypartial = ypartialdown + jmp initvars + +not180: + cmp cx,DEG270 + jge not270 +;---------- +; +; 180-269 degree arc +; +;---------- + mov [xtilestep],-1 ; xtilestep = -1 + mov [ytilestep],1 ; ytilestep = 1 + mov [BYTE cs:horizop],OP_JLE ; patch a jle in + mov [BYTE cs:vertop],OP_JGE ; patch a jge in + + mov bx,DEG270-1 + sub bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + neg dx + neg ax + sbb dx,0 + mov [WORD xstep],ax + mov [WORD xstep+2],dx ; xstep = -finetangent[DEG270-1-angle] + mov bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx-DEG180*4] + mov dx,[es:bx+2-DEG180*4] + mov [WORD ystep],ax + mov [WORD ystep+2],dx ; ystep = finetangent[angle-DEG180] + + mov bx,[xpartialdown] ; xpartial = xpartialdown + mov bp,[ypartialup] ; ypartial = ypartialup + jmp initvars + + +not270: + cmp cx,DEG360 + jge not360 +;---------- +; +; 270-359 degree arc +; +;---------- +entry360: + mov ax,1 + mov [xtilestep],ax ; xtilestep = 1 + mov [ytilestep],ax ; ytilestep = 1 + mov [BYTE cs:horizop],OP_JGE ; patch a jge in + mov [BYTE cs:vertop],OP_JGE ; patch a jge in + + mov bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx-DEG270*4] + mov dx,[es:bx+2-DEG270*4] + mov [WORD xstep],ax + mov [WORD xstep+2],dx ; xstep = finetangent[angle-DEG270] + mov bx,DEG360-1 + sub bx,cx + ;begin 8086 hack + ;shl bx,2 + shl bx,1 + shl bx,1 + ;end 8086 hack + mov ax,[es:bx] + mov dx,[es:bx+2] + mov [WORD ystep],ax + mov [WORD ystep+2],dx ; ystep = finetangent[DEG360-1-angle] + + mov bx,[xpartialup] ; xpartial = xpartialup + mov bp,[ypartialup] ; ypartial = ypartialup + jmp initvars + + +not360: +;---------- +; +; 360-449 degree arc +; +;---------- + sub cx,FINEANGLES ; -449 is the same as 89 + jmp entry90 + +;--------------------------------------------------------------------------- +; +; initialise variables for intersection testing +; +;--------------------------------------------------------------------------- +initvars: + call NEAR xpartialbyystep ; xpartial is in BX + add ax,[WORD viewy] + adc dx,[WORD viewy+2] + mov [WORD yintercept],ax + mov [WORD yintercept+2],dx + + mov si,[focaltx] + add si,[xtilestep] + mov [xtile],si ; xtile = focaltx+xtilestep + ;begin 8086 hack + ;shl si,6 + push cx + mov cl,6 + shl si,cl + pop cx + ;end 8086 hack + add si,dx ; xspot = (xtile<<6) + yinttile + + + call NEAR ypartialbyxstep ; ypartial is in BP + add ax,[WORD viewx] + adc dx,[WORD viewx+2] + mov [WORD xintercept],ax + mov cx,dx + + mov bx,[focalty] + add bx,[ytilestep] + mov bp,bx ; ytile = focalty+ytilestep + mov di,dx + ;begin 8086 hack + ;shl di,6 + push cx + mov cl,6 + shl di,cl + pop cx + ;end 8086 hack + add di,bx ; yspot = (xinttile<<6) + ytile + + mov bx,[xtile] + mov dx,[WORD yintercept+2] + mov ax,SCREENSEG + mov es,ax ; faster than mov es,[screenseg] + + +;--------------------------------------------------------------------------- +; +; trace along this angle until we hit a wall +; +; CORE LOOP! +; +; All variables are killed when a wall is hit +; +; AX : scratch +; BX : xtile +; CX : high word of xintercept +; DX : high word of yintercept +; SI : xspot (yinttile<<6)+xtile (index into tilemap and spotvis) +; DI : yspot (xinttile<<6)+ytile (index into tilemap and spotvis) +; BP : ytile +; ES : screenseg +; +;--------------------------------------------------------------------------- + +;----------- +; +; check intersections with vertical walls +; +;----------- + + EVEN +vertcheck: + cmp dx,bp +vertop: ; 0x7e = jle (ytilestep==-1) + jle horizentry ; 0x7d = jge (ytilestep==1) +vertentry: + test [BYTE tilemap+si],0ffh ; tilehit = *((byte *)tilemap+xspot); + jnz hitvert +passvert: + mov [BYTE spotvis+si],1 ; *((byte *)spotvis+xspot) = true; + add bx,[xtilestep] ; xtile+=xtilestep + mov ax,[WORD ystep] + add [WORD yintercept],ax ; yintercept += ystep + adc dx,[WORD ystep+2] + mov si,bx + ;begin 8086 hack + ;shl si,6 + push cx + mov cl,6 + shl si,cl + pop cx + ;end 8086 hack + add si,dx ; xspot = (xtile<<6)+yinttile + jmp vertcheck + + EVEN +hitvert: + mov al,[BYTE tilemap+si] ; tilehit = *((byte *)tilemap+xspot); + mov [BYTE tilehit],al + or al,al ; set flags + jns notvertdoor + jmp vertdoor +notvertdoor: + mov [WORD xintercept],0 + mov [WORD xintercept+2],bx + mov [xtile],bx + mov [WORD yintercept+2],dx + mov [ytile],dx + call FAR HitVertWall + jmp nextpix + + +;----------- +; +; check intersections with horizontal walls +; +;----------- + EVEN +horizcheck: + cmp cx,bx +horizop: ; 0x7e = jle (xtilestep==-1) + jle vertentry ; 0x7d = jge (xtilestep==1) +horizentry: + test [BYTE tilemap+di],0ffh ; tilehit = *((byte *)tilemap+yspot); + jnz hithoriz +passhoriz: + mov [BYTE spotvis+di],1 ; *((byte *)spotvis+yspot) = true; + add bp,[ytilestep] ; ytile+=ytilestep + mov ax,[WORD xstep] + add [WORD xintercept],ax ; xintercept += xstep + adc cx,[WORD xstep+2] + mov di,cx + ;begin 8086 hack + ;shl di,6 + push cx + mov cl,6 + shl di,cl + pop cx + ;end 8086 hack + add di,bp ; yspot = (xinttile<<6)+ytile + jmp horizcheck + + EVEN +hithoriz: + mov al,[BYTE tilemap+di] ; tilehit = *((byte *)tilemap+yspot); + mov [BYTE tilehit],al + or al,al ; set flags + js horizdoor + mov [WORD xintercept+2],cx + mov [xtile],cx + mov [WORD yintercept],0 + mov [WORD yintercept+2],bp + mov [ytile],bp + call FAR HitHorizWall + jmp nextpix + +;--------------------------------------------------------------------------- +; +; next pixel over +; +;--------------------------------------------------------------------------- + +nextpix: + mov ax,[pixx] + inc ax + mov [pixx],ax + cmp ax,[viewwidth] + jge done + jmp pixxloop +done: + pop bp + pop di + pop si + retf + +;=========================================================================== + +;============= +; +; hit a special horizontal wall, so find which coordinate a door would be +; intersected at, and check to see if the door is open past that point +; +;============= +horizdoor: + mov [xtile],bx ; save off live register variables + mov [WORD yintercept+2],dx + + test al,040h ; both high bits set == pushable wall + jnz horizpushwall + + mov bx,ax + and bx,7fh ; strip high bit + shl bx,1 ; index into word width door table + + mov ax,[WORD xstep] + mov dx,[WORD xstep+2] + sar dx,1 + rcr ax,1 ; half a step gets to door position + + add ax,[WORD xintercept] ; add half step to current intercept pos + adc dx,cx ; CX hold high word of xintercept + + cmp cx,dx ; is it still in the same tile? + je hithmid +; +; midpoint is outside tile, so it hit the side of the wall before a door +; +continuehoriz: + mov bx,[xtile] ; reload register variables + mov dx,[WORD yintercept+2] + jmp passhoriz ; continue tracing +; +; the trace hit the door plane at pixel position AX, see if the door is +; closed that much +; +hithmid: + cmp ax,[doorposition+bx] ; position of leading edge of door + jb continuehoriz +; +; draw the door +; + mov [WORD xintercept],ax ; save pixel intercept position + mov [WORD xintercept+2],cx + + mov [WORD yintercept],8000h ; intercept in middle of tile + mov [WORD yintercept+2],bp + + call FAR HitHorizDoor + jmp nextpix + +;============ +; +; hit a sliding horizontal wall +; +;============ + +horizpushwall: + mov ax,[WORD xstep+2] ; multiply xstep by pwallmove (0-63) + mul [pwallpos] + mov bx,ax + mov ax,[WORD xstep] + mul [pwallpos] + add dx,bx + + sar dx,1 ; then divide by 64 to accomplish a + rcr ax,1 ; fixed point multiplication + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + + add ax,[WORD xintercept] ; add partial step to current intercept + adc dx,cx ; CX hold high word of xintercept + + cmp cx,dx ; is it still in the same tile? + jne continuehoriz ; no, it hit the side + +; +; draw the pushable wall at the new height +; + mov [WORD xintercept],ax ; save pixel intercept position + mov [WORD xintercept+2],dx + + mov [WORD yintercept+2],bp + mov [WORD yintercept],0 + + call FAR HitHorizPWall + jmp nextpix + + + +;=========================================================================== + +;============= +; +; hit a special vertical wall, so find which coordinate a door would be +; intersected at, and check to see if the door is open past that point +; +;============= +vertdoor: + mov [xtile],bx ; save off live register variables + mov [WORD yintercept+2],dx + + test al,040h ; both high bits set == pushable wall + jnz vertpushwall + + mov bx,ax + and bx,7fh ; strip high bit + shl bx,1 ; index into word width doorposition + + mov ax,[WORD ystep] + mov dx,[WORD ystep+2] + sar dx,1 + rcr ax,1 ; half a step gets to door position + + add ax,[WORD yintercept] ; add half step to current intercept pos + adc dx,[WORD yintercept+2] + + cmp [WORD yintercept+2],dx ; is it still in the same tile? + je hitvmid +; +; midpoint is outside tile, so it hit the side of the wall before a door +; +continuevert: + mov bx,[xtile] ; reload register variables + mov dx,[WORD yintercept+2] + jmp passvert ; continue tracing +; +; the trace hit the door plane at pixel position AX, see if the door is +; closed that much +; +hitvmid: + cmp ax,[doorposition+bx] ; position of leading edge of door + jb continuevert +; +; draw the door +; + mov [WORD yintercept],ax ; save pixel intercept position + mov [WORD xintercept],8000h ; intercept in middle of tile + mov ax,[xtile] + mov [WORD xintercept+2],ax + + call FAR HitVertDoor + jmp nextpix + +;============ +; +; hit a sliding vertical wall +; +;============ + +vertpushwall: + mov ax,[WORD ystep+2] ; multiply ystep by pwallmove (0-63) + mul [pwallpos] + mov bx,ax + mov ax,[WORD ystep] + mul [pwallpos] + add dx,bx + + sar dx,1 ; then divide by 64 to accomplish a + rcr ax,1 ; fixed point multiplication + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + sar dx,1 + rcr ax,1 + + add ax,[WORD yintercept] ; add partial step to current intercept + adc dx,[WORD yintercept+2] + + cmp [WORD yintercept+2],dx ; is it still in the same tile? + jne continuevert ; no, it hit the side + +; +; draw the pushable wall at the new height +; + mov [WORD yintercept],ax ; save pixel intercept position + mov [WORD yintercept+2],dx + + mov bx,[xtile] + mov [WORD xintercept+2],bx + mov [WORD xintercept],0 + + call FAR HitVertPWall + jmp nextpix + + + +ENDP + + +END + + diff --git a/src/lib/hb/wl_draw.c b/src/core/wl_draw.c similarity index 100% rename from src/lib/hb/wl_draw.c rename to src/core/wl_draw.c diff --git a/src/lib/hb/wl_game.c b/src/core/wl_game.c similarity index 100% rename from src/lib/hb/wl_game.c rename to src/core/wl_game.c diff --git a/src/lib/hb/wl_inter.c b/src/core/wl_inter.c similarity index 100% rename from src/lib/hb/wl_inter.c rename to src/core/wl_inter.c diff --git a/src/lib/hb/wl_main.c b/src/core/wl_main.c similarity index 100% rename from src/lib/hb/wl_main.c rename to src/core/wl_main.c diff --git a/src/lib/hb/wl_menu.c b/src/core/wl_menu.c similarity index 100% rename from src/lib/hb/wl_menu.c rename to src/core/wl_menu.c diff --git a/src/lib/hb/wl_menu.h b/src/core/wl_menu.h similarity index 100% rename from src/lib/hb/wl_menu.h rename to src/core/wl_menu.h diff --git a/src/lib/hb/wl_play.c b/src/core/wl_play.c similarity index 100% rename from src/lib/hb/wl_play.c rename to src/core/wl_play.c diff --git a/src/lib/hb/wl_scale.c b/src/core/wl_scale.c similarity index 100% rename from src/lib/hb/wl_scale.c rename to src/core/wl_scale.c diff --git a/src/lib/hb/wl_state.c b/src/core/wl_state.c similarity index 100% rename from src/lib/hb/wl_state.c rename to src/core/wl_state.c diff --git a/src/core/wl_text.c b/src/core/wl_text.c new file mode 100755 index 00000000..1df86b83 --- /dev/null +++ b/src/core/wl_text.c @@ -0,0 +1,859 @@ +// WL_TEXT.C + +#include "WL_DEF.H" +#pragma hdrstop + +/* +============================================================================= + +TEXT FORMATTING COMMANDS +------------------------ +^C Change text color +^E[enter] End of layout (all pages) +^G,,[enter] Draw a graphic and push margins +^P[enter] start new page, must be the first chars in a layout +^L,[ENTER] Locate to a specific spot, x in pixels, y in lines + +============================================================================= +*/ + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +#define BACKCOLOR 0x11 + + +#define WORDLIMIT 80 +#define FONTHEIGHT 10 +#define TOPMARGIN 16 +#define BOTTOMMARGIN 32 +#define LEFTMARGIN 16 +#define RIGHTMARGIN 16 +#define PICMARGIN 8 +#define TEXTROWS ((200-TOPMARGIN-BOTTOMMARGIN)/FONTHEIGHT) +#define SPACEWIDTH 7 +#define SCREENPIXWIDTH 320 +#define SCREENMID (SCREENPIXWIDTH/2) + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + +int pagenum,numpages; + +unsigned leftmargin[TEXTROWS],rightmargin[TEXTROWS]; +char far *text; +unsigned rowon; + +int picx,picy,picnum,picdelay; +boolean layoutdone; + +//=========================================================================== + +#ifndef JAPAN +/* +===================== += += RipToEOL += +===================== +*/ + +void RipToEOL (void) +{ + while (*text++ != '\n') // scan to end of line + ; +} + + +/* +===================== += += ParseNumber += +===================== +*/ + +int ParseNumber (void) +{ + char ch; + char num[80],*numptr; + +// +// scan until a number is found +// + ch = *text; + while (ch < '0' || ch >'9') + ch = *++text; + +// +// copy the number out +// + numptr = num; + do + { + *numptr++ = ch; + ch = *++text; + } while (ch >= '0' && ch <= '9'); + *numptr = 0; + + return atoi (num); +} + + + +/* +===================== += += ParsePicCommand += += Call with text pointing just after a ^P += Upon exit text points to the start of next line += +===================== +*/ + +void ParsePicCommand (void) +{ + picy=ParseNumber(); + picx=ParseNumber(); + picnum=ParseNumber(); + RipToEOL (); +} + + +void ParseTimedCommand (void) +{ + picy=ParseNumber(); + picx=ParseNumber(); + picnum=ParseNumber(); + picdelay=ParseNumber(); + RipToEOL (); +} + + +/* +===================== += += TimedPicCommand += += Call with text pointing just after a ^P += Upon exit text points to the start of next line += +===================== +*/ + +void TimedPicCommand (void) +{ + ParseTimedCommand (); + +// +// update the screen, and wait for time delay +// + VW_UpdateScreen (); + +// +// wait for time +// + TimeCount = 0; + while (TimeCount < picdelay) + ; + +// +// draw pic +// + VWB_DrawPic (picx&~7,picy,picnum); +} + + +/* +===================== += += HandleCommand += +===================== +*/ + +void HandleCommand (void) +{ + int i,margin,top,bottom; + int picwidth,picheight,picmid; + + switch (toupper(*++text)) + { + case 'B': + picy=ParseNumber(); + picx=ParseNumber(); + picwidth=ParseNumber(); + picheight=ParseNumber(); + VWB_Bar(picx,picy,picwidth,picheight,BACKCOLOR); + RipToEOL(); + break; + case ';': // comment + RipToEOL(); + break; + case 'P': // ^P is start of next page, ^E is end of file + case 'E': + layoutdone = true; + text--; // back up to the '^' + break; + + case 'C': // ^c changes text color + i = toupper(*++text); + if (i>='0' && i<='9') + fontcolor = i-'0'; + else if (i>='A' && i<='F') + fontcolor = i-'A'+10; + + fontcolor *= 16; + i = toupper(*++text); + if (i>='0' && i<='9') + fontcolor += i-'0'; + else if (i>='A' && i<='F') + fontcolor += i-'A'+10; + text++; + break; + + case '>': + px = 160; + text++; + break; + + case 'L': + py=ParseNumber(); + rowon = (py-TOPMARGIN)/FONTHEIGHT; + py = TOPMARGIN+rowon*FONTHEIGHT; + px=ParseNumber(); + while (*text++ != '\n') // scan to end of line + ; + break; + + case 'T': // ^Tyyy,xxx,ppp,ttt waits ttt tics, then draws pic + TimedPicCommand (); + break; + + case 'G': // ^Gyyy,xxx,ppp draws graphic + ParsePicCommand (); + VWB_DrawPic (picx&~7,picy,picnum); + picwidth = pictable[picnum-STARTPICS].width; + picheight = pictable[picnum-STARTPICS].height; + // + // adjust margins + // + picmid = picx + picwidth/2; + if (picmid > SCREENMID) + margin = picx-PICMARGIN; // new right margin + else + margin = picx+picwidth+PICMARGIN; // new left margin + + top = (picy-TOPMARGIN)/FONTHEIGHT; + if (top<0) + top = 0; + bottom = (picy+picheight-TOPMARGIN)/FONTHEIGHT; + if (bottom>=TEXTROWS) + bottom = TEXTROWS-1; + + for (i=top;i<=bottom;i++) + if (picmid > SCREENMID) + rightmargin[i] = margin; + else + leftmargin[i] = margin; + + // + // adjust this line if needed + // + if (px < leftmargin[rowon]) + px = leftmargin[rowon]; + break; + } +} + + +/* +===================== += += NewLine += +===================== +*/ + +void NewLine (void) +{ + char ch; + + if (++rowon == TEXTROWS) + { + // + // overflowed the page, so skip until next page break + // + layoutdone = true; + do + { + if (*text == '^') + { + ch = toupper(*(text+1)); + if (ch == 'E' || ch == 'P') + { + layoutdone = true; + return; + } + } + text++; + + } while (1); + + } + px = leftmargin[rowon]; + py+= FONTHEIGHT; +} + + + +/* +===================== += += HandleCtrls += +===================== +*/ + +void HandleCtrls (void) +{ + char ch; + + ch = *text++; // get the character and advance + + if (ch == '\n') + { + NewLine (); + return; + } + +} + + +/* +===================== += += HandleWord += +===================== +*/ + +void HandleWord (void) +{ + char word[WORDLIMIT]; + int i,wordindex; + unsigned wwidth,wheight,newpos; + + + // + // copy the next word into [word] + // + word[0] = *text++; + wordindex = 1; + while (*text>32) + { + word[wordindex] = *text++; + if (++wordindex == WORDLIMIT) + Quit ("PageLayout: Word limit exceeded"); + } + word[wordindex] = 0; // stick a null at end for C + + // + // see if it fits on this line + // + VW_MeasurePropString (word,&wwidth,&wheight); + + while (px+wwidth > rightmargin[rowon]) + { + NewLine (); + if (layoutdone) + return; // overflowed page + } + + // + // print it + // + newpos = px+wwidth; + VWB_DrawPropString (word); + px = newpos; + + // + // suck up any extra spaces + // + while (*text == ' ') + { + px += SPACEWIDTH; + text++; + } +} + +/* +===================== += += PageLayout += += Clears the screen, draws the pics on the page, and word wraps the text. += Returns a pointer to the terminating command += +===================== +*/ + +void PageLayout (boolean shownumber) +{ + int i,oldfontcolor; + char ch; + + oldfontcolor = fontcolor; + + fontcolor = 0; + +// +// clear the screen +// + VWB_Bar (0,0,320,200,BACKCOLOR); + VWB_DrawPic (0,0,H_TOPWINDOWPIC); + VWB_DrawPic (0,8,H_LEFTWINDOWPIC); + VWB_DrawPic (312,8,H_RIGHTWINDOWPIC); + VWB_DrawPic (8,176,H_BOTTOMINFOPIC); + + + for (i=0;i1) + { + #ifndef JAPAN + BackPage (); + BackPage (); + #else + pagenum--; + #endif + newpage = true; + } + break; + + case sc_Enter: + case sc_DownArrow: + case sc_PgDn: + case sc_RightArrow: // the text allready points at next page + if (pagenumshapenum = statinfo[type].picnum; + laststatobj->tilex = tilex; + laststatobj->tiley = tiley; + laststatobj->visspot = &spotvis[tilex][tiley]; + + switch (statinfo[type].type) + { + case block: + (unsigned)actorat[tilex][tiley] = 1; // consider it a blocking tile + case dressing: + 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++; + + 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; + 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; +int doornum; + +unsigned doorposition[MAXDOORS]; // leading edge of door 0=closed + // 0xffff = fully open + +byte far 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)); + areabyplayer[player->areanumber] = true; +} + + + +/* +=============== += += InitDoorList += +=============== +*/ + +void InitDoorList (void) +{ + memset (areabyplayer,0,sizeof(areabyplayer)); + _fmemset (areaconnect,0,sizeof(areaconnect)); + + lastdoorobj = &doorobjlist[0]; + doornum = 0; +} + + +/* +=============== += += SpawnDoor += +=============== +*/ + +void SpawnDoor (int tilex, int tiley, boolean vertical, int lock) +{ + int areanumber; + unsigned far *map; + + if (doornum==64) + 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; + + (unsigned)actorat[tilex][tiley] = 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] + farmapylookup[tiley]+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 (check && ((check->x+MINDIST) >> TILESHIFT) == tilex ) + return; + check = actorat[tilex+1][tiley]; + if (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 (check && ((check->y+MINDIST) >> TILESHIFT) == tiley ) + return; + check = actorat[tilex][tiley+1]; + if (check && ((check->y-MINDIST) >> TILESHIFT) == tiley ) + return; + } + + +// +// play door sound if in a connected area +// + area = *(mapsegs[0] + farmapylookup[doorobjlist[door].tiley] + +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 +// + (unsigned)actorat[tilex][tiley] + = 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 += tics) >= OPENTICS) + CloseDoor (door); +} + + + +/* +=============== += += DoorOpening += +=============== +*/ + +void DoorOpening (int door) +{ + int area1,area2; + unsigned far *map; + long position; + + position = doorposition[door]; + if (!position) + { + // + // door is just starting to open, so connect the areas + // + map = mapsegs[0] + farmapylookup[doorobjlist[door].tiley] + +doorobjlist[door].tilex; + + if (doorobjlist[door].vertical) + { + area1 = *(map+1); + area2 = *(map-1); + } + else + { + area1 = *(map-mapwidth); + area2 = *(map+mapwidth); + } + area1 -= AREATILE; + area2 -= AREATILE; + areaconnect[area1][area2]++; + areaconnect[area2][area1]++; + 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] = position; +} + + +/* +=============== += += DoorClosing += +=============== +*/ + +void DoorClosing (int door) +{ + int area1,area2,move; + unsigned far *map; + long position; + int tilex,tiley; + + tilex = doorobjlist[door].tilex; + tiley = doorobjlist[door].tiley; + + if ( ((unsigned)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] + farmapylookup[doorobjlist[door].tiley] + +doorobjlist[door].tilex; + + if (doorobjlist[door].vertical) + { + area1 = *(map+1); + area2 = *(map-1); + } + else + { + area1 = *(map-mapwidth); + area2 = *(map+mapwidth); + } + area1 -= AREATILE; + area2 -= AREATILE; + areaconnect[area1][area2]--; + areaconnect[area2][area1]--; + + ConnectAreas (); + } + + doorposition[door] = 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 + +============================================================================= +*/ + +unsigned pwallstate; +unsigned pwallpos; // amount a pushable wall has been moved (0-63) +unsigned pwallx,pwally; +int pwalldir; + +/* +=============== += += PushWall += +=============== +*/ + +void PushWall (int checkx, int checky, int dir) +{ + int oldtile; + + if (pwallstate) + return; + + + oldtile = tilemap[checkx][checky]; + if (!oldtile) + return; + + switch (dir) + { + case di_north: + if (actorat[checkx][checky-1]) + { + SD_PlaySound (NOWAYSND); + return; + } + (unsigned)actorat[checkx][checky-1] = + tilemap[checkx][checky-1] = oldtile; + break; + + case di_east: + if (actorat[checkx+1][checky]) + { + SD_PlaySound (NOWAYSND); + return; + } + (unsigned)actorat[checkx+1][checky] = + tilemap[checkx+1][checky] = oldtile; + break; + + case di_south: + if (actorat[checkx][checky+1]) + { + SD_PlaySound (NOWAYSND); + return; + } + (unsigned)actorat[checkx][checky+1] = + tilemap[checkx][checky+1] = oldtile; + break; + + case di_west: + if (actorat[checkx-1][checky]) + { + SD_PlaySound (NOWAYSND); + return; + } + (unsigned)actorat[checkx-1][checky] = + tilemap[checkx-1][checky] = oldtile; + break; + } + + gamestate.secretcount++; + pwallx = checkx; + pwally = checky; + pwalldir = dir; + pwallstate = 1; + pwallpos = 0; + tilemap[pwallx][pwally] |= 0xc0; + *(mapsegs[1]+farmapylookup[pwally]+pwallx) = 0; // remove P tile info + + SD_PlaySound (PUSHWALLSND); +} + + + +/* +================= += += MovePWalls += +================= +*/ + +void MovePWalls (void) +{ + int oldblock,oldtile; + + if (!pwallstate) + return; + + oldblock = pwallstate/128; + + pwallstate += tics; + + if (pwallstate/128 != oldblock) + { + // block crossed into a new block + oldtile = tilemap[pwallx][pwally] & 63; + + // + // the tile can now be walked into + // + tilemap[pwallx][pwally] = 0; + (unsigned)actorat[pwallx][pwally] = 0; + *(mapsegs[0]+farmapylookup[pwally]+pwallx) = player->areanumber+AREATILE; + + // + // see if it should be pushed farther + // + if (pwallstate>256) + { + // + // the block has been pushed two tiles + // + pwallstate = 0; + return; + } + else + { + switch (pwalldir) + { + case di_north: + pwally--; + if (actorat[pwallx][pwally-1]) + { + pwallstate = 0; + return; + } + (unsigned)actorat[pwallx][pwally-1] = + tilemap[pwallx][pwally-1] = oldtile; + break; + + case di_east: + pwallx++; + if (actorat[pwallx+1][pwally]) + { + pwallstate = 0; + return; + } + (unsigned)actorat[pwallx+1][pwally] = + tilemap[pwallx+1][pwally] = oldtile; + break; + + case di_south: + pwally++; + if (actorat[pwallx][pwally+1]) + { + pwallstate = 0; + return; + } + (unsigned)actorat[pwallx][pwally+1] = + tilemap[pwallx][pwally+1] = oldtile; + break; + + case di_west: + pwallx--; + if (actorat[pwallx-1][pwally]) + { + pwallstate = 0; + return; + } + (unsigned)actorat[pwallx-1][pwally] = + tilemap[pwallx-1][pwally] = oldtile; + break; + } + + tilemap[pwallx][pwally] = oldtile | 0xc0; + } + } + + + pwallpos = (pwallstate/2)&63; + +} + diff --git a/src/lib/hb/act/wl_act2.c b/src/lib/hb/act/wl_act2.c new file mode 100755 index 00000000..d9d99a0b --- /dev/null +++ b/src/lib/hb/act/wl_act2.c @@ -0,0 +1,3872 @@ +// WL_ACT2.C + +#include "WL_DEF.H" +#pragma hdrstop + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +#define PROJECTILESIZE 0xc000l + +#define BJRUNSPEED 2048 +#define BJJUMPSPEED 680 + + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +dirtype dirtable[9] = {northwest,north,northeast,west,nodir,east, + southwest,south,southeast}; + +int starthitpoints[4][NUMENEMIES] = + // + // BABY MODE + // + { + {25, // guards + 50, // officer + 100, // SS + 1, // dogs + 850, // Hans + 850, // Schabbs + 200, // fake hitler + 800, // mecha hitler + 45, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 850, // Gretel + 850, // Gift + 850, // Fat + 5, // en_spectre, + 1450, // en_angel, + 850, // en_trans, + 1050, // en_uber, + 950, // en_will, + 1250 // en_death + }, + // + // DON'T HURT ME MODE + // + {25, // guards + 50, // officer + 100, // SS + 1, // dogs + 950, // Hans + 950, // Schabbs + 300, // fake hitler + 950, // mecha hitler + 55, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 950, // Gretel + 950, // Gift + 950, // Fat + 10, // en_spectre, + 1550, // en_angel, + 950, // en_trans, + 1150, // en_uber, + 1050, // en_will, + 1350 // en_death + }, + // + // BRING 'EM ON MODE + // + {25, // guards + 50, // officer + 100, // SS + 1, // dogs + + 1050, // Hans + 1550, // Schabbs + 400, // fake hitler + 1050, // mecha hitler + + 55, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 1050, // Gretel + 1050, // Gift + 1050, // Fat + 15, // en_spectre, + 1650, // en_angel, + 1050, // en_trans, + 1250, // en_uber, + 1150, // en_will, + 1450 // en_death + }, + // + // DEATH INCARNATE MODE + // + {25, // guards + 50, // officer + 100, // SS + 1, // dogs + + 1200, // Hans + 2400, // Schabbs + 500, // fake hitler + 1200, // mecha hitler + + 65, // mutants + 25, // ghosts + 25, // ghosts + 25, // ghosts + 25, // ghosts + + 1200, // Gretel + 1200, // Gift + 1200, // Fat + 25, // en_spectre, + 2000, // en_angel, + 1200, // en_trans, + 1400, // en_uber, + 1300, // en_will, + 1600 // en_death + }} + ; + +void A_StartDeathCam (objtype *ob); + + +void T_Path (objtype *ob); +void T_Shoot (objtype *ob); +void T_Bite (objtype *ob); +void T_DogChase (objtype *ob); +void T_Chase (objtype *ob); +void T_Projectile (objtype *ob); +void T_Stand (objtype *ob); + +void A_DeathScream (objtype *ob); + +extern statetype s_rocket; +extern statetype s_smoke1; +extern statetype s_smoke2; +extern statetype s_smoke3; +extern statetype s_smoke4; +extern statetype s_boom2; +extern statetype s_boom3; + +void A_Smoke (objtype *ob); + +statetype s_rocket = {true,SPR_ROCKET_1,3,T_Projectile,A_Smoke,&s_rocket}; +statetype s_smoke1 = {false,SPR_SMOKE_1,3,NULL,NULL,&s_smoke2}; +statetype s_smoke2 = {false,SPR_SMOKE_2,3,NULL,NULL,&s_smoke3}; +statetype s_smoke3 = {false,SPR_SMOKE_3,3,NULL,NULL,&s_smoke4}; +statetype s_smoke4 = {false,SPR_SMOKE_4,3,NULL,NULL,NULL}; + +statetype s_boom1 = {false,SPR_BOOM_1,6,NULL,NULL,&s_boom2}; +statetype s_boom2 = {false,SPR_BOOM_2,6,NULL,NULL,&s_boom3}; +statetype s_boom3 = {false,SPR_BOOM_3,6,NULL,NULL,NULL}; + +#ifdef SPEAR + +extern statetype s_hrocket; +extern statetype s_hsmoke1; +extern statetype s_hsmoke2; +extern statetype s_hsmoke3; +extern statetype s_hsmoke4; +extern statetype s_hboom2; +extern statetype s_hboom3; + +void A_Smoke (objtype *ob); + +statetype s_hrocket = {true,SPR_HROCKET_1,3,T_Projectile,A_Smoke,&s_hrocket}; +statetype s_hsmoke1 = {false,SPR_HSMOKE_1,3,NULL,NULL,&s_hsmoke2}; +statetype s_hsmoke2 = {false,SPR_HSMOKE_2,3,NULL,NULL,&s_hsmoke3}; +statetype s_hsmoke3 = {false,SPR_HSMOKE_3,3,NULL,NULL,&s_hsmoke4}; +statetype s_hsmoke4 = {false,SPR_HSMOKE_4,3,NULL,NULL,NULL}; + +statetype s_hboom1 = {false,SPR_HBOOM_1,6,NULL,NULL,&s_hboom2}; +statetype s_hboom2 = {false,SPR_HBOOM_2,6,NULL,NULL,&s_hboom3}; +statetype s_hboom3 = {false,SPR_HBOOM_3,6,NULL,NULL,NULL}; + +#endif + +void T_Schabb (objtype *ob); +void T_SchabbThrow (objtype *ob); +void T_Fake (objtype *ob); +void T_FakeFire (objtype *ob); +void T_Ghosts (objtype *ob); + +void A_Slurpie (objtype *ob); +void A_HitlerMorph (objtype *ob); +void A_MechaSound (objtype *ob); + +/* +================= += += A_Smoke += +================= +*/ + +void A_Smoke (objtype *ob) +{ + GetNewActor (); +#ifdef SPEAR + if (ob->obclass == hrocketobj) + new->state = &s_hsmoke1; + else +#endif + new->state = &s_smoke1; + new->ticcount = 6; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->obclass = inertobj; + new->active = true; + + new->flags = FL_NEVERMARK; +} + + +/* +=================== += += ProjectileTryMove += += returns true if move ok +=================== +*/ + +#define PROJSIZE 0x2000 + +boolean ProjectileTryMove (objtype *ob) +{ + int xl,yl,xh,yh,x,y; + objtype *check; + long deltax,deltay; + + xl = (ob->x-PROJSIZE) >>TILESHIFT; + yl = (ob->y-PROJSIZE) >>TILESHIFT; + + xh = (ob->x+PROJSIZE) >>TILESHIFT; + yh = (ob->y+PROJSIZE) >>TILESHIFT; + +// +// check for solid walls +// + for (y=yl;y<=yh;y++) + for (x=xl;x<=xh;x++) + { + check = actorat[x][y]; + if (check && checkspeed*tics; + + deltax = FixedByFrac(speed,costable[ob->angle]); + deltay = -FixedByFrac(speed,sintable[ob->angle]); + + if (deltax>0x10000l) + deltax = 0x10000l; + if (deltay>0x10000l) + deltay = 0x10000l; + + ob->x += deltax; + ob->y += deltay; + + deltax = LABS(ob->x - player->x); + deltay = LABS(ob->y - player->y); + + if (!ProjectileTryMove (ob)) + { + if (ob->obclass == rocketobj) + { + PlaySoundLocActor(MISSILEHITSND,ob); + ob->state = &s_boom1; + } +#ifdef SPEAR + else if (ob->obclass == hrocketobj) + { + PlaySoundLocActor(MISSILEHITSND,ob); + ob->state = &s_hboom1; + } +#endif + else + ob->state = NULL; // mark for removal + + return; + } + + if (deltax < PROJECTILESIZE && deltay < PROJECTILESIZE) + { // hit the player + switch (ob->obclass) + { + case needleobj: + damage = (US_RndT() >>3) + 20; + break; + case rocketobj: + case hrocketobj: + case sparkobj: + damage = (US_RndT() >>3) + 30; + break; + case fireobj: + damage = (US_RndT() >>3); + break; + } + + TakeDamage (damage,ob); + ob->state = NULL; // mark for removal + return; + } + + ob->tilex = ob->x >> TILESHIFT; + ob->tiley = ob->y >> TILESHIFT; + +} + + + + +/* +============================================================================= + + GUARD + +============================================================================= +*/ + +// +// guards +// + +extern statetype s_grdstand; + +extern statetype s_grdpath1; +extern statetype s_grdpath1s; +extern statetype s_grdpath2; +extern statetype s_grdpath3; +extern statetype s_grdpath3s; +extern statetype s_grdpath4; + +extern statetype s_grdpain; +extern statetype s_grdpain1; + +extern statetype s_grdgiveup; + +extern statetype s_grdshoot1; +extern statetype s_grdshoot2; +extern statetype s_grdshoot3; +extern statetype s_grdshoot4; + +extern statetype s_grdchase1; +extern statetype s_grdchase1s; +extern statetype s_grdchase2; +extern statetype s_grdchase3; +extern statetype s_grdchase3s; +extern statetype s_grdchase4; + +extern statetype s_grddie1; +extern statetype s_grddie1d; +extern statetype s_grddie2; +extern statetype s_grddie3; +extern statetype s_grddie4; + +statetype s_grdstand = {true,SPR_GRD_S_1,0,T_Stand,NULL,&s_grdstand}; + +statetype s_grdpath1 = {true,SPR_GRD_W1_1,20,T_Path,NULL,&s_grdpath1s}; +statetype s_grdpath1s = {true,SPR_GRD_W1_1,5,NULL,NULL,&s_grdpath2}; +statetype s_grdpath2 = {true,SPR_GRD_W2_1,15,T_Path,NULL,&s_grdpath3}; +statetype s_grdpath3 = {true,SPR_GRD_W3_1,20,T_Path,NULL,&s_grdpath3s}; +statetype s_grdpath3s = {true,SPR_GRD_W3_1,5,NULL,NULL,&s_grdpath4}; +statetype s_grdpath4 = {true,SPR_GRD_W4_1,15,T_Path,NULL,&s_grdpath1}; + +statetype s_grdpain = {2,SPR_GRD_PAIN_1,10,NULL,NULL,&s_grdchase1}; +statetype s_grdpain1 = {2,SPR_GRD_PAIN_2,10,NULL,NULL,&s_grdchase1}; + +statetype s_grdshoot1 = {false,SPR_GRD_SHOOT1,20,NULL,NULL,&s_grdshoot2}; +statetype s_grdshoot2 = {false,SPR_GRD_SHOOT2,20,NULL,T_Shoot,&s_grdshoot3}; +statetype s_grdshoot3 = {false,SPR_GRD_SHOOT3,20,NULL,NULL,&s_grdchase1}; + +statetype s_grdchase1 = {true,SPR_GRD_W1_1,10,T_Chase,NULL,&s_grdchase1s}; +statetype s_grdchase1s = {true,SPR_GRD_W1_1,3,NULL,NULL,&s_grdchase2}; +statetype s_grdchase2 = {true,SPR_GRD_W2_1,8,T_Chase,NULL,&s_grdchase3}; +statetype s_grdchase3 = {true,SPR_GRD_W3_1,10,T_Chase,NULL,&s_grdchase3s}; +statetype s_grdchase3s = {true,SPR_GRD_W3_1,3,NULL,NULL,&s_grdchase4}; +statetype s_grdchase4 = {true,SPR_GRD_W4_1,8,T_Chase,NULL,&s_grdchase1}; + +statetype s_grddie1 = {false,SPR_GRD_DIE_1,15,NULL,A_DeathScream,&s_grddie2}; +statetype s_grddie2 = {false,SPR_GRD_DIE_2,15,NULL,NULL,&s_grddie3}; +statetype s_grddie3 = {false,SPR_GRD_DIE_3,15,NULL,NULL,&s_grddie4}; +statetype s_grddie4 = {false,SPR_GRD_DEAD,0,NULL,NULL,&s_grddie4}; + + +#ifndef SPEAR +// +// ghosts +// +extern statetype s_blinkychase1; +extern statetype s_blinkychase2; +extern statetype s_inkychase1; +extern statetype s_inkychase2; +extern statetype s_pinkychase1; +extern statetype s_pinkychase2; +extern statetype s_clydechase1; +extern statetype s_clydechase2; + +statetype s_blinkychase1 = {false,SPR_BLINKY_W1,10,T_Ghosts,NULL,&s_blinkychase2}; +statetype s_blinkychase2 = {false,SPR_BLINKY_W2,10,T_Ghosts,NULL,&s_blinkychase1}; + +statetype s_inkychase1 = {false,SPR_INKY_W1,10,T_Ghosts,NULL,&s_inkychase2}; +statetype s_inkychase2 = {false,SPR_INKY_W2,10,T_Ghosts,NULL,&s_inkychase1}; + +statetype s_pinkychase1 = {false,SPR_PINKY_W1,10,T_Ghosts,NULL,&s_pinkychase2}; +statetype s_pinkychase2 = {false,SPR_PINKY_W2,10,T_Ghosts,NULL,&s_pinkychase1}; + +statetype s_clydechase1 = {false,SPR_CLYDE_W1,10,T_Ghosts,NULL,&s_clydechase2}; +statetype s_clydechase2 = {false,SPR_CLYDE_W2,10,T_Ghosts,NULL,&s_clydechase1}; +#endif + +// +// dogs +// + +extern statetype s_dogpath1; +extern statetype s_dogpath1s; +extern statetype s_dogpath2; +extern statetype s_dogpath3; +extern statetype s_dogpath3s; +extern statetype s_dogpath4; + +extern statetype s_dogjump1; +extern statetype s_dogjump2; +extern statetype s_dogjump3; +extern statetype s_dogjump4; +extern statetype s_dogjump5; + +extern statetype s_dogchase1; +extern statetype s_dogchase1s; +extern statetype s_dogchase2; +extern statetype s_dogchase3; +extern statetype s_dogchase3s; +extern statetype s_dogchase4; + +extern statetype s_dogdie1; +extern statetype s_dogdie1d; +extern statetype s_dogdie2; +extern statetype s_dogdie3; +extern statetype s_dogdead; + +statetype s_dogpath1 = {true,SPR_DOG_W1_1,20,T_Path,NULL,&s_dogpath1s}; +statetype s_dogpath1s = {true,SPR_DOG_W1_1,5,NULL,NULL,&s_dogpath2}; +statetype s_dogpath2 = {true,SPR_DOG_W2_1,15,T_Path,NULL,&s_dogpath3}; +statetype s_dogpath3 = {true,SPR_DOG_W3_1,20,T_Path,NULL,&s_dogpath3s}; +statetype s_dogpath3s = {true,SPR_DOG_W3_1,5,NULL,NULL,&s_dogpath4}; +statetype s_dogpath4 = {true,SPR_DOG_W4_1,15,T_Path,NULL,&s_dogpath1}; + +statetype s_dogjump1 = {false,SPR_DOG_JUMP1,10,NULL,NULL,&s_dogjump2}; +statetype s_dogjump2 = {false,SPR_DOG_JUMP2,10,NULL,T_Bite,&s_dogjump3}; +statetype s_dogjump3 = {false,SPR_DOG_JUMP3,10,NULL,NULL,&s_dogjump4}; +statetype s_dogjump4 = {false,SPR_DOG_JUMP1,10,NULL,NULL,&s_dogjump5}; +statetype s_dogjump5 = {false,SPR_DOG_W1_1,10,NULL,NULL,&s_dogchase1}; + +statetype s_dogchase1 = {true,SPR_DOG_W1_1,10,T_DogChase,NULL,&s_dogchase1s}; +statetype s_dogchase1s = {true,SPR_DOG_W1_1,3,NULL,NULL,&s_dogchase2}; +statetype s_dogchase2 = {true,SPR_DOG_W2_1,8,T_DogChase,NULL,&s_dogchase3}; +statetype s_dogchase3 = {true,SPR_DOG_W3_1,10,T_DogChase,NULL,&s_dogchase3s}; +statetype s_dogchase3s = {true,SPR_DOG_W3_1,3,NULL,NULL,&s_dogchase4}; +statetype s_dogchase4 = {true,SPR_DOG_W4_1,8,T_DogChase,NULL,&s_dogchase1}; + +statetype s_dogdie1 = {false,SPR_DOG_DIE_1,15,NULL,A_DeathScream,&s_dogdie2}; +statetype s_dogdie2 = {false,SPR_DOG_DIE_2,15,NULL,NULL,&s_dogdie3}; +statetype s_dogdie3 = {false,SPR_DOG_DIE_3,15,NULL,NULL,&s_dogdead}; +statetype s_dogdead = {false,SPR_DOG_DEAD,15,NULL,NULL,&s_dogdead}; + + +// +// officers +// + +extern statetype s_ofcstand; + +extern statetype s_ofcpath1; +extern statetype s_ofcpath1s; +extern statetype s_ofcpath2; +extern statetype s_ofcpath3; +extern statetype s_ofcpath3s; +extern statetype s_ofcpath4; + +extern statetype s_ofcpain; +extern statetype s_ofcpain1; + +extern statetype s_ofcgiveup; + +extern statetype s_ofcshoot1; +extern statetype s_ofcshoot2; +extern statetype s_ofcshoot3; +extern statetype s_ofcshoot4; + +extern statetype s_ofcchase1; +extern statetype s_ofcchase1s; +extern statetype s_ofcchase2; +extern statetype s_ofcchase3; +extern statetype s_ofcchase3s; +extern statetype s_ofcchase4; + +extern statetype s_ofcdie1; +extern statetype s_ofcdie2; +extern statetype s_ofcdie3; +extern statetype s_ofcdie4; +extern statetype s_ofcdie5; + +statetype s_ofcstand = {true,SPR_OFC_S_1,0,T_Stand,NULL,&s_ofcstand}; + +statetype s_ofcpath1 = {true,SPR_OFC_W1_1,20,T_Path,NULL,&s_ofcpath1s}; +statetype s_ofcpath1s = {true,SPR_OFC_W1_1,5,NULL,NULL,&s_ofcpath2}; +statetype s_ofcpath2 = {true,SPR_OFC_W2_1,15,T_Path,NULL,&s_ofcpath3}; +statetype s_ofcpath3 = {true,SPR_OFC_W3_1,20,T_Path,NULL,&s_ofcpath3s}; +statetype s_ofcpath3s = {true,SPR_OFC_W3_1,5,NULL,NULL,&s_ofcpath4}; +statetype s_ofcpath4 = {true,SPR_OFC_W4_1,15,T_Path,NULL,&s_ofcpath1}; + +statetype s_ofcpain = {2,SPR_OFC_PAIN_1,10,NULL,NULL,&s_ofcchase1}; +statetype s_ofcpain1 = {2,SPR_OFC_PAIN_2,10,NULL,NULL,&s_ofcchase1}; + +statetype s_ofcshoot1 = {false,SPR_OFC_SHOOT1,6,NULL,NULL,&s_ofcshoot2}; +statetype s_ofcshoot2 = {false,SPR_OFC_SHOOT2,20,NULL,T_Shoot,&s_ofcshoot3}; +statetype s_ofcshoot3 = {false,SPR_OFC_SHOOT3,10,NULL,NULL,&s_ofcchase1}; + +statetype s_ofcchase1 = {true,SPR_OFC_W1_1,10,T_Chase,NULL,&s_ofcchase1s}; +statetype s_ofcchase1s = {true,SPR_OFC_W1_1,3,NULL,NULL,&s_ofcchase2}; +statetype s_ofcchase2 = {true,SPR_OFC_W2_1,8,T_Chase,NULL,&s_ofcchase3}; +statetype s_ofcchase3 = {true,SPR_OFC_W3_1,10,T_Chase,NULL,&s_ofcchase3s}; +statetype s_ofcchase3s = {true,SPR_OFC_W3_1,3,NULL,NULL,&s_ofcchase4}; +statetype s_ofcchase4 = {true,SPR_OFC_W4_1,8,T_Chase,NULL,&s_ofcchase1}; + +statetype s_ofcdie1 = {false,SPR_OFC_DIE_1,11,NULL,A_DeathScream,&s_ofcdie2}; +statetype s_ofcdie2 = {false,SPR_OFC_DIE_2,11,NULL,NULL,&s_ofcdie3}; +statetype s_ofcdie3 = {false,SPR_OFC_DIE_3,11,NULL,NULL,&s_ofcdie4}; +statetype s_ofcdie4 = {false,SPR_OFC_DIE_4,11,NULL,NULL,&s_ofcdie5}; +statetype s_ofcdie5 = {false,SPR_OFC_DEAD,0,NULL,NULL,&s_ofcdie5}; + + +// +// mutant +// + +extern statetype s_mutstand; + +extern statetype s_mutpath1; +extern statetype s_mutpath1s; +extern statetype s_mutpath2; +extern statetype s_mutpath3; +extern statetype s_mutpath3s; +extern statetype s_mutpath4; + +extern statetype s_mutpain; +extern statetype s_mutpain1; + +extern statetype s_mutgiveup; + +extern statetype s_mutshoot1; +extern statetype s_mutshoot2; +extern statetype s_mutshoot3; +extern statetype s_mutshoot4; + +extern statetype s_mutchase1; +extern statetype s_mutchase1s; +extern statetype s_mutchase2; +extern statetype s_mutchase3; +extern statetype s_mutchase3s; +extern statetype s_mutchase4; + +extern statetype s_mutdie1; +extern statetype s_mutdie2; +extern statetype s_mutdie3; +extern statetype s_mutdie4; +extern statetype s_mutdie5; + +statetype s_mutstand = {true,SPR_MUT_S_1,0,T_Stand,NULL,&s_mutstand}; + +statetype s_mutpath1 = {true,SPR_MUT_W1_1,20,T_Path,NULL,&s_mutpath1s}; +statetype s_mutpath1s = {true,SPR_MUT_W1_1,5,NULL,NULL,&s_mutpath2}; +statetype s_mutpath2 = {true,SPR_MUT_W2_1,15,T_Path,NULL,&s_mutpath3}; +statetype s_mutpath3 = {true,SPR_MUT_W3_1,20,T_Path,NULL,&s_mutpath3s}; +statetype s_mutpath3s = {true,SPR_MUT_W3_1,5,NULL,NULL,&s_mutpath4}; +statetype s_mutpath4 = {true,SPR_MUT_W4_1,15,T_Path,NULL,&s_mutpath1}; + +statetype s_mutpain = {2,SPR_MUT_PAIN_1,10,NULL,NULL,&s_mutchase1}; +statetype s_mutpain1 = {2,SPR_MUT_PAIN_2,10,NULL,NULL,&s_mutchase1}; + +statetype s_mutshoot1 = {false,SPR_MUT_SHOOT1,6,NULL,T_Shoot,&s_mutshoot2}; +statetype s_mutshoot2 = {false,SPR_MUT_SHOOT2,20,NULL,NULL,&s_mutshoot3}; +statetype s_mutshoot3 = {false,SPR_MUT_SHOOT3,10,NULL,T_Shoot,&s_mutshoot4}; +statetype s_mutshoot4 = {false,SPR_MUT_SHOOT4,20,NULL,NULL,&s_mutchase1}; + +statetype s_mutchase1 = {true,SPR_MUT_W1_1,10,T_Chase,NULL,&s_mutchase1s}; +statetype s_mutchase1s = {true,SPR_MUT_W1_1,3,NULL,NULL,&s_mutchase2}; +statetype s_mutchase2 = {true,SPR_MUT_W2_1,8,T_Chase,NULL,&s_mutchase3}; +statetype s_mutchase3 = {true,SPR_MUT_W3_1,10,T_Chase,NULL,&s_mutchase3s}; +statetype s_mutchase3s = {true,SPR_MUT_W3_1,3,NULL,NULL,&s_mutchase4}; +statetype s_mutchase4 = {true,SPR_MUT_W4_1,8,T_Chase,NULL,&s_mutchase1}; + +statetype s_mutdie1 = {false,SPR_MUT_DIE_1,7,NULL,A_DeathScream,&s_mutdie2}; +statetype s_mutdie2 = {false,SPR_MUT_DIE_2,7,NULL,NULL,&s_mutdie3}; +statetype s_mutdie3 = {false,SPR_MUT_DIE_3,7,NULL,NULL,&s_mutdie4}; +statetype s_mutdie4 = {false,SPR_MUT_DIE_4,7,NULL,NULL,&s_mutdie5}; +statetype s_mutdie5 = {false,SPR_MUT_DEAD,0,NULL,NULL,&s_mutdie5}; + + +// +// SS +// + +extern statetype s_ssstand; + +extern statetype s_sspath1; +extern statetype s_sspath1s; +extern statetype s_sspath2; +extern statetype s_sspath3; +extern statetype s_sspath3s; +extern statetype s_sspath4; + +extern statetype s_sspain; +extern statetype s_sspain1; + +extern statetype s_ssshoot1; +extern statetype s_ssshoot2; +extern statetype s_ssshoot3; +extern statetype s_ssshoot4; +extern statetype s_ssshoot5; +extern statetype s_ssshoot6; +extern statetype s_ssshoot7; +extern statetype s_ssshoot8; +extern statetype s_ssshoot9; + +extern statetype s_sschase1; +extern statetype s_sschase1s; +extern statetype s_sschase2; +extern statetype s_sschase3; +extern statetype s_sschase3s; +extern statetype s_sschase4; + +extern statetype s_ssdie1; +extern statetype s_ssdie2; +extern statetype s_ssdie3; +extern statetype s_ssdie4; + +statetype s_ssstand = {true,SPR_SS_S_1,0,T_Stand,NULL,&s_ssstand}; + +statetype s_sspath1 = {true,SPR_SS_W1_1,20,T_Path,NULL,&s_sspath1s}; +statetype s_sspath1s = {true,SPR_SS_W1_1,5,NULL,NULL,&s_sspath2}; +statetype s_sspath2 = {true,SPR_SS_W2_1,15,T_Path,NULL,&s_sspath3}; +statetype s_sspath3 = {true,SPR_SS_W3_1,20,T_Path,NULL,&s_sspath3s}; +statetype s_sspath3s = {true,SPR_SS_W3_1,5,NULL,NULL,&s_sspath4}; +statetype s_sspath4 = {true,SPR_SS_W4_1,15,T_Path,NULL,&s_sspath1}; + +statetype s_sspain = {2,SPR_SS_PAIN_1,10,NULL,NULL,&s_sschase1}; +statetype s_sspain1 = {2,SPR_SS_PAIN_2,10,NULL,NULL,&s_sschase1}; + +statetype s_ssshoot1 = {false,SPR_SS_SHOOT1,20,NULL,NULL,&s_ssshoot2}; +statetype s_ssshoot2 = {false,SPR_SS_SHOOT2,20,NULL,T_Shoot,&s_ssshoot3}; +statetype s_ssshoot3 = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot4}; +statetype s_ssshoot4 = {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot5}; +statetype s_ssshoot5 = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot6}; +statetype s_ssshoot6 = {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot7}; +statetype s_ssshoot7 = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_ssshoot8}; +statetype s_ssshoot8 = {false,SPR_SS_SHOOT2,10,NULL,T_Shoot,&s_ssshoot9}; +statetype s_ssshoot9 = {false,SPR_SS_SHOOT3,10,NULL,NULL,&s_sschase1}; + +statetype s_sschase1 = {true,SPR_SS_W1_1,10,T_Chase,NULL,&s_sschase1s}; +statetype s_sschase1s = {true,SPR_SS_W1_1,3,NULL,NULL,&s_sschase2}; +statetype s_sschase2 = {true,SPR_SS_W2_1,8,T_Chase,NULL,&s_sschase3}; +statetype s_sschase3 = {true,SPR_SS_W3_1,10,T_Chase,NULL,&s_sschase3s}; +statetype s_sschase3s = {true,SPR_SS_W3_1,3,NULL,NULL,&s_sschase4}; +statetype s_sschase4 = {true,SPR_SS_W4_1,8,T_Chase,NULL,&s_sschase1}; + +statetype s_ssdie1 = {false,SPR_SS_DIE_1,15,NULL,A_DeathScream,&s_ssdie2}; +statetype s_ssdie2 = {false,SPR_SS_DIE_2,15,NULL,NULL,&s_ssdie3}; +statetype s_ssdie3 = {false,SPR_SS_DIE_3,15,NULL,NULL,&s_ssdie4}; +statetype s_ssdie4 = {false,SPR_SS_DEAD,0,NULL,NULL,&s_ssdie4}; + + +#ifndef SPEAR +// +// hans +// +extern statetype s_bossstand; + +extern statetype s_bosschase1; +extern statetype s_bosschase1s; +extern statetype s_bosschase2; +extern statetype s_bosschase3; +extern statetype s_bosschase3s; +extern statetype s_bosschase4; + +extern statetype s_bossdie1; +extern statetype s_bossdie2; +extern statetype s_bossdie3; +extern statetype s_bossdie4; + +extern statetype s_bossshoot1; +extern statetype s_bossshoot2; +extern statetype s_bossshoot3; +extern statetype s_bossshoot4; +extern statetype s_bossshoot5; +extern statetype s_bossshoot6; +extern statetype s_bossshoot7; +extern statetype s_bossshoot8; + + +statetype s_bossstand = {false,SPR_BOSS_W1,0,T_Stand,NULL,&s_bossstand}; + +statetype s_bosschase1 = {false,SPR_BOSS_W1,10,T_Chase,NULL,&s_bosschase1s}; +statetype s_bosschase1s = {false,SPR_BOSS_W1,3,NULL,NULL,&s_bosschase2}; +statetype s_bosschase2 = {false,SPR_BOSS_W2,8,T_Chase,NULL,&s_bosschase3}; +statetype s_bosschase3 = {false,SPR_BOSS_W3,10,T_Chase,NULL,&s_bosschase3s}; +statetype s_bosschase3s = {false,SPR_BOSS_W3,3,NULL,NULL,&s_bosschase4}; +statetype s_bosschase4 = {false,SPR_BOSS_W4,8,T_Chase,NULL,&s_bosschase1}; + +statetype s_bossdie1 = {false,SPR_BOSS_DIE1,15,NULL,A_DeathScream,&s_bossdie2}; +statetype s_bossdie2 = {false,SPR_BOSS_DIE2,15,NULL,NULL,&s_bossdie3}; +statetype s_bossdie3 = {false,SPR_BOSS_DIE3,15,NULL,NULL,&s_bossdie4}; +statetype s_bossdie4 = {false,SPR_BOSS_DEAD,0,NULL,NULL,&s_bossdie4}; + +statetype s_bossshoot1 = {false,SPR_BOSS_SHOOT1,30,NULL,NULL,&s_bossshoot2}; +statetype s_bossshoot2 = {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot3}; +statetype s_bossshoot3 = {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot4}; +statetype s_bossshoot4 = {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot5}; +statetype s_bossshoot5 = {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot6}; +statetype s_bossshoot6 = {false,SPR_BOSS_SHOOT2,10,NULL,T_Shoot,&s_bossshoot7}; +statetype s_bossshoot7 = {false,SPR_BOSS_SHOOT3,10,NULL,T_Shoot,&s_bossshoot8}; +statetype s_bossshoot8 = {false,SPR_BOSS_SHOOT1,10,NULL,NULL,&s_bosschase1}; + + +// +// gretel +// +extern statetype s_gretelstand; + +extern statetype s_gretelchase1; +extern statetype s_gretelchase1s; +extern statetype s_gretelchase2; +extern statetype s_gretelchase3; +extern statetype s_gretelchase3s; +extern statetype s_gretelchase4; + +extern statetype s_greteldie1; +extern statetype s_greteldie2; +extern statetype s_greteldie3; +extern statetype s_greteldie4; + +extern statetype s_gretelshoot1; +extern statetype s_gretelshoot2; +extern statetype s_gretelshoot3; +extern statetype s_gretelshoot4; +extern statetype s_gretelshoot5; +extern statetype s_gretelshoot6; +extern statetype s_gretelshoot7; +extern statetype s_gretelshoot8; + + +statetype s_gretelstand = {false,SPR_GRETEL_W1,0,T_Stand,NULL,&s_gretelstand}; + +statetype s_gretelchase1 = {false,SPR_GRETEL_W1,10,T_Chase,NULL,&s_gretelchase1s}; +statetype s_gretelchase1s = {false,SPR_GRETEL_W1,3,NULL,NULL,&s_gretelchase2}; +statetype s_gretelchase2 = {false,SPR_GRETEL_W2,8,T_Chase,NULL,&s_gretelchase3}; +statetype s_gretelchase3 = {false,SPR_GRETEL_W3,10,T_Chase,NULL,&s_gretelchase3s}; +statetype s_gretelchase3s = {false,SPR_GRETEL_W3,3,NULL,NULL,&s_gretelchase4}; +statetype s_gretelchase4 = {false,SPR_GRETEL_W4,8,T_Chase,NULL,&s_gretelchase1}; + +statetype s_greteldie1 = {false,SPR_GRETEL_DIE1,15,NULL,A_DeathScream,&s_greteldie2}; +statetype s_greteldie2 = {false,SPR_GRETEL_DIE2,15,NULL,NULL,&s_greteldie3}; +statetype s_greteldie3 = {false,SPR_GRETEL_DIE3,15,NULL,NULL,&s_greteldie4}; +statetype s_greteldie4 = {false,SPR_GRETEL_DEAD,0,NULL,NULL,&s_greteldie4}; + +statetype s_gretelshoot1 = {false,SPR_GRETEL_SHOOT1,30,NULL,NULL,&s_gretelshoot2}; +statetype s_gretelshoot2 = {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot3}; +statetype s_gretelshoot3 = {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot4}; +statetype s_gretelshoot4 = {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot5}; +statetype s_gretelshoot5 = {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot6}; +statetype s_gretelshoot6 = {false,SPR_GRETEL_SHOOT2,10,NULL,T_Shoot,&s_gretelshoot7}; +statetype s_gretelshoot7 = {false,SPR_GRETEL_SHOOT3,10,NULL,T_Shoot,&s_gretelshoot8}; +statetype s_gretelshoot8 = {false,SPR_GRETEL_SHOOT1,10,NULL,NULL,&s_gretelchase1}; +#endif + + +/* +=============== += += SpawnStand += +=============== +*/ + +void SpawnStand (enemy_t which, int tilex, int tiley, int dir) +{ + unsigned far *map,tile; + + switch (which) + { + case en_guard: + SpawnNewObj (tilex,tiley,&s_grdstand); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_officer: + SpawnNewObj (tilex,tiley,&s_ofcstand); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_mutant: + SpawnNewObj (tilex,tiley,&s_mutstand); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_ss: + SpawnNewObj (tilex,tiley,&s_ssstand); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + } + + + map = mapsegs[0]+farmapylookup[tiley]+tilex; + if (*map == AMBUSHTILE) + { + tilemap[tilex][tiley] = 0; + + if (*(map+1) >= AREATILE) + tile = *(map+1); + if (*(map-mapwidth) >= AREATILE) + tile = *(map-mapwidth); + if (*(map+mapwidth) >= AREATILE) + tile = *(map+mapwidth); + if ( *(map-1) >= AREATILE) + tile = *(map-1); + + *map = tile; + new->areanumber = tile-AREATILE; + + new->flags |= FL_AMBUSH; + } + + new->obclass = guardobj+which; + new->hitpoints = starthitpoints[gamestate.difficulty][which]; + new->dir = dir*2; + new->flags |= FL_SHOOTABLE; +} + + + +/* +=============== += += SpawnDeadGuard += +=============== +*/ + +void SpawnDeadGuard (int tilex, int tiley) +{ + SpawnNewObj (tilex,tiley,&s_grddie4); + new->obclass = inertobj; +} + + + +#ifndef SPEAR +/* +=============== += += SpawnBoss += +=============== +*/ + +void SpawnBoss (int tilex, int tiley) +{ + unsigned far *map,tile; + + SpawnNewObj (tilex,tiley,&s_bossstand); + new->speed = SPDPATROL; + + new->obclass = bossobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_boss]; + new->dir = south; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + +/* +=============== += += SpawnGretel += +=============== +*/ + +void SpawnGretel (int tilex, int tiley) +{ + unsigned far *map,tile; + + SpawnNewObj (tilex,tiley,&s_gretelstand); + new->speed = SPDPATROL; + + new->obclass = gretelobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_gretel]; + new->dir = north; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} +#endif + +/* +=============== += += SpawnPatrol += +=============== +*/ + +void SpawnPatrol (enemy_t which, int tilex, int tiley, int dir) +{ + switch (which) + { + case en_guard: + SpawnNewObj (tilex,tiley,&s_grdpath1); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_officer: + SpawnNewObj (tilex,tiley,&s_ofcpath1); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_ss: + SpawnNewObj (tilex,tiley,&s_sspath1); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_mutant: + SpawnNewObj (tilex,tiley,&s_mutpath1); + new->speed = SPDPATROL; + if (!loadedgame) + gamestate.killtotal++; + break; + + case en_dog: + SpawnNewObj (tilex,tiley,&s_dogpath1); + new->speed = SPDDOG; + if (!loadedgame) + gamestate.killtotal++; + break; + } + + new->obclass = guardobj+which; + new->dir = dir*2; + new->hitpoints = starthitpoints[gamestate.difficulty][which]; + new->distance = tileglobal; + new->flags |= FL_SHOOTABLE; + new->active = true; + + actorat[new->tilex][new->tiley] = NULL; // don't use original spot + + switch (dir) + { + case 0: + new->tilex++; + break; + case 1: + new->tiley--; + break; + case 2: + new->tilex--; + break; + case 3: + new->tiley++; + break; + } + + actorat[new->tilex][new->tiley] = new; +} + + + +/* +================== += += A_DeathScream += +================== +*/ + +void A_DeathScream (objtype *ob) +{ +#ifndef UPLOAD +#ifndef SPEAR + if (mapon==9 && !US_RndT()) +#else + if ((mapon==18 || mapon==19) && !US_RndT()) +#endif + { + switch(ob->obclass) + { + case mutantobj: + case guardobj: + case officerobj: + case ssobj: + case dogobj: + PlaySoundLocActor(DEATHSCREAM6SND,ob); + return; + } + } +#endif + + switch (ob->obclass) + { + case mutantobj: + PlaySoundLocActor(AHHHGSND,ob); + break; + + case guardobj: + { + int sounds[9]={ DEATHSCREAM1SND, + DEATHSCREAM2SND, + DEATHSCREAM3SND, + DEATHSCREAM4SND, + DEATHSCREAM5SND, + DEATHSCREAM7SND, + DEATHSCREAM8SND, + DEATHSCREAM9SND + }; + + #ifndef UPLOAD + PlaySoundLocActor(sounds[US_RndT()%8],ob); + #else + PlaySoundLocActor(sounds[US_RndT()%2],ob); + #endif + } + break; + case officerobj: + PlaySoundLocActor(NEINSOVASSND,ob); + break; + case ssobj: + PlaySoundLocActor(LEBENSND,ob); // JAB + break; + case dogobj: + PlaySoundLocActor(DOGDEATHSND,ob); // JAB + break; +#ifndef SPEAR + case bossobj: + SD_PlaySound(MUTTISND); // JAB + break; + case schabbobj: + SD_PlaySound(MEINGOTTSND); + break; + case fakeobj: + SD_PlaySound(HITLERHASND); + break; + case mechahitlerobj: + SD_PlaySound(SCHEISTSND); + break; + case realhitlerobj: + SD_PlaySound(EVASND); + break; + case gretelobj: + SD_PlaySound(MEINSND); + break; + case giftobj: + SD_PlaySound(DONNERSND); + break; + case fatobj: + SD_PlaySound(ROSESND); + break; +#else + case spectreobj: + SD_PlaySound(GHOSTFADESND); + break; + case angelobj: + SD_PlaySound(ANGELDEATHSND); + break; + case transobj: + SD_PlaySound(TRANSDEATHSND); + break; + case uberobj: + SD_PlaySound(UBERDEATHSND); + break; + case willobj: + SD_PlaySound(WILHELMDEATHSND); + break; + case deathobj: + SD_PlaySound(KNIGHTDEATHSND); + break; +#endif + } +} + + +/* +============================================================================= + + SPEAR ACTORS + +============================================================================= +*/ + +#ifdef SPEAR + +void T_Launch (objtype *ob); +void T_Will (objtype *ob); + +extern statetype s_angelshoot1; +extern statetype s_deathshoot1; +extern statetype s_spark1; + +// +// trans +// +extern statetype s_transstand; + +extern statetype s_transchase1; +extern statetype s_transchase1s; +extern statetype s_transchase2; +extern statetype s_transchase3; +extern statetype s_transchase3s; +extern statetype s_transchase4; + +extern statetype s_transdie0; +extern statetype s_transdie01; +extern statetype s_transdie1; +extern statetype s_transdie2; +extern statetype s_transdie3; +extern statetype s_transdie4; + +extern statetype s_transshoot1; +extern statetype s_transshoot2; +extern statetype s_transshoot3; +extern statetype s_transshoot4; +extern statetype s_transshoot5; +extern statetype s_transshoot6; +extern statetype s_transshoot7; +extern statetype s_transshoot8; + + +statetype s_transstand = {false,SPR_TRANS_W1,0,T_Stand,NULL,&s_transstand}; + +statetype s_transchase1 = {false,SPR_TRANS_W1,10,T_Chase,NULL,&s_transchase1s}; +statetype s_transchase1s = {false,SPR_TRANS_W1,3,NULL,NULL,&s_transchase2}; +statetype s_transchase2 = {false,SPR_TRANS_W2,8,T_Chase,NULL,&s_transchase3}; +statetype s_transchase3 = {false,SPR_TRANS_W3,10,T_Chase,NULL,&s_transchase3s}; +statetype s_transchase3s = {false,SPR_TRANS_W3,3,NULL,NULL,&s_transchase4}; +statetype s_transchase4 = {false,SPR_TRANS_W4,8,T_Chase,NULL,&s_transchase1}; + +statetype s_transdie0 = {false,SPR_TRANS_W1,1,NULL,A_DeathScream,&s_transdie01}; +statetype s_transdie01 = {false,SPR_TRANS_W1,1,NULL,NULL,&s_transdie1}; +statetype s_transdie1 = {false,SPR_TRANS_DIE1,15,NULL,NULL,&s_transdie2}; +statetype s_transdie2 = {false,SPR_TRANS_DIE2,15,NULL,NULL,&s_transdie3}; +statetype s_transdie3 = {false,SPR_TRANS_DIE3,15,NULL,NULL,&s_transdie4}; +statetype s_transdie4 = {false,SPR_TRANS_DEAD,0,NULL,NULL,&s_transdie4}; + +statetype s_transshoot1 = {false,SPR_TRANS_SHOOT1,30,NULL,NULL,&s_transshoot2}; +statetype s_transshoot2 = {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot3}; +statetype s_transshoot3 = {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot4}; +statetype s_transshoot4 = {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot5}; +statetype s_transshoot5 = {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot6}; +statetype s_transshoot6 = {false,SPR_TRANS_SHOOT2,10,NULL,T_Shoot,&s_transshoot7}; +statetype s_transshoot7 = {false,SPR_TRANS_SHOOT3,10,NULL,T_Shoot,&s_transshoot8}; +statetype s_transshoot8 = {false,SPR_TRANS_SHOOT1,10,NULL,NULL,&s_transchase1}; + + +/* +=============== += += SpawnTrans += +=============== +*/ + +void SpawnTrans (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_transdie01.tictime = 105; + + SpawnNewObj (tilex,tiley,&s_transstand); + new->obclass = transobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_trans]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +// +// uber +// +void T_UShoot (objtype *ob); + +extern statetype s_uberstand; + +extern statetype s_uberchase1; +extern statetype s_uberchase1s; +extern statetype s_uberchase2; +extern statetype s_uberchase3; +extern statetype s_uberchase3s; +extern statetype s_uberchase4; + +extern statetype s_uberdie0; +extern statetype s_uberdie01; +extern statetype s_uberdie1; +extern statetype s_uberdie2; +extern statetype s_uberdie3; +extern statetype s_uberdie4; +extern statetype s_uberdie5; + +extern statetype s_ubershoot1; +extern statetype s_ubershoot2; +extern statetype s_ubershoot3; +extern statetype s_ubershoot4; +extern statetype s_ubershoot5; +extern statetype s_ubershoot6; +extern statetype s_ubershoot7; + + +statetype s_uberstand = {false,SPR_UBER_W1,0,T_Stand,NULL,&s_uberstand}; + +statetype s_uberchase1 = {false,SPR_UBER_W1,10,T_Chase,NULL,&s_uberchase1s}; +statetype s_uberchase1s = {false,SPR_UBER_W1,3,NULL,NULL,&s_uberchase2}; +statetype s_uberchase2 = {false,SPR_UBER_W2,8,T_Chase,NULL,&s_uberchase3}; +statetype s_uberchase3 = {false,SPR_UBER_W3,10,T_Chase,NULL,&s_uberchase3s}; +statetype s_uberchase3s = {false,SPR_UBER_W3,3,NULL,NULL,&s_uberchase4}; +statetype s_uberchase4 = {false,SPR_UBER_W4,8,T_Chase,NULL,&s_uberchase1}; + +statetype s_uberdie0 = {false,SPR_UBER_W1,1,NULL,A_DeathScream,&s_uberdie01}; +statetype s_uberdie01 = {false,SPR_UBER_W1,1,NULL,NULL,&s_uberdie1}; +statetype s_uberdie1 = {false,SPR_UBER_DIE1,15,NULL,NULL,&s_uberdie2}; +statetype s_uberdie2 = {false,SPR_UBER_DIE2,15,NULL,NULL,&s_uberdie3}; +statetype s_uberdie3 = {false,SPR_UBER_DIE3,15,NULL,NULL,&s_uberdie4}; +statetype s_uberdie4 = {false,SPR_UBER_DIE4,15,NULL,NULL,&s_uberdie5}; +statetype s_uberdie5 = {false,SPR_UBER_DEAD,0,NULL,NULL,&s_uberdie5}; + +statetype s_ubershoot1 = {false,SPR_UBER_SHOOT1,30,NULL,NULL,&s_ubershoot2}; +statetype s_ubershoot2 = {false,SPR_UBER_SHOOT2,12,NULL,T_UShoot,&s_ubershoot3}; +statetype s_ubershoot3 = {false,SPR_UBER_SHOOT3,12,NULL,T_UShoot,&s_ubershoot4}; +statetype s_ubershoot4 = {false,SPR_UBER_SHOOT4,12,NULL,T_UShoot,&s_ubershoot5}; +statetype s_ubershoot5 = {false,SPR_UBER_SHOOT3,12,NULL,T_UShoot,&s_ubershoot6}; +statetype s_ubershoot6 = {false,SPR_UBER_SHOOT2,12,NULL,T_UShoot,&s_ubershoot7}; +statetype s_ubershoot7 = {false,SPR_UBER_SHOOT1,12,NULL,NULL,&s_uberchase1}; + + +/* +=============== += += SpawnUber += +=============== +*/ + +void SpawnUber (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_uberdie01.tictime = 70; + + SpawnNewObj (tilex,tiley,&s_uberstand); + new->obclass = uberobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_uber]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += T_UShoot += +=============== +*/ + +void T_UShoot (objtype *ob) +{ + int dx,dy,dist; + + T_Shoot (ob); + + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + if (dist <= 1) + TakeDamage (10,ob); +} + + +// +// will +// +extern statetype s_willstand; + +extern statetype s_willchase1; +extern statetype s_willchase1s; +extern statetype s_willchase2; +extern statetype s_willchase3; +extern statetype s_willchase3s; +extern statetype s_willchase4; + +extern statetype s_willdie1; +extern statetype s_willdie2; +extern statetype s_willdie3; +extern statetype s_willdie4; +extern statetype s_willdie5; +extern statetype s_willdie6; + +extern statetype s_willshoot1; +extern statetype s_willshoot2; +extern statetype s_willshoot3; +extern statetype s_willshoot4; +extern statetype s_willshoot5; +extern statetype s_willshoot6; + + +statetype s_willstand = {false,SPR_WILL_W1,0,T_Stand,NULL,&s_willstand}; + +statetype s_willchase1 = {false,SPR_WILL_W1,10,T_Will,NULL,&s_willchase1s}; +statetype s_willchase1s = {false,SPR_WILL_W1,3,NULL,NULL,&s_willchase2}; +statetype s_willchase2 = {false,SPR_WILL_W2,8,T_Will,NULL,&s_willchase3}; +statetype s_willchase3 = {false,SPR_WILL_W3,10,T_Will,NULL,&s_willchase3s}; +statetype s_willchase3s = {false,SPR_WILL_W3,3,NULL,NULL,&s_willchase4}; +statetype s_willchase4 = {false,SPR_WILL_W4,8,T_Will,NULL,&s_willchase1}; + +statetype s_willdeathcam = {false,SPR_WILL_W1,1,NULL,NULL,&s_willdie1}; + +statetype s_willdie1 = {false,SPR_WILL_W1,1,NULL,A_DeathScream,&s_willdie2}; +statetype s_willdie2 = {false,SPR_WILL_W1,10,NULL,NULL,&s_willdie3}; +statetype s_willdie3 = {false,SPR_WILL_DIE1,10,NULL,NULL,&s_willdie4}; +statetype s_willdie4 = {false,SPR_WILL_DIE2,10,NULL,NULL,&s_willdie5}; +statetype s_willdie5 = {false,SPR_WILL_DIE3,10,NULL,NULL,&s_willdie6}; +statetype s_willdie6 = {false,SPR_WILL_DEAD,20,NULL,NULL,&s_willdie6}; + +statetype s_willshoot1 = {false,SPR_WILL_SHOOT1,30,NULL,NULL,&s_willshoot2}; +statetype s_willshoot2 = {false,SPR_WILL_SHOOT2,10,NULL,T_Launch,&s_willshoot3}; +statetype s_willshoot3 = {false,SPR_WILL_SHOOT3,10,NULL,T_Shoot,&s_willshoot4}; +statetype s_willshoot4 = {false,SPR_WILL_SHOOT4,10,NULL,T_Shoot,&s_willshoot5}; +statetype s_willshoot5 = {false,SPR_WILL_SHOOT3,10,NULL,T_Shoot,&s_willshoot6}; +statetype s_willshoot6 = {false,SPR_WILL_SHOOT4,10,NULL,T_Shoot,&s_willchase1}; + + +/* +=============== += += SpawnWill += +=============== +*/ + +void SpawnWill (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_willdie2.tictime = 70; + + SpawnNewObj (tilex,tiley,&s_willstand); + new->obclass = willobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_will]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +================ += += T_Will += +================ +*/ + +void T_Will (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + dodge = false; + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + + if (CheckLine(ob)) // got a shot at player? + { + if ( US_RndT() < (tics<<3) ) + { + // + // go into attack frame + // + if (ob->obclass == willobj) + NewState (ob,&s_willshoot1); + else if (ob->obclass == angelobj) + NewState (ob,&s_angelshoot1); + else + NewState (ob,&s_deathshoot1); + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dist <4) + SelectRunDir (ob); + else if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + +// +// death +// +extern statetype s_deathstand; + +extern statetype s_deathchase1; +extern statetype s_deathchase1s; +extern statetype s_deathchase2; +extern statetype s_deathchase3; +extern statetype s_deathchase3s; +extern statetype s_deathchase4; + +extern statetype s_deathdie1; +extern statetype s_deathdie2; +extern statetype s_deathdie3; +extern statetype s_deathdie4; +extern statetype s_deathdie5; +extern statetype s_deathdie6; +extern statetype s_deathdie7; +extern statetype s_deathdie8; +extern statetype s_deathdie9; + +extern statetype s_deathshoot1; +extern statetype s_deathshoot2; +extern statetype s_deathshoot3; +extern statetype s_deathshoot4; +extern statetype s_deathshoot5; + + +statetype s_deathstand = {false,SPR_DEATH_W1,0,T_Stand,NULL,&s_deathstand}; + +statetype s_deathchase1 = {false,SPR_DEATH_W1,10,T_Will,NULL,&s_deathchase1s}; +statetype s_deathchase1s = {false,SPR_DEATH_W1,3,NULL,NULL,&s_deathchase2}; +statetype s_deathchase2 = {false,SPR_DEATH_W2,8,T_Will,NULL,&s_deathchase3}; +statetype s_deathchase3 = {false,SPR_DEATH_W3,10,T_Will,NULL,&s_deathchase3s}; +statetype s_deathchase3s = {false,SPR_DEATH_W3,3,NULL,NULL,&s_deathchase4}; +statetype s_deathchase4 = {false,SPR_DEATH_W4,8,T_Will,NULL,&s_deathchase1}; + +statetype s_deathdeathcam = {false,SPR_DEATH_W1,1,NULL,NULL,&s_deathdie1}; + +statetype s_deathdie1 = {false,SPR_DEATH_W1,1,NULL,A_DeathScream,&s_deathdie2}; +statetype s_deathdie2 = {false,SPR_DEATH_W1,10,NULL,NULL,&s_deathdie3}; +statetype s_deathdie3 = {false,SPR_DEATH_DIE1,10,NULL,NULL,&s_deathdie4}; +statetype s_deathdie4 = {false,SPR_DEATH_DIE2,10,NULL,NULL,&s_deathdie5}; +statetype s_deathdie5 = {false,SPR_DEATH_DIE3,10,NULL,NULL,&s_deathdie6}; +statetype s_deathdie6 = {false,SPR_DEATH_DIE4,10,NULL,NULL,&s_deathdie7}; +statetype s_deathdie7 = {false,SPR_DEATH_DIE5,10,NULL,NULL,&s_deathdie8}; +statetype s_deathdie8 = {false,SPR_DEATH_DIE6,10,NULL,NULL,&s_deathdie9}; +statetype s_deathdie9 = {false,SPR_DEATH_DEAD,0,NULL,NULL,&s_deathdie9}; + +statetype s_deathshoot1 = {false,SPR_DEATH_SHOOT1,30,NULL,NULL,&s_deathshoot2}; +statetype s_deathshoot2 = {false,SPR_DEATH_SHOOT2,10,NULL,T_Launch,&s_deathshoot3}; +statetype s_deathshoot3 = {false,SPR_DEATH_SHOOT4,10,NULL,T_Shoot,&s_deathshoot4}; +statetype s_deathshoot4 = {false,SPR_DEATH_SHOOT3,10,NULL,T_Launch,&s_deathshoot5}; +statetype s_deathshoot5 = {false,SPR_DEATH_SHOOT4,10,NULL,T_Shoot,&s_deathchase1}; + + +/* +=============== += += SpawnDeath += +=============== +*/ + +void SpawnDeath (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_deathdie2.tictime = 105; + + SpawnNewObj (tilex,tiley,&s_deathstand); + new->obclass = deathobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_death]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + +/* +=============== += += T_Launch += +=============== +*/ + +void T_Launch (objtype *ob) +{ + long deltax,deltay; + float angle; + int iangle; + + deltax = player->x - ob->x; + deltay = ob->y - player->y; + angle = atan2 (deltay,deltax); + if (angle<0) + angle = M_PI*2+angle; + iangle = angle/(M_PI*2)*ANGLES; + if (ob->obclass == deathobj) + { + T_Shoot (ob); + if (ob->state == &s_deathshoot2) + { + iangle-=4; + if (iangle<0) + iangle+=ANGLES; + } + else + { + iangle+=4; + if (iangle>=ANGLES) + iangle-=ANGLES; + } + } + + GetNewActor (); + new->state = &s_rocket; + new->ticcount = 1; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->obclass = rocketobj; + switch(ob->obclass) + { + case deathobj: + new->state = &s_hrocket; + new->obclass = hrocketobj; + PlaySoundLocActor (KNIGHTMISSILESND,new); + break; + case angelobj: + new->state = &s_spark1; + new->obclass = sparkobj; + PlaySoundLocActor (ANGELFIRESND,new); + break; + default: + PlaySoundLocActor (MISSILEFIRESND,new); + } + + new->dir = nodir; + new->angle = iangle; + new->speed = 0x2000l; + new->flags = FL_NONMARK; + new->active = true; +} + + + +// +// angel +// +void A_Relaunch (objtype *ob); +void A_Victory (objtype *ob); +void A_StartAttack (objtype *ob); +void A_Breathing (objtype *ob); + +extern statetype s_angelstand; + +extern statetype s_angelchase1; +extern statetype s_angelchase1s; +extern statetype s_angelchase2; +extern statetype s_angelchase3; +extern statetype s_angelchase3s; +extern statetype s_angelchase4; + +extern statetype s_angeldie1; +extern statetype s_angeldie11; +extern statetype s_angeldie2; +extern statetype s_angeldie3; +extern statetype s_angeldie4; +extern statetype s_angeldie5; +extern statetype s_angeldie6; +extern statetype s_angeldie7; +extern statetype s_angeldie8; +extern statetype s_angeldie9; + +extern statetype s_angelshoot1; +extern statetype s_angelshoot2; +extern statetype s_angelshoot3; +extern statetype s_angelshoot4; +extern statetype s_angelshoot5; +extern statetype s_angelshoot6; + +extern statetype s_angeltired; +extern statetype s_angeltired2; +extern statetype s_angeltired3; +extern statetype s_angeltired4; +extern statetype s_angeltired5; +extern statetype s_angeltired6; +extern statetype s_angeltired7; + +extern statetype s_spark1; +extern statetype s_spark2; +extern statetype s_spark3; +extern statetype s_spark4; + + +statetype s_angelstand = {false,SPR_ANGEL_W1,0,T_Stand,NULL,&s_angelstand}; + +statetype s_angelchase1 = {false,SPR_ANGEL_W1,10,T_Will,NULL,&s_angelchase1s}; +statetype s_angelchase1s = {false,SPR_ANGEL_W1,3,NULL,NULL,&s_angelchase2}; +statetype s_angelchase2 = {false,SPR_ANGEL_W2,8,T_Will,NULL,&s_angelchase3}; +statetype s_angelchase3 = {false,SPR_ANGEL_W3,10,T_Will,NULL,&s_angelchase3s}; +statetype s_angelchase3s = {false,SPR_ANGEL_W3,3,NULL,NULL,&s_angelchase4}; +statetype s_angelchase4 = {false,SPR_ANGEL_W4,8,T_Will,NULL,&s_angelchase1}; + +statetype s_angeldie1 = {false,SPR_ANGEL_W1,1,NULL,A_DeathScream,&s_angeldie11}; +statetype s_angeldie11 = {false,SPR_ANGEL_W1,1,NULL,NULL,&s_angeldie2}; +statetype s_angeldie2 = {false,SPR_ANGEL_DIE1,10,NULL,A_Slurpie,&s_angeldie3}; +statetype s_angeldie3 = {false,SPR_ANGEL_DIE2,10,NULL,NULL,&s_angeldie4}; +statetype s_angeldie4 = {false,SPR_ANGEL_DIE3,10,NULL,NULL,&s_angeldie5}; +statetype s_angeldie5 = {false,SPR_ANGEL_DIE4,10,NULL,NULL,&s_angeldie6}; +statetype s_angeldie6 = {false,SPR_ANGEL_DIE5,10,NULL,NULL,&s_angeldie7}; +statetype s_angeldie7 = {false,SPR_ANGEL_DIE6,10,NULL,NULL,&s_angeldie8}; +statetype s_angeldie8 = {false,SPR_ANGEL_DIE7,10,NULL,NULL,&s_angeldie9}; +statetype s_angeldie9 = {false,SPR_ANGEL_DEAD,130,NULL,A_Victory,&s_angeldie9}; + +statetype s_angelshoot1 = {false,SPR_ANGEL_SHOOT1,10,NULL,A_StartAttack,&s_angelshoot2}; +statetype s_angelshoot2 = {false,SPR_ANGEL_SHOOT2,20,NULL,T_Launch,&s_angelshoot3}; +statetype s_angelshoot3 = {false,SPR_ANGEL_SHOOT1,10,NULL,A_Relaunch,&s_angelshoot2}; + +statetype s_angeltired = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired2}; +statetype s_angeltired2 = {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired3}; +statetype s_angeltired3 = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired4}; +statetype s_angeltired4 = {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired5}; +statetype s_angeltired5 = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angeltired6}; +statetype s_angeltired6 = {false,SPR_ANGEL_TIRED2,40,NULL,NULL,&s_angeltired7}; +statetype s_angeltired7 = {false,SPR_ANGEL_TIRED1,40,NULL,A_Breathing,&s_angelchase1}; + +statetype s_spark1 = {false,SPR_SPARK1,6,T_Projectile,NULL,&s_spark2}; +statetype s_spark2 = {false,SPR_SPARK2,6,T_Projectile,NULL,&s_spark3}; +statetype s_spark3 = {false,SPR_SPARK3,6,T_Projectile,NULL,&s_spark4}; +statetype s_spark4 = {false,SPR_SPARK4,6,T_Projectile,NULL,&s_spark1}; + + +#pragma argsused +void A_Slurpie (objtype *ob) +{ + SD_PlaySound(SLURPIESND); +} + +#pragma argsused +void A_Breathing (objtype *ob) +{ + SD_PlaySound(ANGELTIREDSND); +} + +/* +=============== += += SpawnAngel += +=============== +*/ + +void SpawnAngel (int tilex, int tiley) +{ + unsigned far *map,tile; + + + if (SoundBlasterPresent && DigiMode != sds_Off) + s_angeldie11.tictime = 105; + + SpawnNewObj (tilex,tiley,&s_angelstand); + new->obclass = angelobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_angel]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +================= += += A_Victory += +================= +*/ + +#pragma argsused +void A_Victory (objtype *ob) +{ + playstate = ex_victorious; +} + + +/* +================= += += A_StartAttack += +================= +*/ + +void A_StartAttack (objtype *ob) +{ + ob->temp1 = 0; +} + + +/* +================= += += A_Relaunch += +================= +*/ + +void A_Relaunch (objtype *ob) +{ + if (++ob->temp1 == 3) + { + NewState (ob,&s_angeltired); + return; + } + + if (US_RndT()&1) + { + NewState (ob,&s_angelchase1); + return; + } +} + + + + +// +// spectre +// +void T_SpectreWait (objtype *ob); +void A_Dormant (objtype *ob); + +extern statetype s_spectrewait1; +extern statetype s_spectrewait2; +extern statetype s_spectrewait3; +extern statetype s_spectrewait4; + +extern statetype s_spectrechase1; +extern statetype s_spectrechase2; +extern statetype s_spectrechase3; +extern statetype s_spectrechase4; + +extern statetype s_spectredie1; +extern statetype s_spectredie2; +extern statetype s_spectredie3; +extern statetype s_spectredie4; + +extern statetype s_spectrewake; + +statetype s_spectrewait1 = {false,SPR_SPECTRE_W1,10,T_Stand,NULL,&s_spectrewait2}; +statetype s_spectrewait2 = {false,SPR_SPECTRE_W2,10,T_Stand,NULL,&s_spectrewait3}; +statetype s_spectrewait3 = {false,SPR_SPECTRE_W3,10,T_Stand,NULL,&s_spectrewait4}; +statetype s_spectrewait4 = {false,SPR_SPECTRE_W4,10,T_Stand,NULL,&s_spectrewait1}; + +statetype s_spectrechase1 = {false,SPR_SPECTRE_W1,10,T_Ghosts,NULL,&s_spectrechase2}; +statetype s_spectrechase2 = {false,SPR_SPECTRE_W2,10,T_Ghosts,NULL,&s_spectrechase3}; +statetype s_spectrechase3 = {false,SPR_SPECTRE_W3,10,T_Ghosts,NULL,&s_spectrechase4}; +statetype s_spectrechase4 = {false,SPR_SPECTRE_W4,10,T_Ghosts,NULL,&s_spectrechase1}; + +statetype s_spectredie1 = {false,SPR_SPECTRE_F1,10,NULL,NULL,&s_spectredie2}; +statetype s_spectredie2 = {false,SPR_SPECTRE_F2,10,NULL,NULL,&s_spectredie3}; +statetype s_spectredie3 = {false,SPR_SPECTRE_F3,10,NULL,NULL,&s_spectredie4}; +statetype s_spectredie4 = {false,SPR_SPECTRE_F4,300,NULL,NULL,&s_spectrewake}; +statetype s_spectrewake = {false,SPR_SPECTRE_F4,10,NULL,A_Dormant,&s_spectrewake}; + +/* +=============== += += SpawnSpectre += +=============== +*/ + +void SpawnSpectre (int tilex, int tiley) +{ + unsigned far *map,tile; + + SpawnNewObj (tilex,tiley,&s_spectrewait1); + new->obclass = spectreobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_spectre]; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; // |FL_NEVERMARK|FL_NONMARK; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += A_Dormant += +=============== +*/ + +void A_Dormant (objtype *ob) +{ + long deltax,deltay; + int xl,xh,yl,yh; + int x,y; + unsigned tile; + + deltax = ob->x - player->x; + if (deltax < -MINACTORDIST || deltax > MINACTORDIST) + goto moveok; + deltay = ob->y - player->y; + if (deltay < -MINACTORDIST || deltay > MINACTORDIST) + goto moveok; + + return; +moveok: + + xl = (ob->x-MINDIST) >> TILESHIFT; + xh = (ob->x+MINDIST) >> TILESHIFT; + yl = (ob->y-MINDIST) >> TILESHIFT; + yh = (ob->y+MINDIST) >> TILESHIFT; + + for (y=yl ; y<=yh ; y++) + for (x=xl ; x<=xh ; x++) + { + tile = actorat[x][y]; + if (!tile) + continue; + if (tile<256) + return; + if (((objtype *)tile)->flags&FL_SHOOTABLE) + return; + } + + ob->flags |= FL_AMBUSH | FL_SHOOTABLE; + ob->flags &= ~FL_ATTACKMODE; + ob->dir = nodir; + NewState (ob,&s_spectrewait1); +} + + +#endif + +/* +============================================================================= + + SCHABBS / GIFT / FAT + +============================================================================= +*/ + +#ifndef SPEAR +/* +=============== += += SpawnGhosts += +=============== +*/ + +void SpawnGhosts (int which, int tilex, int tiley) +{ + unsigned far *map,tile; + + switch(which) + { + case en_blinky: + SpawnNewObj (tilex,tiley,&s_blinkychase1); + break; + case en_clyde: + SpawnNewObj (tilex,tiley,&s_clydechase1); + break; + case en_pinky: + SpawnNewObj (tilex,tiley,&s_pinkychase1); + break; + case en_inky: + SpawnNewObj (tilex,tiley,&s_inkychase1); + break; + } + + new->obclass = ghostobj; + new->speed = SPDDOG; + + new->dir = east; + new->flags |= FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + + +void T_Gift (objtype *ob); +void T_GiftThrow (objtype *ob); + +void T_Fat (objtype *ob); +void T_FatThrow (objtype *ob); + +// +// schabb +// +extern statetype s_schabbstand; + +extern statetype s_schabbchase1; +extern statetype s_schabbchase1s; +extern statetype s_schabbchase2; +extern statetype s_schabbchase3; +extern statetype s_schabbchase3s; +extern statetype s_schabbchase4; + +extern statetype s_schabbdie1; +extern statetype s_schabbdie2; +extern statetype s_schabbdie3; +extern statetype s_schabbdie4; +extern statetype s_schabbdie5; +extern statetype s_schabbdie6; + +extern statetype s_schabbshoot1; +extern statetype s_schabbshoot2; + +extern statetype s_needle1; +extern statetype s_needle2; +extern statetype s_needle3; +extern statetype s_needle4; + +extern statetype s_schabbdeathcam; + + +statetype s_schabbstand = {false,SPR_SCHABB_W1,0,T_Stand,NULL,&s_schabbstand}; + +statetype s_schabbchase1 = {false,SPR_SCHABB_W1,10,T_Schabb,NULL,&s_schabbchase1s}; +statetype s_schabbchase1s = {false,SPR_SCHABB_W1,3,NULL,NULL,&s_schabbchase2}; +statetype s_schabbchase2 = {false,SPR_SCHABB_W2,8,T_Schabb,NULL,&s_schabbchase3}; +statetype s_schabbchase3 = {false,SPR_SCHABB_W3,10,T_Schabb,NULL,&s_schabbchase3s}; +statetype s_schabbchase3s = {false,SPR_SCHABB_W3,3,NULL,NULL,&s_schabbchase4}; +statetype s_schabbchase4 = {false,SPR_SCHABB_W4,8,T_Schabb,NULL,&s_schabbchase1}; + +statetype s_schabbdeathcam = {false,SPR_SCHABB_W1,1,NULL,NULL,&s_schabbdie1}; + +statetype s_schabbdie1 = {false,SPR_SCHABB_W1,10,NULL,A_DeathScream,&s_schabbdie2}; +statetype s_schabbdie2 = {false,SPR_SCHABB_W1,10,NULL,NULL,&s_schabbdie3}; +statetype s_schabbdie3 = {false,SPR_SCHABB_DIE1,10,NULL,NULL,&s_schabbdie4}; +statetype s_schabbdie4 = {false,SPR_SCHABB_DIE2,10,NULL,NULL,&s_schabbdie5}; +statetype s_schabbdie5 = {false,SPR_SCHABB_DIE3,10,NULL,NULL,&s_schabbdie6}; +statetype s_schabbdie6 = {false,SPR_SCHABB_DEAD,20,NULL,A_StartDeathCam,&s_schabbdie6}; + +statetype s_schabbshoot1 = {false,SPR_SCHABB_SHOOT1,30,NULL,NULL,&s_schabbshoot2}; +statetype s_schabbshoot2 = {false,SPR_SCHABB_SHOOT2,10,NULL,T_SchabbThrow,&s_schabbchase1}; + +statetype s_needle1 = {false,SPR_HYPO1,6,T_Projectile,NULL,&s_needle2}; +statetype s_needle2 = {false,SPR_HYPO2,6,T_Projectile,NULL,&s_needle3}; +statetype s_needle3 = {false,SPR_HYPO3,6,T_Projectile,NULL,&s_needle4}; +statetype s_needle4 = {false,SPR_HYPO4,6,T_Projectile,NULL,&s_needle1}; + + +// +// gift +// +extern statetype s_giftstand; + +extern statetype s_giftchase1; +extern statetype s_giftchase1s; +extern statetype s_giftchase2; +extern statetype s_giftchase3; +extern statetype s_giftchase3s; +extern statetype s_giftchase4; + +extern statetype s_giftdie1; +extern statetype s_giftdie2; +extern statetype s_giftdie3; +extern statetype s_giftdie4; +extern statetype s_giftdie5; +extern statetype s_giftdie6; + +extern statetype s_giftshoot1; +extern statetype s_giftshoot2; + +extern statetype s_needle1; +extern statetype s_needle2; +extern statetype s_needle3; +extern statetype s_needle4; + +extern statetype s_giftdeathcam; + +extern statetype s_boom1; +extern statetype s_boom2; +extern statetype s_boom3; + + +statetype s_giftstand = {false,SPR_GIFT_W1,0,T_Stand,NULL,&s_giftstand}; + +statetype s_giftchase1 = {false,SPR_GIFT_W1,10,T_Gift,NULL,&s_giftchase1s}; +statetype s_giftchase1s = {false,SPR_GIFT_W1,3,NULL,NULL,&s_giftchase2}; +statetype s_giftchase2 = {false,SPR_GIFT_W2,8,T_Gift,NULL,&s_giftchase3}; +statetype s_giftchase3 = {false,SPR_GIFT_W3,10,T_Gift,NULL,&s_giftchase3s}; +statetype s_giftchase3s = {false,SPR_GIFT_W3,3,NULL,NULL,&s_giftchase4}; +statetype s_giftchase4 = {false,SPR_GIFT_W4,8,T_Gift,NULL,&s_giftchase1}; + +statetype s_giftdeathcam = {false,SPR_GIFT_W1,1,NULL,NULL,&s_giftdie1}; + +statetype s_giftdie1 = {false,SPR_GIFT_W1,1,NULL,A_DeathScream,&s_giftdie2}; +statetype s_giftdie2 = {false,SPR_GIFT_W1,10,NULL,NULL,&s_giftdie3}; +statetype s_giftdie3 = {false,SPR_GIFT_DIE1,10,NULL,NULL,&s_giftdie4}; +statetype s_giftdie4 = {false,SPR_GIFT_DIE2,10,NULL,NULL,&s_giftdie5}; +statetype s_giftdie5 = {false,SPR_GIFT_DIE3,10,NULL,NULL,&s_giftdie6}; +statetype s_giftdie6 = {false,SPR_GIFT_DEAD,20,NULL,A_StartDeathCam,&s_giftdie6}; + +statetype s_giftshoot1 = {false,SPR_GIFT_SHOOT1,30,NULL,NULL,&s_giftshoot2}; +statetype s_giftshoot2 = {false,SPR_GIFT_SHOOT2,10,NULL,T_GiftThrow,&s_giftchase1}; + + +// +// fat +// +extern statetype s_fatstand; + +extern statetype s_fatchase1; +extern statetype s_fatchase1s; +extern statetype s_fatchase2; +extern statetype s_fatchase3; +extern statetype s_fatchase3s; +extern statetype s_fatchase4; + +extern statetype s_fatdie1; +extern statetype s_fatdie2; +extern statetype s_fatdie3; +extern statetype s_fatdie4; +extern statetype s_fatdie5; +extern statetype s_fatdie6; + +extern statetype s_fatshoot1; +extern statetype s_fatshoot2; +extern statetype s_fatshoot3; +extern statetype s_fatshoot4; +extern statetype s_fatshoot5; +extern statetype s_fatshoot6; + +extern statetype s_needle1; +extern statetype s_needle2; +extern statetype s_needle3; +extern statetype s_needle4; + +extern statetype s_fatdeathcam; + + +statetype s_fatstand = {false,SPR_FAT_W1,0,T_Stand,NULL,&s_fatstand}; + +statetype s_fatchase1 = {false,SPR_FAT_W1,10,T_Fat,NULL,&s_fatchase1s}; +statetype s_fatchase1s = {false,SPR_FAT_W1,3,NULL,NULL,&s_fatchase2}; +statetype s_fatchase2 = {false,SPR_FAT_W2,8,T_Fat,NULL,&s_fatchase3}; +statetype s_fatchase3 = {false,SPR_FAT_W3,10,T_Fat,NULL,&s_fatchase3s}; +statetype s_fatchase3s = {false,SPR_FAT_W3,3,NULL,NULL,&s_fatchase4}; +statetype s_fatchase4 = {false,SPR_FAT_W4,8,T_Fat,NULL,&s_fatchase1}; + +statetype s_fatdeathcam = {false,SPR_FAT_W1,1,NULL,NULL,&s_fatdie1}; + +statetype s_fatdie1 = {false,SPR_FAT_W1,1,NULL,A_DeathScream,&s_fatdie2}; +statetype s_fatdie2 = {false,SPR_FAT_W1,10,NULL,NULL,&s_fatdie3}; +statetype s_fatdie3 = {false,SPR_FAT_DIE1,10,NULL,NULL,&s_fatdie4}; +statetype s_fatdie4 = {false,SPR_FAT_DIE2,10,NULL,NULL,&s_fatdie5}; +statetype s_fatdie5 = {false,SPR_FAT_DIE3,10,NULL,NULL,&s_fatdie6}; +statetype s_fatdie6 = {false,SPR_FAT_DEAD,20,NULL,A_StartDeathCam,&s_fatdie6}; + +statetype s_fatshoot1 = {false,SPR_FAT_SHOOT1,30,NULL,NULL,&s_fatshoot2}; +statetype s_fatshoot2 = {false,SPR_FAT_SHOOT2,10,NULL,T_GiftThrow,&s_fatshoot3}; +statetype s_fatshoot3 = {false,SPR_FAT_SHOOT3,10,NULL,T_Shoot,&s_fatshoot4}; +statetype s_fatshoot4 = {false,SPR_FAT_SHOOT4,10,NULL,T_Shoot,&s_fatshoot5}; +statetype s_fatshoot5 = {false,SPR_FAT_SHOOT3,10,NULL,T_Shoot,&s_fatshoot6}; +statetype s_fatshoot6 = {false,SPR_FAT_SHOOT4,10,NULL,T_Shoot,&s_fatchase1}; + + +/* +=============== += += SpawnSchabbs += +=============== +*/ + +void SpawnSchabbs (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (DigiMode != sds_Off) + s_schabbdie2.tictime = 140; + else + s_schabbdie2.tictime = 5; + + SpawnNewObj (tilex,tiley,&s_schabbstand); + new->speed = SPDPATROL; + + new->obclass = schabbobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_schabbs]; + new->dir = south; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += SpawnGift += +=============== +*/ + +void SpawnGift (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (DigiMode != sds_Off) + s_giftdie2.tictime = 140; + else + s_giftdie2.tictime = 5; + + SpawnNewObj (tilex,tiley,&s_giftstand); + new->speed = SPDPATROL; + + new->obclass = giftobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_gift]; + new->dir = north; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += SpawnFat += +=============== +*/ + +void SpawnFat (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (DigiMode != sds_Off) + s_fatdie2.tictime = 140; + else + s_fatdie2.tictime = 5; + + SpawnNewObj (tilex,tiley,&s_fatstand); + new->speed = SPDPATROL; + + new->obclass = fatobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_fat]; + new->dir = south; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +================= += += T_SchabbThrow += +================= +*/ + +void T_SchabbThrow (objtype *ob) +{ + long deltax,deltay; + float angle; + int iangle; + + deltax = player->x - ob->x; + deltay = ob->y - player->y; + angle = atan2 (deltay,deltax); + if (angle<0) + angle = M_PI*2+angle; + iangle = angle/(M_PI*2)*ANGLES; + + GetNewActor (); + new->state = &s_needle1; + new->ticcount = 1; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->obclass = needleobj; + new->dir = nodir; + new->angle = iangle; + new->speed = 0x2000l; + + new->flags = FL_NONMARK; + new->active = true; + + PlaySoundLocActor (SCHABBSTHROWSND,new); +} + +/* +================= += += T_GiftThrow += +================= +*/ + +void T_GiftThrow (objtype *ob) +{ + long deltax,deltay; + float angle; + int iangle; + + deltax = player->x - ob->x; + deltay = ob->y - player->y; + angle = atan2 (deltay,deltax); + if (angle<0) + angle = M_PI*2+angle; + iangle = angle/(M_PI*2)*ANGLES; + + GetNewActor (); + new->state = &s_rocket; + new->ticcount = 1; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->obclass = rocketobj; + new->dir = nodir; + new->angle = iangle; + new->speed = 0x2000l; + new->flags = FL_NONMARK; + new->active = true; + + PlaySoundLocActor (MISSILEFIRESND,new); +} + + + +/* +================= += += T_Schabb += +================= +*/ + +void T_Schabb (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + dodge = false; + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + + if (CheckLine(ob)) // got a shot at player? + { + + if ( US_RndT() < (tics<<3) ) + { + // + // go into attack frame + // + NewState (ob,&s_schabbshoot1); + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dist <4) + SelectRunDir (ob); + else if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + + + +/* +================= += += T_Gift += +================= +*/ + +void T_Gift (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + dodge = false; + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + + if (CheckLine(ob)) // got a shot at player? + { + + if ( US_RndT() < (tics<<3) ) + { + // + // go into attack frame + // + NewState (ob,&s_giftshoot1); + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dist <4) + SelectRunDir (ob); + else if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + + + +/* +================= += += T_Fat += +================= +*/ + +void T_Fat (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + dodge = false; + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + + if (CheckLine(ob)) // got a shot at player? + { + + if ( US_RndT() < (tics<<3) ) + { + // + // go into attack frame + // + NewState (ob,&s_fatshoot1); + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dist <4) + SelectRunDir (ob); + else if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + + +/* +============================================================================= + + HITLERS + +============================================================================= +*/ + + +// +// fake +// +extern statetype s_fakestand; + +extern statetype s_fakechase1; +extern statetype s_fakechase1s; +extern statetype s_fakechase2; +extern statetype s_fakechase3; +extern statetype s_fakechase3s; +extern statetype s_fakechase4; + +extern statetype s_fakedie1; +extern statetype s_fakedie2; +extern statetype s_fakedie3; +extern statetype s_fakedie4; +extern statetype s_fakedie5; +extern statetype s_fakedie6; + +extern statetype s_fakeshoot1; +extern statetype s_fakeshoot2; +extern statetype s_fakeshoot3; +extern statetype s_fakeshoot4; +extern statetype s_fakeshoot5; +extern statetype s_fakeshoot6; +extern statetype s_fakeshoot7; +extern statetype s_fakeshoot8; +extern statetype s_fakeshoot9; + +extern statetype s_fire1; +extern statetype s_fire2; + +statetype s_fakestand = {false,SPR_FAKE_W1,0,T_Stand,NULL,&s_fakestand}; + +statetype s_fakechase1 = {false,SPR_FAKE_W1,10,T_Fake,NULL,&s_fakechase1s}; +statetype s_fakechase1s = {false,SPR_FAKE_W1,3,NULL,NULL,&s_fakechase2}; +statetype s_fakechase2 = {false,SPR_FAKE_W2,8,T_Fake,NULL,&s_fakechase3}; +statetype s_fakechase3 = {false,SPR_FAKE_W3,10,T_Fake,NULL,&s_fakechase3s}; +statetype s_fakechase3s = {false,SPR_FAKE_W3,3,NULL,NULL,&s_fakechase4}; +statetype s_fakechase4 = {false,SPR_FAKE_W4,8,T_Fake,NULL,&s_fakechase1}; + +statetype s_fakedie1 = {false,SPR_FAKE_DIE1,10,NULL,A_DeathScream,&s_fakedie2}; +statetype s_fakedie2 = {false,SPR_FAKE_DIE2,10,NULL,NULL,&s_fakedie3}; +statetype s_fakedie3 = {false,SPR_FAKE_DIE3,10,NULL,NULL,&s_fakedie4}; +statetype s_fakedie4 = {false,SPR_FAKE_DIE4,10,NULL,NULL,&s_fakedie5}; +statetype s_fakedie5 = {false,SPR_FAKE_DIE5,10,NULL,NULL,&s_fakedie6}; +statetype s_fakedie6 = {false,SPR_FAKE_DEAD,0,NULL,NULL,&s_fakedie6}; + +statetype s_fakeshoot1 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot2}; +statetype s_fakeshoot2 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot3}; +statetype s_fakeshoot3 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot4}; +statetype s_fakeshoot4 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot5}; +statetype s_fakeshoot5 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot6}; +statetype s_fakeshoot6 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot7}; +statetype s_fakeshoot7 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot8}; +statetype s_fakeshoot8 = {false,SPR_FAKE_SHOOT,8,NULL,T_FakeFire,&s_fakeshoot9}; +statetype s_fakeshoot9 = {false,SPR_FAKE_SHOOT,8,NULL,NULL,&s_fakechase1}; + +statetype s_fire1 = {false,SPR_FIRE1,6,NULL,T_Projectile,&s_fire2}; +statetype s_fire2 = {false,SPR_FIRE2,6,NULL,T_Projectile,&s_fire1}; + +// +// hitler +// +extern statetype s_mechachase1; +extern statetype s_mechachase1s; +extern statetype s_mechachase2; +extern statetype s_mechachase3; +extern statetype s_mechachase3s; +extern statetype s_mechachase4; + +extern statetype s_mechadie1; +extern statetype s_mechadie2; +extern statetype s_mechadie3; +extern statetype s_mechadie4; + +extern statetype s_mechashoot1; +extern statetype s_mechashoot2; +extern statetype s_mechashoot3; +extern statetype s_mechashoot4; +extern statetype s_mechashoot5; +extern statetype s_mechashoot6; + + +extern statetype s_hitlerchase1; +extern statetype s_hitlerchase1s; +extern statetype s_hitlerchase2; +extern statetype s_hitlerchase3; +extern statetype s_hitlerchase3s; +extern statetype s_hitlerchase4; + +extern statetype s_hitlerdie1; +extern statetype s_hitlerdie2; +extern statetype s_hitlerdie3; +extern statetype s_hitlerdie4; +extern statetype s_hitlerdie5; +extern statetype s_hitlerdie6; +extern statetype s_hitlerdie7; +extern statetype s_hitlerdie8; +extern statetype s_hitlerdie9; +extern statetype s_hitlerdie10; + +extern statetype s_hitlershoot1; +extern statetype s_hitlershoot2; +extern statetype s_hitlershoot3; +extern statetype s_hitlershoot4; +extern statetype s_hitlershoot5; +extern statetype s_hitlershoot6; + +extern statetype s_hitlerdeathcam; + +statetype s_mechastand = {false,SPR_MECHA_W1,0,T_Stand,NULL,&s_mechastand}; + +statetype s_mechachase1 = {false,SPR_MECHA_W1,10,T_Chase,A_MechaSound,&s_mechachase1s}; +statetype s_mechachase1s = {false,SPR_MECHA_W1,6,NULL,NULL,&s_mechachase2}; +statetype s_mechachase2 = {false,SPR_MECHA_W2,8,T_Chase,NULL,&s_mechachase3}; +statetype s_mechachase3 = {false,SPR_MECHA_W3,10,T_Chase,A_MechaSound,&s_mechachase3s}; +statetype s_mechachase3s = {false,SPR_MECHA_W3,6,NULL,NULL,&s_mechachase4}; +statetype s_mechachase4 = {false,SPR_MECHA_W4,8,T_Chase,NULL,&s_mechachase1}; + +statetype s_mechadie1 = {false,SPR_MECHA_DIE1,10,NULL,A_DeathScream,&s_mechadie2}; +statetype s_mechadie2 = {false,SPR_MECHA_DIE2,10,NULL,NULL,&s_mechadie3}; +statetype s_mechadie3 = {false,SPR_MECHA_DIE3,10,NULL,A_HitlerMorph,&s_mechadie4}; +statetype s_mechadie4 = {false,SPR_MECHA_DEAD,0,NULL,NULL,&s_mechadie4}; + +statetype s_mechashoot1 = {false,SPR_MECHA_SHOOT1,30,NULL,NULL,&s_mechashoot2}; +statetype s_mechashoot2 = {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechashoot3}; +statetype s_mechashoot3 = {false,SPR_MECHA_SHOOT3,10,NULL,T_Shoot,&s_mechashoot4}; +statetype s_mechashoot4 = {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechashoot5}; +statetype s_mechashoot5 = {false,SPR_MECHA_SHOOT3,10,NULL,T_Shoot,&s_mechashoot6}; +statetype s_mechashoot6 = {false,SPR_MECHA_SHOOT2,10,NULL,T_Shoot,&s_mechachase1}; + + +statetype s_hitlerchase1 = {false,SPR_HITLER_W1,6,T_Chase,NULL,&s_hitlerchase1s}; +statetype s_hitlerchase1s = {false,SPR_HITLER_W1,4,NULL,NULL,&s_hitlerchase2}; +statetype s_hitlerchase2 = {false,SPR_HITLER_W2,2,T_Chase,NULL,&s_hitlerchase3}; +statetype s_hitlerchase3 = {false,SPR_HITLER_W3,6,T_Chase,NULL,&s_hitlerchase3s}; +statetype s_hitlerchase3s = {false,SPR_HITLER_W3,4,NULL,NULL,&s_hitlerchase4}; +statetype s_hitlerchase4 = {false,SPR_HITLER_W4,2,T_Chase,NULL,&s_hitlerchase1}; + +statetype s_hitlerdeathcam = {false,SPR_HITLER_W1,10,NULL,NULL,&s_hitlerdie1}; + +statetype s_hitlerdie1 = {false,SPR_HITLER_W1,1,NULL,A_DeathScream,&s_hitlerdie2}; +statetype s_hitlerdie2 = {false,SPR_HITLER_W1,10,NULL,NULL,&s_hitlerdie3}; +statetype s_hitlerdie3 = {false,SPR_HITLER_DIE1,10,NULL,A_Slurpie,&s_hitlerdie4}; +statetype s_hitlerdie4 = {false,SPR_HITLER_DIE2,10,NULL,NULL,&s_hitlerdie5}; +statetype s_hitlerdie5 = {false,SPR_HITLER_DIE3,10,NULL,NULL,&s_hitlerdie6}; +statetype s_hitlerdie6 = {false,SPR_HITLER_DIE4,10,NULL,NULL,&s_hitlerdie7}; +statetype s_hitlerdie7 = {false,SPR_HITLER_DIE5,10,NULL,NULL,&s_hitlerdie8}; +statetype s_hitlerdie8 = {false,SPR_HITLER_DIE6,10,NULL,NULL,&s_hitlerdie9}; +statetype s_hitlerdie9 = {false,SPR_HITLER_DIE7,10,NULL,NULL,&s_hitlerdie10}; +statetype s_hitlerdie10 = {false,SPR_HITLER_DEAD,20,NULL,A_StartDeathCam,&s_hitlerdie10}; + +statetype s_hitlershoot1 = {false,SPR_HITLER_SHOOT1,30,NULL,NULL,&s_hitlershoot2}; +statetype s_hitlershoot2 = {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlershoot3}; +statetype s_hitlershoot3 = {false,SPR_HITLER_SHOOT3,10,NULL,T_Shoot,&s_hitlershoot4}; +statetype s_hitlershoot4 = {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlershoot5}; +statetype s_hitlershoot5 = {false,SPR_HITLER_SHOOT3,10,NULL,T_Shoot,&s_hitlershoot6}; +statetype s_hitlershoot6 = {false,SPR_HITLER_SHOOT2,10,NULL,T_Shoot,&s_hitlerchase1}; + + + +/* +=============== += += SpawnFakeHitler += +=============== +*/ + +void SpawnFakeHitler (int tilex, int tiley) +{ + unsigned far *map,tile; + + + if (DigiMode != sds_Off) + s_hitlerdie2.tictime = 140; + else + s_hitlerdie2.tictime = 5; + + SpawnNewObj (tilex,tiley,&s_fakestand); + new->speed = SPDPATROL; + + new->obclass = fakeobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_fake]; + new->dir = north; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += SpawnHitler += +=============== +*/ + +void SpawnHitler (int tilex, int tiley) +{ + unsigned far *map,tile; + + if (DigiMode != sds_Off) + s_hitlerdie2.tictime = 140; + else + s_hitlerdie2.tictime = 5; + + + SpawnNewObj (tilex,tiley,&s_mechastand); + new->speed = SPDPATROL; + + new->obclass = mechahitlerobj; + new->hitpoints = starthitpoints[gamestate.difficulty][en_hitler]; + new->dir = south; + new->flags |= FL_SHOOTABLE|FL_AMBUSH; + if (!loadedgame) + gamestate.killtotal++; +} + + +/* +=============== += += A_HitlerMorph += +=============== +*/ + +void A_HitlerMorph (objtype *ob) +{ + unsigned far *map,tile,hitpoints[4]={500,700,800,900}; + + + SpawnNewObj (ob->tilex,ob->tiley,&s_hitlerchase1); + new->speed = SPDPATROL*5; + + new->x = ob->x; + new->y = ob->y; + + new->distance = ob->distance; + new->dir = ob->dir; + new->flags = ob->flags | FL_SHOOTABLE; + + new->obclass = realhitlerobj; + new->hitpoints = hitpoints[gamestate.difficulty]; +} + + +//////////////////////////////////////////////////////// +// +// A_MechaSound +// A_Slurpie +// +//////////////////////////////////////////////////////// +void A_MechaSound (objtype *ob) +{ + if (areabyplayer[ob->areanumber]) + PlaySoundLocActor (MECHSTEPSND,ob); +} + + +#pragma argsused +void A_Slurpie (objtype *ob) +{ + SD_PlaySound(SLURPIESND); +} + +/* +================= += += T_FakeFire += +================= +*/ + +void T_FakeFire (objtype *ob) +{ + long deltax,deltay; + float angle; + int iangle; + + deltax = player->x - ob->x; + deltay = ob->y - player->y; + angle = atan2 (deltay,deltax); + if (angle<0) + angle = M_PI*2+angle; + iangle = angle/(M_PI*2)*ANGLES; + + GetNewActor (); + new->state = &s_fire1; + new->ticcount = 1; + + new->tilex = ob->tilex; + new->tiley = ob->tiley; + new->x = ob->x; + new->y = ob->y; + new->dir = nodir; + new->angle = iangle; + new->obclass = fireobj; + new->speed = 0x1200l; + new->flags = FL_NEVERMARK; + new->active = true; + + PlaySoundLocActor (FLAMETHROWERSND,new); +} + + + +/* +================= += += T_Fake += +================= +*/ + +void T_Fake (objtype *ob) +{ + long move; + int dx,dy,dist; + boolean dodge; + + if (CheckLine(ob)) // got a shot at player? + { + if ( US_RndT() < (tics<<1) ) + { + // + // go into attack frame + // + NewState (ob,&s_fakeshoot1); + return; + } + } + + if (ob->dir == nodir) + { + SelectDodgeDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectDodgeDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + +#endif +/* +============================================================================ + + STAND + +============================================================================ +*/ + + +/* +=============== += += T_Stand += +=============== +*/ + +void T_Stand (objtype *ob) +{ + SightPlayer (ob); +} + + +/* +============================================================================ + + CHASE + +============================================================================ +*/ + +/* +================= += += T_Chase += +================= +*/ + +void T_Chase (objtype *ob) +{ + long move; + int dx,dy,dist,chance; + boolean dodge; + + if (gamestate.victoryflag) + return; + + dodge = false; + if (CheckLine(ob)) // got a shot at player? + { + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx : dy; + if (!dist || (dist==1 && ob->distance<0x4000) ) + chance = 300; + else + chance = (tics<<4)/dist; + + if ( US_RndT()obclass) + { + case guardobj: + NewState (ob,&s_grdshoot1); + break; + case officerobj: + NewState (ob,&s_ofcshoot1); + break; + case mutantobj: + NewState (ob,&s_mutshoot1); + break; + case ssobj: + NewState (ob,&s_ssshoot1); + break; +#ifndef SPEAR + case bossobj: + NewState (ob,&s_bossshoot1); + break; + case gretelobj: + NewState (ob,&s_gretelshoot1); + break; + case mechahitlerobj: + NewState (ob,&s_mechashoot1); + break; + case realhitlerobj: + NewState (ob,&s_hitlershoot1); + break; +#else + case angelobj: + NewState (ob,&s_angelshoot1); + break; + case transobj: + NewState (ob,&s_transshoot1); + break; + case uberobj: + NewState (ob,&s_ubershoot1); + break; + case willobj: + NewState (ob,&s_willshoot1); + break; + case deathobj: + NewState (ob,&s_deathshoot1); + break; +#endif + } + return; + } + dodge = true; + } + + if (ob->dir == nodir) + { + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + if (dodge) + SelectDodgeDir (ob); + else + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + +/* +================= += += T_Ghosts += +================= +*/ + +void T_Ghosts (objtype *ob) +{ + long move; + + + if (ob->dir == nodir) + { + SelectChaseDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectChaseDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + +/* +================= += += T_DogChase += +================= +*/ + +void T_DogChase (objtype *ob) +{ + long move; + int dist,chance; + long dx,dy; + + + if (ob->dir == nodir) + { + SelectDodgeDir (ob); + if (ob->dir == nodir) + return; // object is blocked in + } + + move = ob->speed*tics; + + while (move) + { + // + // check for byte range + // + dx = player->x - ob->x; + if (dx<0) + dx = -dx; + dx -= move; + if (dx <= MINACTORDIST) + { + dy = player->y - ob->y; + if (dy<0) + dy = -dy; + dy -= move; + if (dy <= MINACTORDIST) + { + NewState (ob,&s_dogjump1); + return; + } + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + // + // reached goal tile, so select another one + // + + // + // fix position to account for round off during moving + // + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectDodgeDir (ob); + + if (ob->dir == nodir) + return; // object is blocked in + } + +} + + + +/* +============================================================================ + + PATH + +============================================================================ +*/ + + +/* +=============== += += SelectPathDir += +=============== +*/ + +void SelectPathDir (objtype *ob) +{ + unsigned spot; + + spot = MAPSPOT(ob->tilex,ob->tiley,1)-ICONARROWS; + + if (spot<8) + { + // new direction + ob->dir = spot; + } + + ob->distance = TILEGLOBAL; + + if (!TryWalk (ob)) + ob->dir = nodir; +} + + +/* +=============== += += T_Path += +=============== +*/ + +void T_Path (objtype *ob) +{ + long move; + long deltax,deltay,size; + + if (SightPlayer (ob)) + return; + + if (ob->dir == nodir) + { + SelectPathDir (ob); + if (ob->dir == nodir) + return; // all movement is blocked + } + + + move = ob->speed*tics; + + while (move) + { + if (ob->distance < 0) + { + // + // waiting for a door to open + // + OpenDoor (-ob->distance-1); + if (doorobjlist[-ob->distance-1].action != dr_open) + return; + ob->distance = TILEGLOBAL; // go ahead, the door is now opoen + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + if (ob->tilex>MAPSIZE || ob->tiley>MAPSIZE) + { + sprintf (str,"T_Path hit a wall at %u,%u, dir %u" + ,ob->tilex,ob->tiley,ob->dir); + Quit (str); + } + + + + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectPathDir (ob); + + if (ob->dir == nodir) + return; // all movement is blocked + } +} + + +/* +============================================================================= + + FIGHT + +============================================================================= +*/ + + +/* +=============== += += T_Shoot += += Try to damage the player, based on skill level and player's speed += +=============== +*/ + +void T_Shoot (objtype *ob) +{ + int dx,dy,dist; + int hitchance,damage; + + hitchance = 128; + + if (!areabyplayer[ob->areanumber]) + return; + + if (!CheckLine (ob)) // player is behind a wall + return; + + dx = abs(ob->tilex - player->tilex); + dy = abs(ob->tiley - player->tiley); + dist = dx>dy ? dx:dy; + + if (ob->obclass == ssobj || ob->obclass == bossobj) + dist = dist*2/3; // ss are better shots + + if (thrustspeed >= RUNSPEED) + { + if (ob->flags&FL_VISABLE) + hitchance = 160-dist*16; // player can see to dodge + else + hitchance = 160-dist*8; + } + else + { + if (ob->flags&FL_VISABLE) + hitchance = 256-dist*16; // player can see to dodge + else + hitchance = 256-dist*8; + } + +// see if the shot was a hit + + if (US_RndT()>2; + else if (dist<4) + damage = US_RndT()>>3; + else + damage = US_RndT()>>4; + + TakeDamage (damage,ob); + } + + switch(ob->obclass) + { + case ssobj: + PlaySoundLocActor(SSFIRESND,ob); + break; +#ifndef SPEAR + case giftobj: + case fatobj: + PlaySoundLocActor(MISSILEFIRESND,ob); + break; + case mechahitlerobj: + case realhitlerobj: + case bossobj: + PlaySoundLocActor(BOSSFIRESND,ob); + break; + case schabbobj: + PlaySoundLocActor(SCHABBSTHROWSND,ob); + break; + case fakeobj: + PlaySoundLocActor(FLAMETHROWERSND,ob); + break; +#endif + default: + PlaySoundLocActor(NAZIFIRESND,ob); + } + +} + + +/* +=============== += += T_Bite += +=============== +*/ + +void T_Bite (objtype *ob) +{ + long dx,dy; + int hitchance,damage; + + + PlaySoundLocActor(DOGATTACKSND,ob); // JAB + + dx = player->x - ob->x; + if (dx<0) + dx = -dx; + dx -= TILEGLOBAL; + if (dx <= MINACTORDIST) + { + dy = player->y - ob->y; + if (dy<0) + dy = -dy; + dy -= TILEGLOBAL; + if (dy <= MINACTORDIST) + { + if (US_RndT()<180) + { + TakeDamage (US_RndT()>>4,ob); + return; + } + } + } + + return; +} + + +#ifndef SPEAR +/* +============================================================================ + + BJ VICTORY + +============================================================================ +*/ + + +// +// BJ victory +// + +void T_BJRun (objtype *ob); +void T_BJJump (objtype *ob); +void T_BJDone (objtype *ob); +void T_BJYell (objtype *ob); + +void T_DeathCam (objtype *ob); + +extern statetype s_bjrun1; +extern statetype s_bjrun1s; +extern statetype s_bjrun2; +extern statetype s_bjrun3; +extern statetype s_bjrun3s; +extern statetype s_bjrun4; + +extern statetype s_bjjump1; +extern statetype s_bjjump2; +extern statetype s_bjjump3; +extern statetype s_bjjump4; + + +statetype s_bjrun1 = {false,SPR_BJ_W1,12,T_BJRun,NULL,&s_bjrun1s}; +statetype s_bjrun1s = {false,SPR_BJ_W1,3, NULL,NULL,&s_bjrun2}; +statetype s_bjrun2 = {false,SPR_BJ_W2,8,T_BJRun,NULL,&s_bjrun3}; +statetype s_bjrun3 = {false,SPR_BJ_W3,12,T_BJRun,NULL,&s_bjrun3s}; +statetype s_bjrun3s = {false,SPR_BJ_W3,3, NULL,NULL,&s_bjrun4}; +statetype s_bjrun4 = {false,SPR_BJ_W4,8,T_BJRun,NULL,&s_bjrun1}; + + +statetype s_bjjump1 = {false,SPR_BJ_JUMP1,14,T_BJJump,NULL,&s_bjjump2}; +statetype s_bjjump2 = {false,SPR_BJ_JUMP2,14,T_BJJump,T_BJYell,&s_bjjump3}; +statetype s_bjjump3 = {false,SPR_BJ_JUMP3,14,T_BJJump,NULL,&s_bjjump4}; +statetype s_bjjump4 = {false,SPR_BJ_JUMP4,300,NULL,T_BJDone,&s_bjjump4}; + + +statetype s_deathcam = {false,0,0,NULL,NULL,NULL}; + + +/* +=============== += += SpawnBJVictory += +=============== +*/ + +void SpawnBJVictory (void) +{ + unsigned far *map,tile; + + SpawnNewObj (player->tilex,player->tiley+1,&s_bjrun1); + new->x = player->x; + new->y = player->y; + new->obclass = bjobj; + new->dir = north; + new->temp1 = 6; // tiles to run forward +} + + + +/* +=============== += += T_BJRun += +=============== +*/ + +void T_BJRun (objtype *ob) +{ + long move; + + move = BJRUNSPEED*tics; + + while (move) + { + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + + + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + SelectPathDir (ob); + + if ( !(--ob->temp1) ) + { + NewState (ob,&s_bjjump1); + return; + } + } +} + + +/* +=============== += += T_BJJump += +=============== +*/ + +void T_BJJump (objtype *ob) +{ + long move; + + move = BJJUMPSPEED*tics; + MoveObj (ob,move); +} + + +/* +=============== += += T_BJYell += +=============== +*/ + +void T_BJYell (objtype *ob) +{ + PlaySoundLocActor(YEAHSND,ob); // JAB +} + + +/* +=============== += += T_BJDone += +=============== +*/ + +#pragma argsused +void T_BJDone (objtype *ob) +{ + playstate = ex_victorious; // exit castle tile +} + + + +//=========================================================================== + + +/* +=============== += += CheckPosition += +=============== +*/ + +boolean CheckPosition (objtype *ob) +{ + int x,y,xl,yl,xh,yh; + objtype *check; + + xl = (ob->x-PLAYERSIZE) >>TILESHIFT; + yl = (ob->y-PLAYERSIZE) >>TILESHIFT; + + xh = (ob->x+PLAYERSIZE) >>TILESHIFT; + yh = (ob->y+PLAYERSIZE) >>TILESHIFT; + + // + // check for solid walls + // + for (y=yl;y<=yh;y++) + for (x=xl;x<=xh;x++) + { + check = actorat[x][y]; + if (check && checkx = gamestate.killx; + player->y = gamestate.killy; + + dx = ob->x - player->x; + dy = player->y - ob->y; + + fangle = atan2(dy,dx); // returns -pi to pi + if (fangle<0) + fangle = M_PI*2+fangle; + + player->angle = fangle/(M_PI*2)*ANGLES; + +// +// try to position as close as possible without being in a wall +// + dist = 0x14000l; + do + { + xmove = FixedByFrac(dist,costable[player->angle]); + ymove = -FixedByFrac(dist,sintable[player->angle]); + + player->x = ob->x - xmove; + player->y = ob->y - ymove; + dist += 0x1000; + + } while (!CheckPosition (player)); + plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned + pluy = player->y >> UNSIGNEDSHIFT; + player->tilex = player->x >> TILESHIFT; // scale to tile values + player->tiley = player->y >> TILESHIFT; + +// +// go back to the game +// + temp = bufferofs; + for (i=0;i<3;i++) + { + bufferofs = screenloc[i]; + DrawPlayBorder (); + } + bufferofs = temp; + + fizzlein = true; + switch (ob->obclass) + { +#ifndef SPEAR + case schabbobj: + NewState (ob,&s_schabbdeathcam); + break; + case realhitlerobj: + NewState (ob,&s_hitlerdeathcam); + break; + case giftobj: + NewState (ob,&s_giftdeathcam); + break; + case fatobj: + NewState (ob,&s_fatdeathcam); + break; +#endif + } + +} + +#endif diff --git a/src/lib/hb/c3_asm.asm b/src/lib/hb/asm/c3_asm.asm similarity index 100% rename from src/lib/hb/c3_asm.asm rename to src/lib/hb/asm/c3_asm.asm diff --git a/src/lib/hb/c6_asm.asm b/src/lib/hb/asm/c6_asm.asm similarity index 100% rename from src/lib/hb/c6_asm.asm rename to src/lib/hb/asm/c6_asm.asm diff --git a/src/lib/hb/asm/wl_asm.asm b/src/lib/hb/asm/wl_asm.asm new file mode 100755 index 00000000..cca5d690 --- /dev/null +++ b/src/lib/hb/asm/wl_asm.asm @@ -0,0 +1,69 @@ +; JABHACK.ASM + +.386C +IDEAL +MODEL MEDIUM + +EXTRN LDIV@:far + +;============================================================================ + +DATASEG + +;============================================================================ + +CODESEG + +; Hacked up Juan Jimenez's code a bit to just return 386/not 386 +PROC _CheckIs386 +PUBLIC _CheckIs386 + +;hack to never look for a 386, for benchmark comparisons of same code on all CPUs +; pushf ; Save flag registers, we use them here +; xor ax,ax ; Clear AX and... +; push ax ; ...push it onto the stack +; popf ; Pop 0 into flag registers (all bits to 0), +; pushf ; attempting to set bits 12-15 of flags to 0's +; pop ax ; Recover the save flags +; and ax,08000h ; If bits 12-15 of flags are set to +; cmp ax,08000h ; zero then it's 8088/86 or 80188/186 +; jz not386 +; +; mov ax,07000h ; Try to set flag bits 12-14 to 1's +; push ax ; Push the test value onto the stack +; popf ; Pop it into the flag register +; pushf ; Push it back onto the stack +; pop ax ; Pop it into AX for check +; and ax,07000h ; if bits 12-14 are cleared then +; jz not386 ; the chip is an 80286 +; +; mov ax,1 ; We now assume it's a 80386 or better +; popf +; retf +;end benchmark hack + +not386: + xor ax,ax + popf + retf + + ENDP + + +PROC _jabhack2 +PUBLIC _jabhack2 + + push es + + mov ax,seg LDIV@ + mov es,ax + mov ax,9090h ;Two NOP's + mov [WORD FAR es:LDIV@],ax ;Patch over XOR AX,AX + mov [WORD FAR es:LDIV@+2],ax ;and over JMP SHORT COMMON + + pop es + retf + + ENDP + + END diff --git a/src/lib/hb/c3_debug.c b/src/lib/hb/debug/c3_debug.c similarity index 100% rename from src/lib/hb/c3_debug.c rename to src/lib/hb/debug/c3_debug.c diff --git a/src/lib/hb/c6_debug.c b/src/lib/hb/debug/c6_debug.c similarity index 100% rename from src/lib/hb/c6_debug.c rename to src/lib/hb/debug/c6_debug.c diff --git a/src/lib/hb/debug/wl_debug.c b/src/lib/hb/debug/wl_debug.c new file mode 100755 index 00000000..dd4674b1 --- /dev/null +++ b/src/lib/hb/debug/wl_debug.c @@ -0,0 +1,722 @@ +// WL_DEBUG.C + +#include "WL_DEF.H" +#pragma hdrstop +#include + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +#define VIEWTILEX (viewwidth/16) +#define VIEWTILEY (viewheight/16) + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + +int DebugKeys (void); + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +int maporgx; +int maporgy; +enum {mapview,tilemapview,actoratview,visview} viewtype; + +void ViewMap (void); + +//=========================================================================== + +/* +================== += += DebugMemory += +================== +*/ + +void DebugMemory (void) +{ + int i; + char scratch[80],str[10]; + long mem; + spritetype _seg *block; + + CenterWindow (16,7); + + US_CPrint ("Memory Usage"); + US_CPrint ("------------"); + US_Print ("Total :"); + US_PrintUnsigned (mminfo.mainmem/1024); + US_Print ("k\nFree :"); + US_PrintUnsigned (MM_UnusedMemory()/1024); + US_Print ("k\nWith purge:"); + US_PrintUnsigned (MM_TotalFree()/1024); + US_Print ("k\n"); + VW_UpdateScreen(); + IN_Ack (); +} + +//=========================================================================== + +/* +================== += += CountObjects += +================== +*/ + +void CountObjects (void) +{ + int i,total,count,active,inactive,doors; + objtype *obj; + + CenterWindow (16,7); + active = inactive = count = doors = 0; + + US_Print ("Total statics :"); + total = laststatobj-&statobjlist[0]; + US_PrintUnsigned (total); + + US_Print ("\nIn use statics:"); + for (i=0;inext;obj;obj=obj->next) + { + if (obj->active) + active++; + else + inactive++; + } + + US_Print ("\nTotal actors :"); + US_PrintUnsigned (active+inactive); + + US_Print ("\nActive actors :"); + US_PrintUnsigned (active); + + VW_UpdateScreen(); + IN_Ack (); +} + +//=========================================================================== + +/* +================ += += PicturePause += +================ +*/ + +void PicturePause (void) +{ + int i; + byte p; + unsigned x; + byte far *dest,far *src; + memptr buffer; + + VW_ColorBorder (15); + FinishPaletteShifts (); + + LastScan = 0; + while (!LastScan) + ; + if (LastScan != sc_Enter) + { + VW_ColorBorder (0); + return; + } + + VW_ColorBorder (1); + VW_SetScreen (0,0); +// +// vga stuff... +// + + ClearMemory (); + CA_SetAllPurge(); + MM_GetPtr (&buffer,64000); + for (p=0;p<4;p++) + { + src = MK_FP(0xa000,displayofs); + dest = (byte far *)buffer+p; + VGAREADMAP(p); + for (x=0;x<16000;x++,dest+=4) + *dest = *src++; + } + + +#if 0 + for (p=0;p<4;p++) + { + src = MK_FP(0xa000,0); + dest = (byte far *)buffer+51200+p; + VGAREADMAP(p); + for (x=0;x<3200;x++,dest+=4) + *dest = *src++; + } +#endif + + asm mov ax,0x13 + asm int 0x10 + + dest = MK_FP(0xa000,0); + _fmemcpy (dest,buffer,64000); + + VL_SetPalette (&gamepal); + + + IN_Shutdown (); + + VW_WaitVBL(70); + bioskey(0); + VW_WaitVBL(70); + Quit (NULL); +} + + +//=========================================================================== + + +/* +================ += += ShapeTest += +================ +*/ + +#pragma warn -pia +void ShapeTest (void) +{ +extern word NumDigi; +extern word _seg *DigiList; +static char buf[10]; + + boolean done; + ScanCode scan; + int i,j,k,x; + longword l; + memptr addr; + PageListStruct far *page; + + CenterWindow(20,16); + VW_UpdateScreen(); + for (i = 0,done = false;!done;) + { + US_ClearWindow(); +// sound = -1; + + page = &PMPages[i]; + US_Print(" Page #"); + US_PrintUnsigned(i); + if (i < PMSpriteStart) + US_Print(" (Wall)"); + else if (i < PMSoundStart) + US_Print(" (Sprite)"); + else if (i == ChunksInFile - 1) + US_Print(" (Sound Info)"); + else + US_Print(" (Sound)"); + + US_Print("\n XMS: "); + if (page->xmsPage != -1) + US_PrintUnsigned(page->xmsPage); + else + US_Print("No"); + + US_Print("\n Main: "); + if (page->mainPage != -1) + US_PrintUnsigned(page->mainPage); + else if (page->emsPage != -1) + { + US_Print("EMS "); + US_PrintUnsigned(page->emsPage); + } + else + US_Print("No"); + + US_Print("\n Last hit: "); + US_PrintUnsigned(page->lastHit); + + US_Print("\n Address: "); + addr = PM_GetPageAddress(i); + sprintf(buf,"0x%04x",(word)addr); + US_Print(buf); + + if (addr) + { + if (i < PMSpriteStart) + { + // + // draw the wall + // + bufferofs += 32*SCREENWIDTH; + postx = 128; + postwidth = 1; + postsource = ((long)((unsigned)addr))<<16; + for (x=0;x<64;x++,postx++,postsource+=64) + { + wallheight[postx] = 256; + FarScalePost (); + } + bufferofs -= 32*SCREENWIDTH; + } + else if (i < PMSoundStart) + { + // + // draw the sprite + // + bufferofs += 32*SCREENWIDTH; + SimpleScaleShape (160, i-PMSpriteStart, 64); + bufferofs -= 32*SCREENWIDTH; + } + else if (i == ChunksInFile - 1) + { + US_Print("\n\n Number of sounds: "); + US_PrintUnsigned(NumDigi); + for (l = j = k = 0;j < NumDigi;j++) + { + l += DigiList[(j * 2) + 1]; + k += (DigiList[(j * 2) + 1] + (PMPageSize - 1)) / PMPageSize; + } + US_Print("\n Total bytes: "); + US_PrintUnsigned(l); + US_Print("\n Total pages: "); + US_PrintUnsigned(k); + } + else + { + byte far *dp = (byte far *)MK_FP(addr,0); + for (j = 0;j < NumDigi;j++) + { + k = (DigiList[(j * 2) + 1] + (PMPageSize - 1)) / PMPageSize; + if + ( + (i >= PMSoundStart + DigiList[j * 2]) + && (i < PMSoundStart + DigiList[j * 2] + k) + ) + break; + } + if (j < NumDigi) + { +// sound = j; + US_Print("\n Sound #"); + US_PrintUnsigned(j); + US_Print("\n Segment #"); + US_PrintUnsigned(i - PMSoundStart - DigiList[j * 2]); + } + for (j = 0;j < page->length;j += 32) + { + byte v = dp[j]; + int v2 = (unsigned)v; + v2 -= 128; + v2 /= 4; + if (v2 < 0) + VWB_Vlin(WindowY + WindowH - 32 + v2, + WindowY + WindowH - 32, + WindowX + 8 + (j / 32),BLACK); + else + VWB_Vlin(WindowY + WindowH - 32, + WindowY + WindowH - 32 + v2, + WindowX + 8 + (j / 32),BLACK); + } + } + } + + VW_UpdateScreen(); + + while (!(scan = LastScan)) + SD_Poll(); + + IN_ClearKey(scan); + switch (scan) + { + case sc_LeftArrow: + if (i) + i--; + break; + case sc_RightArrow: + if (++i >= ChunksInFile) + i--; + break; + case sc_W: // Walls + i = 0; + break; + case sc_S: // Sprites + i = PMSpriteStart; + break; + case sc_D: // Digitized + i = PMSoundStart; + break; + case sc_I: // Digitized info + i = ChunksInFile - 1; + break; + case sc_L: // Load all pages + for (j = 0;j < ChunksInFile;j++) + PM_GetPage(j); + break; + case sc_P: +// if (sound != -1) +// SD_PlayDigitized(sound); + break; + case sc_Escape: + done = true; + break; + case sc_Enter: + PM_GetPage(i); + break; + } + } + SD_StopDigitized(); +} +#pragma warn +pia + + + +//=========================================================================== + + +/* +================ += += DebugKeys += +================ +*/ + +int DebugKeys (void) +{ + boolean esc; + int level,i; + + if (Keyboard[sc_B]) // B = border color + { + CenterWindow(24,3); + PrintY+=6; + US_Print(" Border color (0-15):"); + VW_UpdateScreen(); + esc = !US_LineInput (px,py,str,NULL,true,2,0); + if (!esc) + { + level = atoi (str); + if (level>=0 && level<=15) + VW_ColorBorder (level); + } + return 1; + } + + if (Keyboard[sc_C]) // C = count objects + { + CountObjects(); + return 1; + } + + if (Keyboard[sc_E]) // E = quit level + { + if (tedlevel) + Quit (NULL); + playstate = ex_completed; +// gamestate.mapon++; + } + + if (Keyboard[sc_F]) // F = facing spot + { + CenterWindow (14,4); + US_Print ("X:"); + US_PrintUnsigned (player->x); + US_Print ("\nY:"); + US_PrintUnsigned (player->y); + US_Print ("\nA:"); + US_PrintUnsigned (player->angle); + VW_UpdateScreen(); + IN_Ack(); + return 1; + } + + if (Keyboard[sc_G]) // G = god mode + { + CenterWindow (12,2); + if (godmode) + US_PrintCentered ("God mode OFF"); + else + US_PrintCentered ("God mode ON"); + VW_UpdateScreen(); + IN_Ack(); + godmode ^= 1; + return 1; + } + if (Keyboard[sc_H]) // H = hurt self + { + IN_ClearKeysDown (); + TakeDamage (16,NULL); + } + else if (Keyboard[sc_I]) // I = item cheat + { + CenterWindow (12,3); + US_PrintCentered ("Free items!"); + VW_UpdateScreen(); + GivePoints (100000); + HealSelf (99); + if (gamestate.bestweapon 99) + gamestate.ammo = 99; + DrawAmmo (); + IN_Ack (); + return 1; + } + else if (Keyboard[sc_M]) // M = memory info + { + DebugMemory(); + return 1; + } +#ifdef SPEAR + else if (Keyboard[sc_N]) // N = no clip + { + noclip^=1; + CenterWindow (18,3); + if (noclip) + US_PrintCentered ("No clipping ON"); + else + US_PrintCentered ("No clipping OFF"); + VW_UpdateScreen(); + IN_Ack (); + return 1; + } +#endif +#if 0 + else if (Keyboard[sc_O]) // O = overhead + { + ViewMap(); + return 1; + } +#endif + else if (Keyboard[sc_P]) // P = pause with no screen disruptioon + { + PicturePause (); + return 1; + } + else if (Keyboard[sc_Q]) // Q = fast quit + Quit (NULL); + else if (Keyboard[sc_S]) // S = slow motion + { + singlestep^=1; + CenterWindow (18,3); + if (singlestep) + US_PrintCentered ("Slow motion ON"); + else + US_PrintCentered ("Slow motion OFF"); + VW_UpdateScreen(); + IN_Ack (); + return 1; + } + else if (Keyboard[sc_T]) // T = shape test + { + ShapeTest (); + return 1; + } + else if (Keyboard[sc_V]) // V = extra VBLs + { + CenterWindow(30,3); + PrintY+=6; + US_Print(" Add how many extra VBLs(0-8):"); + VW_UpdateScreen(); + esc = !US_LineInput (px,py,str,NULL,true,2,0); + if (!esc) + { + level = atoi (str); + if (level>=0 && level<=8) + extravbls = level; + } + return 1; + } + else if (Keyboard[sc_W]) // W = warp to level + { + CenterWindow(26,3); + PrintY+=6; +#ifndef SPEAR + US_Print(" Warp to which level(1-10):"); +#else + US_Print(" Warp to which level(1-21):"); +#endif + VW_UpdateScreen(); + esc = !US_LineInput (px,py,str,NULL,true,2,0); + if (!esc) + { + level = atoi (str); +#ifndef SPEAR + if (level>0 && level<11) +#else + if (level>0 && level<22) +#endif + { + gamestate.mapon = level-1; + playstate = ex_warped; + } + } + return 1; + } + else if (Keyboard[sc_X]) // X = item cheat + { + CenterWindow (12,3); + US_PrintCentered ("Extra stuff!"); + VW_UpdateScreen(); + // DEBUG: put stuff here + IN_Ack (); + return 1; + } + + return 0; +} + + +#if 0 +/* +=================== += += OverheadRefresh += +=================== +*/ + +void OverheadRefresh (void) +{ + unsigned x,y,endx,endy,sx,sy; + unsigned tile; + + + endx = maporgx+VIEWTILEX; + endy = maporgy+VIEWTILEY; + + for (y=maporgy;y>12)); + LatchDrawChar(sx+8,sy,NUMBERCHARS+((tile&0x0f00)>>8)); + LatchDrawChar(sx,sy+8,NUMBERCHARS+((tile&0x00f0)>>4)); + LatchDrawChar(sx+8,sy+8,NUMBERCHARS+(tile&0x000f)); + } + } + +} +#endif + +#if 0 +/* +=================== += += ViewMap += +=================== +*/ + +void ViewMap (void) +{ + boolean button0held; + + viewtype = actoratview; +// button0held = false; + + + maporgx = player->tilex - VIEWTILEX/2; + if (maporgx<0) + maporgx = 0; + if (maporgx>MAPSIZE-VIEWTILEX) + maporgx=MAPSIZE-VIEWTILEX; + maporgy = player->tiley - VIEWTILEY/2; + if (maporgy<0) + maporgy = 0; + if (maporgy>MAPSIZE-VIEWTILEY) + maporgy=MAPSIZE-VIEWTILEY; + + do + { +// +// let user pan around +// + PollControls (); + if (controlx < 0 && maporgx>0) + maporgx--; + if (controlx > 0 && maporgx0) + maporgy--; + if (controly > 0 && maporgyvisview) + viewtype = mapview; + } + if (!c.button0) + button0held = false; +#endif + + OverheadRefresh (); + + } while (!Keyboard[sc_Escape]); + + IN_ClearKeysDown (); +} +#endif + diff --git a/src/lib/hb/c3_def.h b/src/lib/hb/def/c3_def.h similarity index 100% rename from src/lib/hb/c3_def.h rename to src/lib/hb/def/c3_def.h diff --git a/src/lib/hb/kd_def.h b/src/lib/hb/def/kd_def.h similarity index 100% rename from src/lib/hb/kd_def.h rename to src/lib/hb/def/kd_def.h diff --git a/src/lib/hb/def/wl_def.h b/src/lib/hb/def/wl_def.h new file mode 100755 index 00000000..d1bc0802 --- /dev/null +++ b/src/lib/hb/def/wl_def.h @@ -0,0 +1,1276 @@ +//#define BETA +#define YEAR 1992 +#define MONTH 9 +#define DAY 30 + +#include "ID_HEADS.H" +#include +#include + +#include "WL_MENU.H" + +#ifdef SPANISH +#include "SPANISH.H" +#else +#include "FOREIGN.H" +#endif + +#ifdef SPEAR +#include "F_SPEAR.H" +#endif + +/* +============================================================================= + + MACROS + +============================================================================= +*/ + + +#define COLORBORDER(color) asm{mov dx,STATUS_REGISTER_1;in al,dx;\ + mov dx,ATR_INDEX;mov al,ATR_OVERSCAN;out dx,al;mov al,color;out dx,al;\ + mov al,32;out dx,al}; + +#define MAPSPOT(x,y,plane) (*(mapsegs[plane]+farmapylookup[y]+x)) + +#define SIGN(x) ((x)>0?1:-1) +#define ABS(x) ((int)(x)>0?(x):-(x)) +#define LABS(x) ((long)(x)>0?(x):-(x)) + +/* +============================================================================= + + GLOBAL CONSTANTS + +============================================================================= +*/ + +#define MAXACTORS 150 // max number of nazis, etc / map +#define MAXSTATS 400 // max number of lamps, bonus, etc +#define MAXDOORS 64 // max number of sliding doors +#define MAXWALLTILES 64 // max number of wall tiles + +// +// tile constants +// + +#define ICONARROWS 90 +#define PUSHABLETILE 98 +#define EXITTILE 99 // at end of castle +#define AREATILE 107 // first of NUMAREAS floor tiles +#define NUMAREAS 37 +#define ELEVATORTILE 21 +#define AMBUSHTILE 106 +#define ALTELEVATORTILE 107 + +#define NUMBERCHARS 9 + + +//---------------- + +#define EXTRAPOINTS 40000 + +#define PLAYERSPEED 3000 +#define RUNSPEED 6000 + +#define SCREENSEG 0xa000 + +#define SCREENBWIDE 80 + +#define HEIGHTRATIO 0.50 // also defined in id_mm.c + +#define BORDERCOLOR 3 +#define FLASHCOLOR 5 +#define FLASHTICS 4 + + +#define PLAYERSIZE MINDIST // player radius +#define MINACTORDIST 0x10000l // minimum dist from player center + // to any actor center + +#define NUMLATCHPICS 100 + + +#define PI 3.141592657 + +#define GLOBAL1 (1l<<16) +#define TILEGLOBAL GLOBAL1 +#define PIXGLOBAL (GLOBAL1/64) +#define TILESHIFT 16l +#define UNSIGNEDSHIFT 8 + +#define ANGLES 360 // must be divisable by 4 +#define ANGLEQUAD (ANGLES/4) +#define FINEANGLES 3600 +#define ANG90 (FINEANGLES/4) +#define ANG180 (ANG90*2) +#define ANG270 (ANG90*3) +#define ANG360 (ANG90*4) +#define VANG90 (ANGLES/4) +#define VANG180 (VANG90*2) +#define VANG270 (VANG90*3) +#define VANG360 (VANG90*4) + +#define MINDIST (0x5800l) + + +#define MAXSCALEHEIGHT 256 // largest scale on largest view + +#define MAXVIEWWIDTH 320 + +#define MAPSIZE 64 // maps are 64*64 max +#define NORTH 0 +#define EAST 1 +#define SOUTH 2 +#define WEST 3 + + +#define STATUSLINES 40 + +#define SCREENSIZE (SCREENBWIDE*208) +#define PAGE1START 0 +#define PAGE2START (SCREENSIZE) +#define PAGE3START (SCREENSIZE*2u) +#define FREESTART (SCREENSIZE*3u) + + +#define PIXRADIUS 512 + +#define STARTAMMO 8 + + +// object flag values + +#define FL_SHOOTABLE 1 +#define FL_BONUS 2 +#define FL_NEVERMARK 4 +#define FL_VISABLE 8 +#define FL_ATTACKMODE 16 +#define FL_FIRSTATTACK 32 +#define FL_AMBUSH 64 +#define FL_NONMARK 128 + + +// +// sprite constants +// + +enum { + SPR_DEMO, + SPR_DEATHCAM, +// +// static sprites +// + SPR_STAT_0,SPR_STAT_1,SPR_STAT_2,SPR_STAT_3, + SPR_STAT_4,SPR_STAT_5,SPR_STAT_6,SPR_STAT_7, + + SPR_STAT_8,SPR_STAT_9,SPR_STAT_10,SPR_STAT_11, + SPR_STAT_12,SPR_STAT_13,SPR_STAT_14,SPR_STAT_15, + + SPR_STAT_16,SPR_STAT_17,SPR_STAT_18,SPR_STAT_19, + SPR_STAT_20,SPR_STAT_21,SPR_STAT_22,SPR_STAT_23, + + SPR_STAT_24,SPR_STAT_25,SPR_STAT_26,SPR_STAT_27, + SPR_STAT_28,SPR_STAT_29,SPR_STAT_30,SPR_STAT_31, + + SPR_STAT_32,SPR_STAT_33,SPR_STAT_34,SPR_STAT_35, + SPR_STAT_36,SPR_STAT_37,SPR_STAT_38,SPR_STAT_39, + + SPR_STAT_40,SPR_STAT_41,SPR_STAT_42,SPR_STAT_43, + SPR_STAT_44,SPR_STAT_45,SPR_STAT_46,SPR_STAT_47, + +#ifdef SPEAR + SPR_STAT_48,SPR_STAT_49,SPR_STAT_50,SPR_STAT_51, +#endif + +// +// guard +// + SPR_GRD_S_1,SPR_GRD_S_2,SPR_GRD_S_3,SPR_GRD_S_4, + SPR_GRD_S_5,SPR_GRD_S_6,SPR_GRD_S_7,SPR_GRD_S_8, + + SPR_GRD_W1_1,SPR_GRD_W1_2,SPR_GRD_W1_3,SPR_GRD_W1_4, + SPR_GRD_W1_5,SPR_GRD_W1_6,SPR_GRD_W1_7,SPR_GRD_W1_8, + + SPR_GRD_W2_1,SPR_GRD_W2_2,SPR_GRD_W2_3,SPR_GRD_W2_4, + SPR_GRD_W2_5,SPR_GRD_W2_6,SPR_GRD_W2_7,SPR_GRD_W2_8, + + SPR_GRD_W3_1,SPR_GRD_W3_2,SPR_GRD_W3_3,SPR_GRD_W3_4, + SPR_GRD_W3_5,SPR_GRD_W3_6,SPR_GRD_W3_7,SPR_GRD_W3_8, + + SPR_GRD_W4_1,SPR_GRD_W4_2,SPR_GRD_W4_3,SPR_GRD_W4_4, + SPR_GRD_W4_5,SPR_GRD_W4_6,SPR_GRD_W4_7,SPR_GRD_W4_8, + + SPR_GRD_PAIN_1,SPR_GRD_DIE_1,SPR_GRD_DIE_2,SPR_GRD_DIE_3, + SPR_GRD_PAIN_2,SPR_GRD_DEAD, + + SPR_GRD_SHOOT1,SPR_GRD_SHOOT2,SPR_GRD_SHOOT3, + +// +// dogs +// + SPR_DOG_W1_1,SPR_DOG_W1_2,SPR_DOG_W1_3,SPR_DOG_W1_4, + SPR_DOG_W1_5,SPR_DOG_W1_6,SPR_DOG_W1_7,SPR_DOG_W1_8, + + SPR_DOG_W2_1,SPR_DOG_W2_2,SPR_DOG_W2_3,SPR_DOG_W2_4, + SPR_DOG_W2_5,SPR_DOG_W2_6,SPR_DOG_W2_7,SPR_DOG_W2_8, + + SPR_DOG_W3_1,SPR_DOG_W3_2,SPR_DOG_W3_3,SPR_DOG_W3_4, + SPR_DOG_W3_5,SPR_DOG_W3_6,SPR_DOG_W3_7,SPR_DOG_W3_8, + + SPR_DOG_W4_1,SPR_DOG_W4_2,SPR_DOG_W4_3,SPR_DOG_W4_4, + SPR_DOG_W4_5,SPR_DOG_W4_6,SPR_DOG_W4_7,SPR_DOG_W4_8, + + SPR_DOG_DIE_1,SPR_DOG_DIE_2,SPR_DOG_DIE_3,SPR_DOG_DEAD, + SPR_DOG_JUMP1,SPR_DOG_JUMP2,SPR_DOG_JUMP3, + + + +// +// ss +// + SPR_SS_S_1,SPR_SS_S_2,SPR_SS_S_3,SPR_SS_S_4, + SPR_SS_S_5,SPR_SS_S_6,SPR_SS_S_7,SPR_SS_S_8, + + SPR_SS_W1_1,SPR_SS_W1_2,SPR_SS_W1_3,SPR_SS_W1_4, + SPR_SS_W1_5,SPR_SS_W1_6,SPR_SS_W1_7,SPR_SS_W1_8, + + SPR_SS_W2_1,SPR_SS_W2_2,SPR_SS_W2_3,SPR_SS_W2_4, + SPR_SS_W2_5,SPR_SS_W2_6,SPR_SS_W2_7,SPR_SS_W2_8, + + SPR_SS_W3_1,SPR_SS_W3_2,SPR_SS_W3_3,SPR_SS_W3_4, + SPR_SS_W3_5,SPR_SS_W3_6,SPR_SS_W3_7,SPR_SS_W3_8, + + SPR_SS_W4_1,SPR_SS_W4_2,SPR_SS_W4_3,SPR_SS_W4_4, + SPR_SS_W4_5,SPR_SS_W4_6,SPR_SS_W4_7,SPR_SS_W4_8, + + SPR_SS_PAIN_1,SPR_SS_DIE_1,SPR_SS_DIE_2,SPR_SS_DIE_3, + SPR_SS_PAIN_2,SPR_SS_DEAD, + + SPR_SS_SHOOT1,SPR_SS_SHOOT2,SPR_SS_SHOOT3, + +// +// mutant +// + SPR_MUT_S_1,SPR_MUT_S_2,SPR_MUT_S_3,SPR_MUT_S_4, + SPR_MUT_S_5,SPR_MUT_S_6,SPR_MUT_S_7,SPR_MUT_S_8, + + SPR_MUT_W1_1,SPR_MUT_W1_2,SPR_MUT_W1_3,SPR_MUT_W1_4, + SPR_MUT_W1_5,SPR_MUT_W1_6,SPR_MUT_W1_7,SPR_MUT_W1_8, + + SPR_MUT_W2_1,SPR_MUT_W2_2,SPR_MUT_W2_3,SPR_MUT_W2_4, + SPR_MUT_W2_5,SPR_MUT_W2_6,SPR_MUT_W2_7,SPR_MUT_W2_8, + + SPR_MUT_W3_1,SPR_MUT_W3_2,SPR_MUT_W3_3,SPR_MUT_W3_4, + SPR_MUT_W3_5,SPR_MUT_W3_6,SPR_MUT_W3_7,SPR_MUT_W3_8, + + SPR_MUT_W4_1,SPR_MUT_W4_2,SPR_MUT_W4_3,SPR_MUT_W4_4, + SPR_MUT_W4_5,SPR_MUT_W4_6,SPR_MUT_W4_7,SPR_MUT_W4_8, + + SPR_MUT_PAIN_1,SPR_MUT_DIE_1,SPR_MUT_DIE_2,SPR_MUT_DIE_3, + SPR_MUT_PAIN_2,SPR_MUT_DIE_4,SPR_MUT_DEAD, + + SPR_MUT_SHOOT1,SPR_MUT_SHOOT2,SPR_MUT_SHOOT3,SPR_MUT_SHOOT4, + +// +// officer +// + SPR_OFC_S_1,SPR_OFC_S_2,SPR_OFC_S_3,SPR_OFC_S_4, + SPR_OFC_S_5,SPR_OFC_S_6,SPR_OFC_S_7,SPR_OFC_S_8, + + SPR_OFC_W1_1,SPR_OFC_W1_2,SPR_OFC_W1_3,SPR_OFC_W1_4, + SPR_OFC_W1_5,SPR_OFC_W1_6,SPR_OFC_W1_7,SPR_OFC_W1_8, + + SPR_OFC_W2_1,SPR_OFC_W2_2,SPR_OFC_W2_3,SPR_OFC_W2_4, + SPR_OFC_W2_5,SPR_OFC_W2_6,SPR_OFC_W2_7,SPR_OFC_W2_8, + + SPR_OFC_W3_1,SPR_OFC_W3_2,SPR_OFC_W3_3,SPR_OFC_W3_4, + SPR_OFC_W3_5,SPR_OFC_W3_6,SPR_OFC_W3_7,SPR_OFC_W3_8, + + SPR_OFC_W4_1,SPR_OFC_W4_2,SPR_OFC_W4_3,SPR_OFC_W4_4, + SPR_OFC_W4_5,SPR_OFC_W4_6,SPR_OFC_W4_7,SPR_OFC_W4_8, + + SPR_OFC_PAIN_1,SPR_OFC_DIE_1,SPR_OFC_DIE_2,SPR_OFC_DIE_3, + SPR_OFC_PAIN_2,SPR_OFC_DIE_4,SPR_OFC_DEAD, + + SPR_OFC_SHOOT1,SPR_OFC_SHOOT2,SPR_OFC_SHOOT3, + +#ifndef SPEAR +// +// ghosts +// + SPR_BLINKY_W1,SPR_BLINKY_W2,SPR_PINKY_W1,SPR_PINKY_W2, + SPR_CLYDE_W1,SPR_CLYDE_W2,SPR_INKY_W1,SPR_INKY_W2, + +// +// hans +// + SPR_BOSS_W1,SPR_BOSS_W2,SPR_BOSS_W3,SPR_BOSS_W4, + SPR_BOSS_SHOOT1,SPR_BOSS_SHOOT2,SPR_BOSS_SHOOT3,SPR_BOSS_DEAD, + + SPR_BOSS_DIE1,SPR_BOSS_DIE2,SPR_BOSS_DIE3, + +// +// schabbs +// + SPR_SCHABB_W1,SPR_SCHABB_W2,SPR_SCHABB_W3,SPR_SCHABB_W4, + SPR_SCHABB_SHOOT1,SPR_SCHABB_SHOOT2, + + SPR_SCHABB_DIE1,SPR_SCHABB_DIE2,SPR_SCHABB_DIE3,SPR_SCHABB_DEAD, + SPR_HYPO1,SPR_HYPO2,SPR_HYPO3,SPR_HYPO4, + +// +// fake +// + SPR_FAKE_W1,SPR_FAKE_W2,SPR_FAKE_W3,SPR_FAKE_W4, + SPR_FAKE_SHOOT,SPR_FIRE1,SPR_FIRE2, + + SPR_FAKE_DIE1,SPR_FAKE_DIE2,SPR_FAKE_DIE3,SPR_FAKE_DIE4, + SPR_FAKE_DIE5,SPR_FAKE_DEAD, + +// +// hitler +// + SPR_MECHA_W1,SPR_MECHA_W2,SPR_MECHA_W3,SPR_MECHA_W4, + SPR_MECHA_SHOOT1,SPR_MECHA_SHOOT2,SPR_MECHA_SHOOT3,SPR_MECHA_DEAD, + + SPR_MECHA_DIE1,SPR_MECHA_DIE2,SPR_MECHA_DIE3, + + SPR_HITLER_W1,SPR_HITLER_W2,SPR_HITLER_W3,SPR_HITLER_W4, + SPR_HITLER_SHOOT1,SPR_HITLER_SHOOT2,SPR_HITLER_SHOOT3,SPR_HITLER_DEAD, + + SPR_HITLER_DIE1,SPR_HITLER_DIE2,SPR_HITLER_DIE3,SPR_HITLER_DIE4, + SPR_HITLER_DIE5,SPR_HITLER_DIE6,SPR_HITLER_DIE7, + +// +// giftmacher +// + SPR_GIFT_W1,SPR_GIFT_W2,SPR_GIFT_W3,SPR_GIFT_W4, + SPR_GIFT_SHOOT1,SPR_GIFT_SHOOT2, + + SPR_GIFT_DIE1,SPR_GIFT_DIE2,SPR_GIFT_DIE3,SPR_GIFT_DEAD, +#endif +// +// Rocket, smoke and small explosion +// + SPR_ROCKET_1,SPR_ROCKET_2,SPR_ROCKET_3,SPR_ROCKET_4, + SPR_ROCKET_5,SPR_ROCKET_6,SPR_ROCKET_7,SPR_ROCKET_8, + + SPR_SMOKE_1,SPR_SMOKE_2,SPR_SMOKE_3,SPR_SMOKE_4, + SPR_BOOM_1,SPR_BOOM_2,SPR_BOOM_3, + +// +// Angel of Death's DeathSparks(tm) +// +#ifdef SPEAR + SPR_HROCKET_1,SPR_HROCKET_2,SPR_HROCKET_3,SPR_HROCKET_4, + SPR_HROCKET_5,SPR_HROCKET_6,SPR_HROCKET_7,SPR_HROCKET_8, + + SPR_HSMOKE_1,SPR_HSMOKE_2,SPR_HSMOKE_3,SPR_HSMOKE_4, + SPR_HBOOM_1,SPR_HBOOM_2,SPR_HBOOM_3, + + SPR_SPARK1,SPR_SPARK2,SPR_SPARK3,SPR_SPARK4, +#endif + +#ifndef SPEAR +// +// gretel +// + SPR_GRETEL_W1,SPR_GRETEL_W2,SPR_GRETEL_W3,SPR_GRETEL_W4, + SPR_GRETEL_SHOOT1,SPR_GRETEL_SHOOT2,SPR_GRETEL_SHOOT3,SPR_GRETEL_DEAD, + + SPR_GRETEL_DIE1,SPR_GRETEL_DIE2,SPR_GRETEL_DIE3, + +// +// fat face +// + SPR_FAT_W1,SPR_FAT_W2,SPR_FAT_W3,SPR_FAT_W4, + SPR_FAT_SHOOT1,SPR_FAT_SHOOT2,SPR_FAT_SHOOT3,SPR_FAT_SHOOT4, + + SPR_FAT_DIE1,SPR_FAT_DIE2,SPR_FAT_DIE3,SPR_FAT_DEAD, + +// +// bj +// + SPR_BJ_W1,SPR_BJ_W2,SPR_BJ_W3,SPR_BJ_W4, + SPR_BJ_JUMP1,SPR_BJ_JUMP2,SPR_BJ_JUMP3,SPR_BJ_JUMP4, +#else +// +// THESE ARE FOR 'SPEAR OF DESTINY' +// + +// +// Trans Grosse +// + SPR_TRANS_W1,SPR_TRANS_W2,SPR_TRANS_W3,SPR_TRANS_W4, + SPR_TRANS_SHOOT1,SPR_TRANS_SHOOT2,SPR_TRANS_SHOOT3,SPR_TRANS_DEAD, + + SPR_TRANS_DIE1,SPR_TRANS_DIE2,SPR_TRANS_DIE3, + +// +// Wilhelm +// + SPR_WILL_W1,SPR_WILL_W2,SPR_WILL_W3,SPR_WILL_W4, + SPR_WILL_SHOOT1,SPR_WILL_SHOOT2,SPR_WILL_SHOOT3,SPR_WILL_SHOOT4, + + SPR_WILL_DIE1,SPR_WILL_DIE2,SPR_WILL_DIE3,SPR_WILL_DEAD, + +// +// UberMutant +// + SPR_UBER_W1,SPR_UBER_W2,SPR_UBER_W3,SPR_UBER_W4, + SPR_UBER_SHOOT1,SPR_UBER_SHOOT2,SPR_UBER_SHOOT3,SPR_UBER_SHOOT4, + + SPR_UBER_DIE1,SPR_UBER_DIE2,SPR_UBER_DIE3,SPR_UBER_DIE4, + SPR_UBER_DEAD, + +// +// Death Knight +// + SPR_DEATH_W1,SPR_DEATH_W2,SPR_DEATH_W3,SPR_DEATH_W4, + SPR_DEATH_SHOOT1,SPR_DEATH_SHOOT2,SPR_DEATH_SHOOT3,SPR_DEATH_SHOOT4, + + SPR_DEATH_DIE1,SPR_DEATH_DIE2,SPR_DEATH_DIE3,SPR_DEATH_DIE4, + SPR_DEATH_DIE5,SPR_DEATH_DIE6,SPR_DEATH_DEAD, + +// +// Ghost +// + SPR_SPECTRE_W1,SPR_SPECTRE_W2,SPR_SPECTRE_W3,SPR_SPECTRE_W4, + SPR_SPECTRE_F1,SPR_SPECTRE_F2,SPR_SPECTRE_F3,SPR_SPECTRE_F4, + +// +// Angel of Death +// + SPR_ANGEL_W1,SPR_ANGEL_W2,SPR_ANGEL_W3,SPR_ANGEL_W4, + SPR_ANGEL_SHOOT1,SPR_ANGEL_SHOOT2,SPR_ANGEL_TIRED1,SPR_ANGEL_TIRED2, + + SPR_ANGEL_DIE1,SPR_ANGEL_DIE2,SPR_ANGEL_DIE3,SPR_ANGEL_DIE4, + SPR_ANGEL_DIE5,SPR_ANGEL_DIE6,SPR_ANGEL_DIE7,SPR_ANGEL_DEAD, + +#endif + +// +// player attack frames +// + SPR_KNIFEREADY,SPR_KNIFEATK1,SPR_KNIFEATK2,SPR_KNIFEATK3, + SPR_KNIFEATK4, + + SPR_PISTOLREADY,SPR_PISTOLATK1,SPR_PISTOLATK2,SPR_PISTOLATK3, + SPR_PISTOLATK4, + + SPR_MACHINEGUNREADY,SPR_MACHINEGUNATK1,SPR_MACHINEGUNATK2,MACHINEGUNATK3, + SPR_MACHINEGUNATK4, + + SPR_CHAINREADY,SPR_CHAINATK1,SPR_CHAINATK2,SPR_CHAINATK3, + SPR_CHAINATK4, + + }; + + +/* +============================================================================= + + GLOBAL TYPES + +============================================================================= +*/ + +typedef long fixed; + +typedef enum { + di_north, + di_east, + di_south, + di_west +} controldir_t; + +typedef enum { + dr_normal, + dr_lock1, + dr_lock2, + dr_lock3, + dr_lock4, + dr_elevator +} door_t; + +typedef enum { + ac_badobject = -1, + ac_no, + ac_yes, + ac_allways +} activetype; + +typedef enum { + nothing, + playerobj, + inertobj, + guardobj, + officerobj, + ssobj, + dogobj, + bossobj, + schabbobj, + fakeobj, + mechahitlerobj, + mutantobj, + needleobj, + fireobj, + bjobj, + ghostobj, + realhitlerobj, + gretelobj, + giftobj, + fatobj, + rocketobj, + + spectreobj, + angelobj, + transobj, + uberobj, + willobj, + deathobj, + hrocketobj, + sparkobj +} classtype; + +typedef enum { + dressing, + block, + bo_gibs, + bo_alpo, + bo_firstaid, + bo_key1, + bo_key2, + bo_key3, + bo_key4, + bo_cross, + bo_chalice, + bo_bible, + bo_crown, + bo_clip, + bo_clip2, + bo_machinegun, + bo_chaingun, + bo_food, + bo_fullheal, + bo_25clip, + bo_spear +} stat_t; + +typedef enum { + east, + northeast, + north, + northwest, + west, + southwest, + south, + southeast, + nodir +} dirtype; + + +#define NUMENEMIES 22 +typedef enum { + en_guard, + en_officer, + en_ss, + en_dog, + en_boss, + en_schabbs, + en_fake, + en_hitler, + en_mutant, + en_blinky, + en_clyde, + en_pinky, + en_inky, + en_gretel, + en_gift, + en_fat, + en_spectre, + en_angel, + en_trans, + en_uber, + en_will, + en_death +} enemy_t; + + +typedef struct statestruct +{ + boolean rotate; + int shapenum; // a shapenum of -1 means get from ob->temp1 + int tictime; + void (*think) (),(*action) (); + struct statestruct *next; +} statetype; + + +//--------------------- +// +// trivial actor structure +// +//--------------------- + +typedef struct statstruct +{ + byte tilex,tiley; + byte *visspot; + int shapenum; // if shapenum == -1 the obj has been removed + byte flags; + byte itemnumber; +} statobj_t; + + +//--------------------- +// +// door actor structure +// +//--------------------- + +typedef struct doorstruct +{ + byte tilex,tiley; + boolean vertical; + byte lock; + enum {dr_open,dr_closed,dr_opening,dr_closing} action; + int ticcount; +} doorobj_t; + + +//-------------------- +// +// thinking actor structure +// +//-------------------- + +typedef struct objstruct +{ + activetype active; + int ticcount; + classtype obclass; + statetype *state; + + byte flags; // FL_SHOOTABLE, etc + + long distance; // if negative, wait for that door to open + dirtype dir; + + fixed x,y; + unsigned tilex,tiley; + byte areanumber; + + int viewx; + unsigned viewheight; + fixed transx,transy; // in global coord + + int angle; + int hitpoints; + long speed; + + int temp1,temp2,temp3; + struct objstruct *next,*prev; +} objtype; + + +#define NUMBUTTONS 8 +enum { + bt_nobutton=-1, + bt_attack=0, + bt_strafe, + bt_run, + bt_use, + bt_readyknife, + bt_readypistol, + bt_readymachinegun, + bt_readychaingun +}; + + +#define NUMWEAPONS 5 +typedef enum { + wp_knife, + wp_pistol, + wp_machinegun, + wp_chaingun +} weapontype; + + +typedef enum { + gd_baby, + gd_easy, + gd_medium, + gd_hard +}; + +//--------------- +// +// gamestate structure +// +//--------------- + +typedef struct +{ + int difficulty; + int mapon; + long oldscore,score,nextextra; + int lives; + int health; + int ammo; + int keys; + weapontype bestweapon,weapon,chosenweapon; + + int faceframe; + int attackframe,attackcount,weaponframe; + + int episode,secretcount,treasurecount,killcount, + secrettotal,treasuretotal,killtotal; + long TimeCount; + long killx,killy; + boolean victoryflag; // set during victory animations +} gametype; + + +typedef enum { + ex_stillplaying, + ex_completed, + ex_died, + ex_warped, + ex_resetgame, + ex_loadedgame, + ex_victorious, + ex_abort, + ex_demodone, + ex_secretlevel +} exit_t; + + +/* +============================================================================= + + WL_MAIN DEFINITIONS + +============================================================================= +*/ + +extern boolean MS_CheckParm (char far *string); + +extern char str[80],str2[20]; +extern int tedlevelnum; +extern boolean tedlevel; +extern boolean nospr; +extern boolean IsA386; + +extern byte far *scalermemory; + +extern fixed focallength; +extern unsigned viewangles; +extern unsigned screenofs; +extern int viewwidth; +extern int viewheight; +extern int centerx; +extern int shootdelta; + +extern int dirangle[9]; + +extern boolean startgame,loadedgame,virtualreality; +extern int mouseadjustment; +// +// math tables +// +extern int pixelangle[MAXVIEWWIDTH]; +extern long far finetangent[FINEANGLES/4]; +extern fixed far sintable[],far *costable; + +// +// derived constants +// +extern fixed scale,maxslope; +extern long heightnumerator; +extern int minheightdiv; + +extern char configname[13]; + + + +void HelpScreens (void); +void OrderingInfo (void); +void TEDDeath(void); +void Quit (char *error); +void CalcProjection (long focal); +boolean SetViewSize (unsigned width, unsigned height); +void NewGame (int difficulty,int episode); +void NewViewSize (int width); +boolean LoadTheGame(int file,int x,int y); +boolean SaveTheGame(int file,int x,int y); +void ShowViewSize (int width); +void ShutdownId (void); + + +/* +============================================================================= + + WL_GAME DEFINITIONS + +============================================================================= +*/ + + +extern boolean ingame,fizzlein; +extern unsigned latchpics[NUMLATCHPICS]; +extern gametype gamestate; +extern int doornum; + +extern char demoname[13]; + +extern long spearx,speary; +extern unsigned spearangle; +extern boolean spearflag; + + +void DrawPlayBorder (void); +void ScanInfoPlane (void); +void SetupGameLevel (void); +void NormalScreen (void); +void DrawPlayScreen (void); +void FizzleOut (void); +void GameLoop (void); +void ClearMemory (void); +void PlayDemo (int demonumber); +void RecordDemo (void); +void DrawAllPlayBorder (void); +void DrawHighScores(void); +void DrawAllPlayBorderSides (void); + + +// JAB +#define PlaySoundLocTile(s,tx,ty) PlaySoundLocGlobal(s,(((long)(tx) << TILESHIFT) + (1L << (TILESHIFT - 1))),(((long)ty << TILESHIFT) + (1L << (TILESHIFT - 1)))) +#define PlaySoundLocActor(s,ob) PlaySoundLocGlobal(s,(ob)->x,(ob)->y) +void PlaySoundLocGlobal(word s,fixed gx,fixed gy); +void UpdateSoundLoc(void); + + +/* +============================================================================= + + WL_PLAY DEFINITIONS + +============================================================================= +*/ + +#ifdef SPEAR +extern long funnyticount; // FOR FUNNY BJ FACE +#endif + +extern exit_t playstate; + +extern boolean madenoise; + +extern objtype objlist[MAXACTORS],*new,*obj,*player,*lastobj, + *objfreelist,*killerobj; +extern statobj_t statobjlist[MAXSTATS],*laststatobj; +extern doorobj_t doorobjlist[MAXDOORS],*lastdoorobj; + +extern unsigned farmapylookup[MAPSIZE]; +extern byte *nearmapylookup[MAPSIZE]; + +extern byte tilemap[MAPSIZE][MAPSIZE]; // wall values only +extern byte spotvis[MAPSIZE][MAPSIZE]; +extern objtype *actorat[MAPSIZE][MAPSIZE]; + +#define UPDATESIZE (UPDATEWIDE*UPDATEHIGH) +extern byte update[UPDATESIZE]; + +extern boolean singlestep,godmode,noclip; +extern int extravbls; + +// +// control info +// +extern boolean mouseenabled,joystickenabled,joypadenabled,joystickprogressive; +extern int joystickport; +extern int dirscan[4]; +extern int buttonscan[NUMBUTTONS]; +extern int buttonmouse[4]; +extern int buttonjoy[4]; + +extern boolean buttonheld[NUMBUTTONS]; + +extern int viewsize; + +// +// curent user input +// +extern int controlx,controly; // range from -100 to 100 +extern boolean buttonstate[NUMBUTTONS]; + +extern boolean demorecord,demoplayback; +extern char far *demoptr, far *lastdemoptr; +extern memptr demobuffer; + + + +void InitRedShifts (void); +void FinishPaletteShifts (void); + +void CenterWindow(word w,word h); +void InitActorList (void); +void GetNewActor (void); +void RemoveObj (objtype *gone); +void PollControls (void); +void StopMusic(void); +void StartMusic(void); +void PlayLoop (void); +void StartDamageFlash (int damage); +void StartBonusFlash (void); + +/* +============================================================================= + + WL_INTER + +============================================================================= +*/ + +void IntroScreen (void); +void PreloadGraphics(void); +void LevelCompleted (void); +void CheckHighScore (long score,word other); +void Victory (void); +void ClearSplitVWB (void); + + +/* +============================================================================= + + WL_DEBUG + +============================================================================= +*/ + +int DebugKeys (void); +void PicturePause (void); + + +/* +============================================================================= + + WL_DRAW DEFINITIONS + +============================================================================= +*/ + +extern unsigned screenloc[3]; +extern unsigned freelatch; + +extern long lasttimecount; +extern long frameon; +extern boolean fizzlein; + +extern unsigned wallheight[MAXVIEWWIDTH]; + +extern fixed tileglobal; +extern fixed focallength; +extern fixed mindist; + +// +// math tables +// +extern int pixelangle[MAXVIEWWIDTH]; +extern long far finetangent[FINEANGLES/4]; +extern fixed far sintable[],far *costable; + +// +// derived constants +// +extern fixed scale; +extern long heightnumerator,mindist; + +// +// refresh variables +// +extern fixed viewx,viewy; // the focal point +extern int viewangle; +extern fixed viewsin,viewcos; + +extern long postsource; +extern unsigned postx; +extern unsigned postwidth; + + +extern int horizwall[],vertwall[]; + +extern unsigned pwallpos; + + +fixed FixedByFrac (fixed a, fixed b); +void TransformActor (objtype *ob); +void BuildTables (void); +void ClearScreen (void); +int CalcRotate (objtype *ob); +void DrawScaleds (void); +void CalcTics (void); +void FixOfs (void); +void ThreeDRefresh (void); +void FarScalePost (void); + +/* +============================================================================= + + WL_STATE DEFINITIONS + +============================================================================= +*/ +#define TURNTICS 10 +#define SPDPATROL 512 +#define SPDDOG 1500 + + +extern dirtype opposite[9]; +extern dirtype diagonal[9][9]; + + +void InitHitRect (objtype *ob, unsigned radius); +void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state); +void NewState (objtype *ob, statetype *state); + +boolean TryWalk (objtype *ob); +void SelectChaseDir (objtype *ob); +void SelectDodgeDir (objtype *ob); +void SelectRunDir (objtype *ob); +void MoveObj (objtype *ob, long move); +boolean SightPlayer (objtype *ob); + +void KillActor (objtype *ob); +void DamageActor (objtype *ob, unsigned damage); + +boolean CheckLine (objtype *ob); +boolean CheckSight (objtype *ob); + + +/* +============================================================================= + + WL_SCALE DEFINITIONS + +============================================================================= +*/ + + +#define COMPSCALECODESTART (65*4) // offset to start of code in comp scaler + +typedef struct +{ + unsigned codeofs[65]; + unsigned width[65]; + byte code[]; +} t_compscale; + +typedef struct +{ + unsigned leftpix,rightpix; + unsigned dataofs[64]; +// table data after dataofs[rightpix-leftpix+1] +} t_compshape; + + +extern t_compscale _seg *scaledirectory[MAXSCALEHEIGHT+1]; +extern long fullscalefarcall[MAXSCALEHEIGHT+1]; + +extern byte bitmasks1[8][8]; +extern byte bitmasks2[8][8]; +extern unsigned wordmasks[8][8]; + +extern byte mapmasks1[4][8]; +extern byte mapmasks2[4][8]; +extern byte mapmasks3[4][8]; + +extern int maxscale,maxscaleshl2; + +extern boolean insetupscaling; + +void SetupScaling (int maxscaleheight); +void ScaleShape (int xcenter, int shapenum, unsigned height); +void SimpleScaleShape (int xcenter, int shapenum, unsigned height); + +/* +============================================================================= + + WL_AGENT DEFINITIONS + +============================================================================= +*/ + +// +// player state info +// +extern boolean running; +extern long thrustspeed; +extern unsigned plux,pluy; // player coordinates scaled to unsigned + +extern int anglefrac; +extern int facecount; + +void SpawnPlayer (int tilex, int tiley, int dir); +void DrawFace (void); +void DrawHealth (void); +void TakeDamage (int points,objtype *attacker); +void HealSelf (int points); +void DrawLevel (void); +void DrawLives (void); +void GiveExtraMan (void); +void DrawScore (void); +void GivePoints (long points); +void DrawWeapon (void); +void DrawKeys (void); +void GiveWeapon (int weapon); +void DrawAmmo (void); +void GiveAmmo (int ammo); +void GiveKey (int key); +void GetBonus (statobj_t *check); + +void Thrust (int angle, long speed); + +/* +============================================================================= + + WL_ACT1 DEFINITIONS + +============================================================================= +*/ + +extern doorobj_t doorobjlist[MAXDOORS],*lastdoorobj; +extern int doornum; + +extern unsigned doorposition[MAXDOORS],pwallstate; + +extern byte far areaconnect[NUMAREAS][NUMAREAS]; + +extern boolean areabyplayer[NUMAREAS]; + +extern unsigned pwallstate; +extern unsigned pwallpos; // amount a pushable wall has been moved (0-63) +extern unsigned pwallx,pwally; +extern int pwalldir; + + +void InitDoorList (void); +void InitStaticList (void); +void SpawnStatic (int tilex, int tiley, int type); +void SpawnDoor (int tilex, int tiley, boolean vertical, int lock); +void MoveDoors (void); +void MovePWalls (void); +void OpenDoor (int door); +void PlaceItemType (int itemtype, int tilex, int tiley); +void PushWall (int checkx, int checky, int dir); +void OperateDoor (int door); +void InitAreas (void); + +/* +============================================================================= + + WL_ACT2 DEFINITIONS + +============================================================================= +*/ + +#define s_nakedbody s_static10 + +extern statetype s_grddie1; +extern statetype s_dogdie1; +extern statetype s_ofcdie1; +extern statetype s_mutdie1; +extern statetype s_ssdie1; +extern statetype s_bossdie1; +extern statetype s_schabbdie1; +extern statetype s_fakedie1; +extern statetype s_mechadie1; +extern statetype s_hitlerdie1; +extern statetype s_greteldie1; +extern statetype s_giftdie1; +extern statetype s_fatdie1; + +extern statetype s_spectredie1; +extern statetype s_angeldie1; +extern statetype s_transdie0; +extern statetype s_uberdie0; +extern statetype s_willdie1; +extern statetype s_deathdie1; + + +extern statetype s_grdchase1; +extern statetype s_dogchase1; +extern statetype s_ofcchase1; +extern statetype s_sschase1; +extern statetype s_mutchase1; +extern statetype s_bosschase1; +extern statetype s_schabbchase1; +extern statetype s_fakechase1; +extern statetype s_mechachase1; +extern statetype s_gretelchase1; +extern statetype s_giftchase1; +extern statetype s_fatchase1; + +extern statetype s_spectrechase1; +extern statetype s_angelchase1; +extern statetype s_transchase1; +extern statetype s_uberchase1; +extern statetype s_willchase1; +extern statetype s_deathchase1; + +extern statetype s_blinkychase1; +extern statetype s_hitlerchase1; + +extern statetype s_grdpain; +extern statetype s_grdpain1; +extern statetype s_ofcpain; +extern statetype s_ofcpain1; +extern statetype s_sspain; +extern statetype s_sspain1; +extern statetype s_mutpain; +extern statetype s_mutpain1; + +extern statetype s_deathcam; + +extern statetype s_schabbdeathcam2; +extern statetype s_hitlerdeathcam2; +extern statetype s_giftdeathcam2; +extern statetype s_fatdeathcam2; + +void SpawnStand (enemy_t which, int tilex, int tiley, int dir); +void SpawnPatrol (enemy_t which, int tilex, int tiley, int dir); +void KillActor (objtype *ob); + +void US_ControlPanel(byte); + +void SpawnDeadGuard (int tilex, int tiley); +void SpawnBoss (int tilex, int tiley); +void SpawnGretel (int tilex, int tiley); +void SpawnTrans (int tilex, int tiley); +void SpawnUber (int tilex, int tiley); +void SpawnWill (int tilex, int tiley); +void SpawnDeath (int tilex, int tiley); +void SpawnAngel (int tilex, int tiley); +void SpawnSpectre (int tilex, int tiley); +void SpawnGhosts (int which, int tilex, int tiley); +void SpawnSchabbs (int tilex, int tiley); +void SpawnGift (int tilex, int tiley); +void SpawnFat (int tilex, int tiley); +void SpawnFakeHitler (int tilex, int tiley); +void SpawnHitler (int tilex, int tiley); + +/* +============================================================================= + + WL_TEXT DEFINITIONS + +============================================================================= +*/ + +extern char helpfilename[],endfilename[]; + +extern void HelpScreens(void); +extern void EndText(void); diff --git a/src/lib/hb/c3_draw.c b/src/lib/hb/draw/c3_draw.c similarity index 100% rename from src/lib/hb/c3_draw.c rename to src/lib/hb/draw/c3_draw.c diff --git a/src/lib/hb/c6_draw.c b/src/lib/hb/draw/c6_draw.c similarity index 100% rename from src/lib/hb/c6_draw.c rename to src/lib/hb/draw/c6_draw.c diff --git a/src/lib/hb/draw/wl_draw.c b/src/lib/hb/draw/wl_draw.c new file mode 100755 index 00000000..3c32e39e --- /dev/null +++ b/src/lib/hb/draw/wl_draw.c @@ -0,0 +1,1419 @@ +// WL_DRAW.C + +#include "WL_DEF.H" +#include +#pragma hdrstop + +//#define DEBUGWALLS +//#define DEBUGTICS + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +// the door is the last picture before the sprites +#define DOORWALL (PMSpriteStart-8) + +#define ACTORSIZE 0x4000 + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + +#ifdef DEBUGWALLS +unsigned screenloc[3]= {0,0,0}; +#else +unsigned screenloc[3]= {PAGE1START,PAGE2START,PAGE3START}; +#endif +unsigned freelatch = FREESTART; + +long lasttimecount; +long frameon; + +unsigned wallheight[MAXVIEWWIDTH]; + +fixed tileglobal = TILEGLOBAL; +fixed mindist = MINDIST; + + +// +// math tables +// +int pixelangle[MAXVIEWWIDTH]; +long far finetangent[FINEANGLES/4]; +fixed far sintable[ANGLES+ANGLES/4],far *costable = sintable+(ANGLES/4); + +// +// refresh variables +// +fixed viewx,viewy; // the focal point +int viewangle; +fixed viewsin,viewcos; + + + +fixed FixedByFrac (fixed a, fixed b); +void TransformActor (objtype *ob); +void BuildTables (void); +void ClearScreen (void); +int CalcRotate (objtype *ob); +void DrawScaleds (void); +void CalcTics (void); +void FixOfs (void); +void ThreeDRefresh (void); + + + +// +// wall optimization variables +// +int lastside; // true for vertical +long lastintercept; +int lasttilehit; + + +// +// ray tracing variables +// +int focaltx,focalty,viewtx,viewty; + +int midangle,angle; +unsigned xpartial,ypartial; +unsigned xpartialup,xpartialdown,ypartialup,ypartialdown; +unsigned xinttile,yinttile; + +unsigned tilehit; +unsigned pixx; + +int xtile,ytile; +int xtilestep,ytilestep; +long xintercept,yintercept; +long xstep,ystep; + +int horizwall[MAXWALLTILES],vertwall[MAXWALLTILES]; + + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +void AsmRefresh (void); // in WL_DR_A.ASM + +/* +============================================================================ + + 3 - D DEFINITIONS + +============================================================================ +*/ + + +//========================================================================== + + +/* +======================== += += FixedByFrac += += multiply a 16/16 bit, 2's complement fixed point number by a 16 bit += fraction, passed as a signed magnitude 32 bit number += +======================== +*/ + +#pragma warn -rvl // I stick the return value in with ASMs + +fixed FixedByFrac (fixed a, fixed b) +{ +// +// setup +// +asm mov si,[WORD PTR b+2] // sign of result = sign of fraction + +asm mov ax,[WORD PTR a] +asm mov cx,[WORD PTR a+2] + +asm or cx,cx +asm jns aok: // negative? +asm neg cx +asm neg ax +asm sbb cx,0 +asm xor si,0x8000 // toggle sign of result +aok: + +// +// multiply cx:ax by bx +// +asm mov bx,[WORD PTR b] +asm mul bx // fraction*fraction +asm mov di,dx // di is low word of result +asm mov ax,cx // +asm mul bx // units*fraction +asm add ax,di +asm adc dx,0 + +// +// put result dx:ax in 2's complement +// +asm test si,0x8000 // is the result negative? +asm jz ansok: +asm neg dx +asm neg ax +asm sbb dx,0 + +ansok:; + +} + +#pragma warn +rvl + +//========================================================================== + +/* +======================== += += TransformActor += += Takes paramaters: += gx,gy : globalx/globaly of point += += globals: += viewx,viewy : point of view += viewcos,viewsin : sin/cos of viewangle += scale : conversion from global value to screen value += += sets: += screenx,transx,transy,screenheight: projected edge location and size += +======================== +*/ + + +// +// transform actor +// +void TransformActor (objtype *ob) +{ + int ratio; + fixed gx,gy,gxt,gyt,nx,ny; + long temp; + +// +// translate point to view centered coordinates +// + gx = ob->x-viewx; + gy = ob->y-viewy; + +// +// calculate newx +// + gxt = FixedByFrac(gx,viewcos); + gyt = FixedByFrac(gy,viewsin); + nx = gxt-gyt-ACTORSIZE; // fudge the shape forward a bit, because + // the midpoint could put parts of the shape + // into an adjacent wall + +// +// calculate newy +// + gxt = FixedByFrac(gx,viewsin); + gyt = FixedByFrac(gy,viewcos); + ny = gyt+gxt; + +// +// calculate perspective ratio +// + ob->transx = nx; + ob->transy = ny; + + if (nxviewheight = 0; + return; + } + + ob->viewx = centerx + ny*scale/nx; // DEBUG: use assembly divide + +// +// calculate height (heightnumerator/(nx>>8)) +// + asm mov ax,[WORD PTR heightnumerator] + asm mov dx,[WORD PTR heightnumerator+2] + asm idiv [WORD PTR nx+1] // nx>>8 + asm mov [WORD PTR temp],ax + asm mov [WORD PTR temp+2],dx + + ob->viewheight = temp; +} + +//========================================================================== + +/* +======================== += += TransformTile += += Takes paramaters: += tx,ty : tile the object is centered in += += globals: += viewx,viewy : point of view += viewcos,viewsin : sin/cos of viewangle += scale : conversion from global value to screen value += += sets: += screenx,transx,transy,screenheight: projected edge location and size += += Returns true if the tile is withing getting distance += +======================== +*/ + +boolean TransformTile (int tx, int ty, int *dispx, int *dispheight) +{ + int ratio; + fixed gx,gy,gxt,gyt,nx,ny; + long temp; + +// +// translate point to view centered coordinates +// + gx = ((long)tx<>8)) +// + asm mov ax,[WORD PTR heightnumerator] + asm mov dx,[WORD PTR heightnumerator+2] + asm idiv [WORD PTR nx+1] // nx>>8 + asm mov [WORD PTR temp],ax + asm mov [WORD PTR temp+2],dx + + *dispheight = temp; + +// +// see if it should be grabbed +// + if (nx-TILEGLOBAL/2 && ny>8)) + // + if (nx>8 +} + + +//========================================================================== + +/* +=================== += += ScalePost += +=================== +*/ + +long postsource; +unsigned postx; +unsigned postwidth; + +void near ScalePost (void) // VGA version +{ + asm mov ax,SCREENSEG + asm mov es,ax + + asm mov bx,[postx] + asm shl bx,1 + asm mov bp,WORD PTR [wallheight+bx] // fractional height (low 3 bits frac) + asm and bp,0xfff8 // bp = heightscaler*4 + asm shr bp,1 + asm cmp bp,[maxscaleshl2] + asm jle heightok + asm mov bp,[maxscaleshl2] +heightok: + asm add bp,OFFSET fullscalefarcall + // + // scale a byte wide strip of wall + // + asm mov bx,[postx] + asm mov di,bx + asm shr di,1 // X in bytes + asm shr di,1 + asm add di,[bufferofs] + + asm and bx,3 + /* begin 8086 hack + asm shl bx,3 + */ + asm push cx + asm mov cl,3 + asm shl bx,cl + asm pop cx + /* end 8086 hack */ + asm add bx,[postwidth] + + asm mov al,BYTE PTR [mapmasks1-1+bx] // -1 because no widths of 0 + asm mov dx,SC_INDEX+1 + asm out dx,al // set bit mask register + asm lds si,DWORD PTR [postsource] + asm call DWORD PTR [bp] // scale the line of pixels + + asm mov al,BYTE PTR [ss:mapmasks2-1+bx] // -1 because no widths of 0 + asm or al,al + asm jz nomore + + // + // draw a second byte for vertical strips that cross two bytes + // + asm inc di + asm out dx,al // set bit mask register + asm call DWORD PTR [bp] // scale the line of pixels + + asm mov al,BYTE PTR [ss:mapmasks3-1+bx] // -1 because no widths of 0 + asm or al,al + asm jz nomore + // + // draw a third byte for vertical strips that cross three bytes + // + asm inc di + asm out dx,al // set bit mask register + asm call DWORD PTR [bp] // scale the line of pixels + + +nomore: + asm mov ax,ss + asm mov ds,ax +} + +void FarScalePost (void) // just so other files can call +{ + ScalePost (); +} + + +/* +==================== += += HitVertWall += += tilehit bit 7 is 0, because it's not a door tile += if bit 6 is 1 and the adjacent tile is a door tile, use door side pic += +==================== +*/ + +void HitVertWall (void) +{ + int wallpic; + unsigned texture; + + texture = (yintercept>>4)&0xfc0; + if (xtilestep == -1) + { + texture = 0xfc0-texture; + xintercept += TILEGLOBAL; + } + wallheight[pixx] = CalcHeight(); + + if (lastside==1 && lastintercept == xtile && lasttilehit == tilehit) + { + // in the same wall type as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + // new wall + if (lastside != -1) // if not the first scaled post + ScalePost (); + + lastside = true; + lastintercept = xtile; + + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + if (tilehit & 0x40) + { // check for adjacent doors + ytile = yintercept>>TILESHIFT; + if ( tilemap[xtile-xtilestep][ytile]&0x80 ) + wallpic = DOORWALL+3; + else + wallpic = vertwall[tilehit & ~0x40]; + } + else + wallpic = vertwall[tilehit]; + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); + (unsigned)postsource = texture; + + } +} + + +/* +==================== += += HitHorizWall += += tilehit bit 7 is 0, because it's not a door tile += if bit 6 is 1 and the adjacent tile is a door tile, use door side pic += +==================== +*/ + +void HitHorizWall (void) +{ + int wallpic; + unsigned texture; + + texture = (xintercept>>4)&0xfc0; + if (ytilestep == -1) + yintercept += TILEGLOBAL; + else + texture = 0xfc0-texture; + wallheight[pixx] = CalcHeight(); + + if (lastside==0 && lastintercept == ytile && lasttilehit == tilehit) + { + // in the same wall type as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + // new wall + if (lastside != -1) // if not the first scaled post + ScalePost (); + + lastside = 0; + lastintercept = ytile; + + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + if (tilehit & 0x40) + { // check for adjacent doors + xtile = xintercept>>TILESHIFT; + if ( tilemap[xtile][ytile-ytilestep]&0x80 ) + wallpic = DOORWALL+2; + else + wallpic = horizwall[tilehit & ~0x40]; + } + else + wallpic = horizwall[tilehit]; + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); + (unsigned)postsource = texture; + } + +} + +//========================================================================== + +/* +==================== += += HitHorizDoor += +==================== +*/ + +void HitHorizDoor (void) +{ + unsigned texture,doorpage,doornum; + + doornum = tilehit&0x7f; + texture = ( (xintercept-doorposition[doornum]) >> 4) &0xfc0; + + wallheight[pixx] = CalcHeight(); + + if (lasttilehit == tilehit) + { + // in the same door as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + if (lastside != -1) // if not the first scaled post + ScalePost (); // draw last post + // first pixel in this door + lastside = 2; + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + switch (doorobjlist[doornum].lock) + { + case dr_normal: + doorpage = DOORWALL; + break; + case dr_lock1: + case dr_lock2: + case dr_lock3: + case dr_lock4: + doorpage = DOORWALL+6; + break; + case dr_elevator: + doorpage = DOORWALL+4; + break; + } + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage); + (unsigned)postsource = texture; + } +} + +//========================================================================== + +/* +==================== += += HitVertDoor += +==================== +*/ + +void HitVertDoor (void) +{ + unsigned texture,doorpage,doornum; + + doornum = tilehit&0x7f; + texture = ( (yintercept-doorposition[doornum]) >> 4) &0xfc0; + + wallheight[pixx] = CalcHeight(); + + if (lasttilehit == tilehit) + { + // in the same door as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + if (lastside != -1) // if not the first scaled post + ScalePost (); // draw last post + // first pixel in this door + lastside = 2; + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + switch (doorobjlist[doornum].lock) + { + case dr_normal: + doorpage = DOORWALL; + break; + case dr_lock1: + case dr_lock2: + case dr_lock3: + case dr_lock4: + doorpage = DOORWALL+6; + break; + case dr_elevator: + doorpage = DOORWALL+4; + break; + } + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(doorpage+1); + (unsigned)postsource = texture; + } +} + +//========================================================================== + + +/* +==================== += += HitHorizPWall += += A pushable wall in action has been hit += +==================== +*/ + +void HitHorizPWall (void) +{ + int wallpic; + unsigned texture,offset; + + texture = (xintercept>>4)&0xfc0; + offset = pwallpos<<10; + if (ytilestep == -1) + yintercept += TILEGLOBAL-offset; + else + { + texture = 0xfc0-texture; + yintercept += offset; + } + + wallheight[pixx] = CalcHeight(); + + if (lasttilehit == tilehit) + { + // in the same wall type as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + // new wall + if (lastside != -1) // if not the first scaled post + ScalePost (); + + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + wallpic = horizwall[tilehit&63]; + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); + (unsigned)postsource = texture; + } + +} + + +/* +==================== += += HitVertPWall += += A pushable wall in action has been hit += +==================== +*/ + +void HitVertPWall (void) +{ + int wallpic; + unsigned texture,offset; + + texture = (yintercept>>4)&0xfc0; + offset = pwallpos<<10; + if (xtilestep == -1) + { + xintercept += TILEGLOBAL-offset; + texture = 0xfc0-texture; + } + else + xintercept += offset; + + wallheight[pixx] = CalcHeight(); + + if (lasttilehit == tilehit) + { + // in the same wall type as last time, so check for optimized draw + if (texture == (unsigned)postsource) + { + // wide scale + postwidth++; + wallheight[pixx] = wallheight[pixx-1]; + return; + } + else + { + ScalePost (); + (unsigned)postsource = texture; + postwidth = 1; + postx = pixx; + } + } + else + { + // new wall + if (lastside != -1) // if not the first scaled post + ScalePost (); + + lasttilehit = tilehit; + postx = pixx; + postwidth = 1; + + wallpic = vertwall[tilehit&63]; + + *( ((unsigned *)&postsource)+1) = (unsigned)PM_GetPage(wallpic); + (unsigned)postsource = texture; + } + +} + +//========================================================================== + +//========================================================================== + +#if 0 +/* +===================== += += ClearScreen += +===================== +*/ + +void ClearScreen (void) +{ + unsigned floor=egaFloor[gamestate.episode*10+mapon], + ceiling=egaCeiling[gamestate.episode*10+mapon]; + + // + // clear the screen + // +asm mov dx,GC_INDEX +asm mov ax,GC_MODE + 256*2 // read mode 0, write mode 2 +asm out dx,ax +asm mov ax,GC_BITMASK + 255*256 +asm out dx,ax + +asm mov dx,40 +asm mov ax,[viewwidth] +asm shr ax,1 +asm shr ax,1 +asm shr ax,1 +asm sub dx,ax // dx = 40-viewwidth/8 + +asm mov bx,[viewwidth] +asm shr bx,1 // bl = viewwidth/16 +asm shr bx,1 +asm shr bx,1 +asm shr bx,1 +asm mov bh,BYTE PTR [viewheight] +asm shr bh,1 // half height + +asm mov ax,[ceiling] +asm mov es,[screenseg] +asm mov di,[bufferofs] + +toploop: +asm mov cl,bl +asm rep stosw +asm add di,dx +asm dec bh +asm jnz toploop + +asm mov bh,BYTE PTR [viewheight] +asm shr bh,1 // half height +asm mov ax,[floor] + +bottomloop: +asm mov cl,bl +asm rep stosw +asm add di,dx +asm dec bh +asm jnz bottomloop + + +asm mov dx,GC_INDEX +asm mov ax,GC_MODE + 256*10 // read mode 1, write mode 2 +asm out dx,ax +asm mov al,GC_BITMASK +asm out dx,al + +} +#endif +//========================================================================== + +unsigned vgaCeiling[]= +{ +#ifndef SPEAR + 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xbfbf, + 0x4e4e,0x4e4e,0x4e4e,0x1d1d,0x8d8d,0x4e4e,0x1d1d,0x2d2d,0x1d1d,0x8d8d, + 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x2d2d,0xdddd,0x1d1d,0x1d1d,0x9898, + + 0x1d1d,0x9d9d,0x2d2d,0xdddd,0xdddd,0x9d9d,0x2d2d,0x4d4d,0x1d1d,0xdddd, + 0x7d7d,0x1d1d,0x2d2d,0x2d2d,0xdddd,0xd7d7,0x1d1d,0x1d1d,0x1d1d,0x2d2d, + 0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xdddd,0xdddd,0x7d7d,0xdddd,0xdddd,0xdddd +#else + 0x6f6f,0x4f4f,0x1d1d,0xdede,0xdfdf,0x2e2e,0x7f7f,0x9e9e,0xaeae,0x7f7f, + 0x1d1d,0xdede,0xdfdf,0xdede,0xdfdf,0xdede,0xe1e1,0xdcdc,0x2e2e,0x1d1d,0xdcdc +#endif +}; + +/* +===================== += += VGAClearScreen += +===================== +*/ + +void VGAClearScreen (void) +{ + unsigned ceiling=vgaCeiling[gamestate.episode*10+mapon]; + + // + // clear the screen + // +asm mov dx,SC_INDEX +asm mov ax,SC_MAPMASK+15*256 // write through all planes +asm out dx,ax + +asm mov dx,80 +asm mov ax,[viewwidth] +asm shr ax,1 +asm shr ax,1 +asm sub dx,ax // dx = 40-viewwidth/2 + +asm mov bx,[viewwidth] +asm shr bx,1 // bl = viewwidth/8 +asm shr bx,1 +asm shr bx,1 +asm mov bh,BYTE PTR [viewheight] +asm shr bh,1 // half height + +asm mov es,[screenseg] +asm mov di,[bufferofs] +asm mov ax,[ceiling] + +toploop: +asm mov cl,bl +asm rep stosw +asm add di,dx +asm dec bh +asm jnz toploop + +asm mov bh,BYTE PTR [viewheight] +asm shr bh,1 // half height +asm mov ax,0x1919 + +bottomloop: +asm mov cl,bl +asm rep stosw +asm add di,dx +asm dec bh +asm jnz bottomloop +} + +//========================================================================== + +/* +===================== += += CalcRotate += +===================== +*/ + +int CalcRotate (objtype *ob) +{ + int angle,viewangle; + + // this isn't exactly correct, as it should vary by a trig value, + // but it is close enough with only eight rotations + + viewangle = player->angle + (centerx - ob->viewx)/8; + + if (ob->obclass == rocketobj || ob->obclass == hrocketobj) + angle = (viewangle-180)- ob->angle; + else + angle = (viewangle-180)- dirangle[ob->dir]; + + angle+=ANGLES/16; + while (angle>=ANGLES) + angle-=ANGLES; + while (angle<0) + angle+=ANGLES; + + if (ob->state->rotate == 2) // 2 rotation pain frame + return 4*(angle/(ANGLES/2)); // seperated by 3 (art layout...) + + return angle/(ANGLES/8); +} + + +/* +===================== += += DrawScaleds += += Draws all objects that are visable += +===================== +*/ + +#define MAXVISABLE 50 + +typedef struct +{ + int viewx, + viewheight, + shapenum; +} visobj_t; + +visobj_t vislist[MAXVISABLE],*visptr,*visstep,*farthest; + +void DrawScaleds (void) +{ + int i,j,least,numvisable,height; + memptr shape; + byte *tilespot,*visspot; + int shapenum; + unsigned spotloc; + + statobj_t *statptr; + objtype *obj; + + visptr = &vislist[0]; + +// +// place static objects +// + for (statptr = &statobjlist[0] ; statptr !=laststatobj ; statptr++) + { + if ((visptr->shapenum = statptr->shapenum) == -1) + continue; // object has been deleted + + if (!*statptr->visspot) + continue; // not visable + + if (TransformTile (statptr->tilex,statptr->tiley + ,&visptr->viewx,&visptr->viewheight) && statptr->flags & FL_BONUS) + { + GetBonus (statptr); + continue; + } + + if (!visptr->viewheight) + continue; // to close to the object + + if (visptr < &vislist[MAXVISABLE-1]) // don't let it overflow + visptr++; + } + +// +// place active objects +// + for (obj = player->next;obj;obj=obj->next) + { + if (!(visptr->shapenum = obj->state->shapenum)) + continue; // no shape + + spotloc = (obj->tilex<<6)+obj->tiley; // optimize: keep in struct? + visspot = &spotvis[0][0]+spotloc; + tilespot = &tilemap[0][0]+spotloc; + + // + // could be in any of the nine surrounding tiles + // + if (*visspot + || ( *(visspot-1) && !*(tilespot-1) ) + || ( *(visspot+1) && !*(tilespot+1) ) + || ( *(visspot-65) && !*(tilespot-65) ) + || ( *(visspot-64) && !*(tilespot-64) ) + || ( *(visspot-63) && !*(tilespot-63) ) + || ( *(visspot+65) && !*(tilespot+65) ) + || ( *(visspot+64) && !*(tilespot+64) ) + || ( *(visspot+63) && !*(tilespot+63) ) ) + { + obj->active = true; + TransformActor (obj); + if (!obj->viewheight) + continue; // too close or far away + + visptr->viewx = obj->viewx; + visptr->viewheight = obj->viewheight; + if (visptr->shapenum == -1) + visptr->shapenum = obj->temp1; // special shape + + if (obj->state->rotate) + visptr->shapenum += CalcRotate (obj); + + if (visptr < &vislist[MAXVISABLE-1]) // don't let it overflow + visptr++; + obj->flags |= FL_VISABLE; + } + else + obj->flags &= ~FL_VISABLE; + } + +// +// draw from back to front +// + numvisable = visptr-&vislist[0]; + + if (!numvisable) + return; // no visable objects + + for (i = 0; iviewheight; + if (height < least) + { + least = height; + farthest = visstep; + } + } + // + // draw farthest + // + ScaleShape(farthest->viewx,farthest->shapenum,farthest->viewheight); + + farthest->viewheight = 32000; + } + +} + +//========================================================================== + +/* +============== += += DrawPlayerWeapon += += Draw the player's hands += +============== +*/ + +int weaponscale[NUMWEAPONS] = {SPR_KNIFEREADY,SPR_PISTOLREADY + ,SPR_MACHINEGUNREADY,SPR_CHAINREADY}; + +void DrawPlayerWeapon (void) +{ + int shapenum; + +#ifndef SPEAR + if (gamestate.victoryflag) + { + if (player->state == &s_deathcam && (TimeCount&32) ) + SimpleScaleShape(viewwidth/2,SPR_DEATHCAM,viewheight+1); + return; + } +#endif + + if (gamestate.weapon != -1) + { + shapenum = weaponscale[gamestate.weapon]+gamestate.weaponframe; + SimpleScaleShape(viewwidth/2,shapenum,viewheight+1); + } + + if (demorecord || demoplayback) + SimpleScaleShape(viewwidth/2,SPR_DEMO,viewheight+1); +} + + +//========================================================================== + + +/* +===================== += += CalcTics += +===================== +*/ + +void CalcTics (void) +{ + long newtime,oldtimecount; + +// +// calculate tics since last refresh for adaptive timing +// + if (lasttimecount > TimeCount) + TimeCount = lasttimecount; // if the game was paused a LONG time + + do + { + newtime = TimeCount; + tics = newtime-lasttimecount; + } while (!tics); // make sure at least one tic passes + + lasttimecount = newtime; + +#ifdef FILEPROFILE + strcpy (scratch,"\tTics:"); + itoa (tics,str,10); + strcat (scratch,str); + strcat (scratch,"\n"); + write (profilehandle,scratch,strlen(scratch)); +#endif + + if (tics>MAXTICS) + { + TimeCount -= (tics-MAXTICS); + tics = MAXTICS; + } +} + + +//========================================================================== + + +/* +======================== += += FixOfs += +======================== +*/ + +void FixOfs (void) +{ + VW_ScreenToScreen (displayofs,bufferofs,viewwidth/8,viewheight); +} + + +//========================================================================== + + +/* +==================== += += WallRefresh += +==================== +*/ + +void WallRefresh (void) +{ +// +// set up variables for this view +// + viewangle = player->angle; + midangle = viewangle*(FINEANGLES/ANGLES); + viewsin = sintable[viewangle]; + viewcos = costable[viewangle]; + viewx = player->x - FixedByFrac(focallength,viewcos); + viewy = player->y + FixedByFrac(focallength,viewsin); + + focaltx = viewx>>TILESHIFT; + focalty = viewy>>TILESHIFT; + + viewtx = player->x >> TILESHIFT; + viewty = player->y >> TILESHIFT; + + xpartialdown = viewx&(TILEGLOBAL-1); + xpartialup = TILEGLOBAL-xpartialdown; + ypartialdown = viewy&(TILEGLOBAL-1); + ypartialup = TILEGLOBAL-ypartialdown; + + lastside = -1; // the first pixel is on a new wall + AsmRefresh (); + ScalePost (); // no more optimization on last post +} + +//========================================================================== + +/* +======================== += += ThreeDRefresh += +======================== +*/ + +void ThreeDRefresh (void) +{ + int tracedir; + +// this wouldn't need to be done except for my debugger/video wierdness + outportb (SC_INDEX,SC_MAPMASK); + +// +// clear out the traced array +// +asm mov ax,ds +asm mov es,ax +asm mov di,OFFSET spotvis +asm xor ax,ax +asm mov cx,2048 // 64*64 / 2 +asm rep stosw + + bufferofs += screenofs; + +// +// follow the walls from there to the right, drawwing as we go +// + VGAClearScreen (); + + WallRefresh (); + +// +// draw all the scaled images +// + DrawScaleds(); // draw scaled stuff + DrawPlayerWeapon (); // draw player's hands + +// +// show screen and time last cycle +// + if (fizzlein) + { + FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,20,false); + fizzlein = false; + + lasttimecount = TimeCount = 0; // don't make a big tic count + + } + + bufferofs -= screenofs; + displayofs = bufferofs; + + asm cli + asm mov cx,[displayofs] + asm mov dx,3d4h // CRTC address register + asm mov al,0ch // start address high register + asm out dx,al + asm inc dx + asm mov al,ch + asm out dx,al // set the high byte + asm sti + + bufferofs += SCREENSIZE; + if (bufferofs > PAGE3START) + bufferofs = PAGE1START; + + frameon++; + PM_NextFrame(); +} + + +//=========================================================================== + diff --git a/src/lib/hb/c3_game.c b/src/lib/hb/game/c3_game.c similarity index 100% rename from src/lib/hb/c3_game.c rename to src/lib/hb/game/c3_game.c diff --git a/src/lib/hb/c6_game.c b/src/lib/hb/game/c6_game.c similarity index 100% rename from src/lib/hb/c6_game.c rename to src/lib/hb/game/c6_game.c diff --git a/src/lib/hb/game/wl_game.c b/src/lib/hb/game/wl_game.c new file mode 100755 index 00000000..9f63d9fe --- /dev/null +++ b/src/lib/hb/game/wl_game.c @@ -0,0 +1,1484 @@ +// WL_GAME.C + +#include "WL_DEF.H" +#pragma hdrstop + +#ifdef MYPROFILE +#include +#endif + + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + +boolean ingame,fizzlein; +unsigned latchpics[NUMLATCHPICS]; +gametype gamestate; + +long spearx,speary; +unsigned spearangle; +boolean spearflag; + +// +// ELEVATOR BACK MAPS - REMEMBER (-1)!! +// +int ElevatorBackTo[]={1,1,7,3,5,3}; + +void ScanInfoPlane (void); +void SetupGameLevel (void); +void DrawPlayScreen (void); +void LoadLatchMem (void); +void GameLoop (void); + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + + +//=========================================================================== +//=========================================================================== + + +/* +========================== += += SetSoundLoc - Given the location of an object (in terms of global += coordinates, held in globalsoundx and globalsoundy), munges the values += for an approximate distance from the left and right ear, and puts += those values into leftchannel and rightchannel. += += JAB += +========================== +*/ + + fixed globalsoundx,globalsoundy; + int leftchannel,rightchannel; +#define ATABLEMAX 15 +byte righttable[ATABLEMAX][ATABLEMAX * 2] = { +{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 0, 0, 0, 0, 0, 1, 3, 5, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 6, 4, 0, 0, 0, 0, 0, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 4, 1, 0, 0, 0, 1, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 5, 4, 2, 1, 0, 1, 2, 3, 5, 7, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 5, 4, 3, 2, 2, 3, 3, 5, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 4, 4, 4, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 6, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8} +}; +byte lefttable[ATABLEMAX][ATABLEMAX * 2] = { +{ 8, 8, 8, 8, 8, 8, 8, 8, 5, 3, 1, 0, 0, 0, 0, 0, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 2, 0, 0, 0, 0, 0, 4, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 2, 1, 0, 0, 0, 1, 4, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 5, 3, 2, 1, 0, 1, 2, 4, 5, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 5, 3, 3, 2, 2, 3, 4, 5, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 5, 4, 4, 4, 4, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 6, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}, +{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8} +}; + +void +SetSoundLoc(fixed gx,fixed gy) +{ + fixed xt,yt; + int x,y; + +// +// translate point to view centered coordinates +// + gx -= viewx; + gy -= viewy; + +// +// calculate newx +// + xt = FixedByFrac(gx,viewcos); + yt = FixedByFrac(gy,viewsin); + x = (xt - yt) >> TILESHIFT; + +// +// calculate newy +// + xt = FixedByFrac(gx,viewsin); + yt = FixedByFrac(gy,viewcos); + y = (yt + xt) >> TILESHIFT; + + if (y >= ATABLEMAX) + y = ATABLEMAX - 1; + else if (y <= -ATABLEMAX) + y = -ATABLEMAX; + if (x < 0) + x = -x; + if (x >= ATABLEMAX) + x = ATABLEMAX - 1; + leftchannel = lefttable[x][y + ATABLEMAX]; + rightchannel = righttable[x][y + ATABLEMAX]; + +#if 0 + CenterWindow(8,1); + US_PrintSigned(leftchannel); + US_Print(","); + US_PrintSigned(rightchannel); + VW_UpdateScreen(); +#endif +} + +/* +========================== += += SetSoundLocGlobal - Sets up globalsoundx & globalsoundy and then calls += UpdateSoundLoc() to transform that into relative channel volumes. Those += values are then passed to the Sound Manager so that they'll be used for += the next sound played (if possible). += += JAB += +========================== +*/ +void PlaySoundLocGlobal(word s,fixed gx,fixed gy) +{ + SetSoundLoc(gx,gy); + SD_PositionSound(leftchannel,rightchannel); + if (SD_PlaySound(s)) + { + globalsoundx = gx; + globalsoundy = gy; + } +} + +void UpdateSoundLoc(void) +{ + if (SoundPositioned) + { + SetSoundLoc(globalsoundx,globalsoundy); + SD_SetPosition(leftchannel,rightchannel); + } +} + +/* +** JAB End +*/ + + +/* +========================== += += ClearMemory += +========================== +*/ + +void ClearMemory (void) +{ + PM_UnlockMainMem(); + SD_StopDigitized(); + MM_SortMem (); +} + + +/* +========================== += += ScanInfoPlane += += Spawn all actors and mark down special places += +========================== +*/ + +void ScanInfoPlane (void) +{ + unsigned x,y,i,j; + int tile; + unsigned far *start; + + start = mapsegs[1]; + for (y=0;ywidth; + mapheight = mapheaderseg[mapon]->height; + + if (mapwidth != 64 || mapheight != 64) + Quit ("Map not 64*64!"); + + +// +// copy the wall data to a data segment array +// + memset (tilemap,0,sizeof(tilemap)); + memset (actorat,0,sizeof(actorat)); + map = mapsegs[0]; + for (y=0;y= 90 && tile <= 101) + { + // door + switch (tile) + { + case 90: + case 92: + case 94: + case 96: + case 98: + case 100: + SpawnDoor (x,y,1,(tile-90)/2); + break; + case 91: + case 93: + case 95: + case 97: + case 99: + case 101: + SpawnDoor (x,y,0,(tile-91)/2); + break; + } + } + } + +// +// spawn actors +// + ScanInfoPlane (); + +// +// take out the ambush markers +// + map = mapsegs[0]; + for (y=0;y= AREATILE) + tile = *map; + if (*(map-1-mapwidth) >= AREATILE) + tile = *(map-1-mapwidth); + if (*(map-1+mapwidth) >= AREATILE) + tile = *(map-1+mapwidth); + if ( *(map-2) >= AREATILE) + tile = *(map-2); + + *(map-1) = tile; + } + } + + + +// +// have the caching manager load and purge stuff to make sure all marks +// are in memory +// + CA_LoadAllSounds (); + +} + + +//========================================================================== + + +/* +=================== += += DrawPlayBorderSides += += To fix window overwrites += +=================== +*/ + +void DrawPlayBorderSides (void) +{ + int xl,yl; + + xl = 160-viewwidth/2; + yl = (200-STATUSLINES-viewheight)/2; + + VWB_Bar (0,0,xl-1,200-STATUSLINES,127); + VWB_Bar (xl+viewwidth+1,0,xl-2,200-STATUSLINES,127); + + VWB_Vlin (yl-1,yl+viewheight,xl-1,0); + VWB_Vlin (yl-1,yl+viewheight,xl+viewwidth,125); +} + + +/* +=================== += += DrawAllPlayBorderSides += +=================== +*/ + +void DrawAllPlayBorderSides (void) +{ + unsigned i,temp; + + temp = bufferofs; + for (i=0;i<3;i++) + { + bufferofs = screenloc[i]; + DrawPlayBorderSides (); + } + bufferofs = temp; +} + +/* +=================== += += DrawPlayBorder += +=================== +*/ +void DrawAllPlayBorder (void) +{ + unsigned i,temp; + + temp = bufferofs; + for (i=0;i<3;i++) + { + bufferofs = screenloc[i]; + DrawPlayBorder (); + } + bufferofs = temp; +} + +/* +=================== += += DrawPlayBorder += +=================== +*/ + +void DrawPlayBorder (void) +{ + int xl,yl; + + VWB_Bar (0,0,320,200-STATUSLINES,127); + + xl = 160-viewwidth/2; + yl = (200-STATUSLINES-viewheight)/2; + VWB_Bar (xl,yl,viewwidth,viewheight,0); + + VWB_Hlin (xl-1,xl+viewwidth,yl-1,0); + VWB_Hlin (xl-1,xl+viewwidth,yl+viewheight,125); + VWB_Vlin (yl-1,yl+viewheight,xl-1,0); + VWB_Vlin (yl-1,yl+viewheight,xl+viewwidth,125); + VWB_Plot (xl-1,yl+viewheight,124); +} + + + +/* +=================== += += DrawPlayScreen += +=================== +*/ + +void DrawPlayScreen (void) +{ + int i,j,p,m; + unsigned temp; + + VW_FadeOut (); + + temp = bufferofs; + + CA_CacheGrChunk (STATUSBARPIC); + + for (i=0;i<3;i++) + { + bufferofs = screenloc[i]; + DrawPlayBorder (); + VWB_DrawPic (0,200-STATUSLINES,STATUSBARPIC); + } + + bufferofs = temp; + + UNCACHEGRCHUNK (STATUSBARPIC); + + DrawFace (); + DrawHealth (); + DrawLives (); + DrawLevel (); + DrawAmmo (); + DrawKeys (); + DrawWeapon (); + DrawScore (); +} + + + +//========================================================================== + +/* +================== += += StartDemoRecord += +================== +*/ + +#define MAXDEMOSIZE 8192 + +void StartDemoRecord (int levelnumber) +{ + MM_GetPtr (&demobuffer,MAXDEMOSIZE); + MM_SetLock (&demobuffer,true); + demoptr = (char far *)demobuffer; + lastdemoptr = demoptr+MAXDEMOSIZE; + + *demoptr = levelnumber; + demoptr += 4; // leave space for length + demorecord = true; +} + + +/* +================== += += FinishDemoRecord += +================== +*/ + +char demoname[13] = "DEMO?."; + +void FinishDemoRecord (void) +{ + long length,level; + + demorecord = false; + + length = demoptr - (char far *)demobuffer; + + demoptr = ((char far *)demobuffer)+1; + *(unsigned far *)demoptr = length; + + CenterWindow(24,3); + PrintY+=6; + US_Print(" Demo number (0-9):"); + VW_UpdateScreen(); + + if (US_LineInput (px,py,str,NULL,true,2,0)) + { + level = atoi (str); + if (level>=0 && level<=9) + { + demoname[4] = '0'+level; + CA_WriteFile (demoname,(void far *)demobuffer,length); + } + } + + + MM_FreePtr (&demobuffer); +} + +//========================================================================== + +/* +================== += += RecordDemo += += Fades the screen out, then starts a demo. Exits with the screen faded += +================== +*/ + +void RecordDemo (void) +{ + int level,esc; + + CenterWindow(26,3); + PrintY+=6; + CA_CacheGrChunk(STARTFONT); + fontnumber=0; + US_Print(" Demo which level(1-10):"); + VW_UpdateScreen(); + VW_FadeIn (); + esc = !US_LineInput (px,py,str,NULL,true,2,0); + if (esc) + return; + + level = atoi (str); + level--; + + SETFONTCOLOR(0,15); + VW_FadeOut (); + +#ifndef SPEAR + NewGame (gd_hard,level/10); + gamestate.mapon = level%10; +#else + NewGame (gd_hard,0); + gamestate.mapon = level; +#endif + + StartDemoRecord (level); + + DrawPlayScreen (); + VW_FadeIn (); + + startgame = false; + demorecord = true; + + SetupGameLevel (); + StartMusic (); + PM_CheckMainMem (); + fizzlein = true; + + PlayLoop (); + + demoplayback = false; + + StopMusic (); + VW_FadeOut (); + ClearMemory (); + + FinishDemoRecord (); +} + +//========================================================================== + +/* +================== += += PlayDemo += += Fades the screen out, then starts a demo. Exits with the screen faded += +================== +*/ + +void PlayDemo (int demonumber) +{ + int length; + +#ifdef DEMOSEXTERN +// debug: load chunk +#ifndef SPEARDEMO + int dems[4]={T_DEMO0,T_DEMO1,T_DEMO2,T_DEMO3}; +#else + int dems[1]={T_DEMO0}; +#endif + + CA_CacheGrChunk(dems[demonumber]); + demoptr = grsegs[dems[demonumber]]; + MM_SetLock (&grsegs[dems[demonumber]],true); +#else + demoname[4] = '0'+demonumber; + CA_LoadFile (demoname,&demobuffer); + MM_SetLock (&demobuffer,true); + demoptr = (char far *)demobuffer; +#endif + + NewGame (1,0); + gamestate.mapon = *demoptr++; + gamestate.difficulty = gd_hard; + length = *((unsigned far *)demoptr)++; + demoptr++; + lastdemoptr = demoptr-4+length; + + VW_FadeOut (); + + SETFONTCOLOR(0,15); + DrawPlayScreen (); + VW_FadeIn (); + + startgame = false; + demoplayback = true; + + SetupGameLevel (); + StartMusic (); + PM_CheckMainMem (); + fizzlein = true; + + PlayLoop (); + +#ifdef DEMOSEXTERN + UNCACHEGRCHUNK(dems[demonumber]); +#else + MM_FreePtr (&demobuffer); +#endif + + demoplayback = false; + + StopMusic (); + VW_FadeOut (); + ClearMemory (); +} + +//========================================================================== + +/* +================== += += Died += +================== +*/ + +#define DEATHROTATE 2 + +void Died (void) +{ + float fangle; + long dx,dy; + int iangle,curangle,clockwise,counter,change; + + gamestate.weapon = -1; // take away weapon + SD_PlaySound (PLAYERDEATHSND); +// +// swing around to face attacker +// + dx = killerobj->x - player->x; + dy = player->y - killerobj->y; + + fangle = atan2(dy,dx); // returns -pi to pi + if (fangle<0) + fangle = M_PI*2+fangle; + + iangle = fangle/(M_PI*2)*ANGLES; + + if (player->angle > iangle) + { + counter = player->angle - iangle; + clockwise = ANGLES-player->angle + iangle; + } + else + { + clockwise = iangle - player->angle; + counter = player->angle + ANGLES-iangle; + } + + curangle = player->angle; + + if (clockwiseiangle) + curangle -= ANGLES; + do + { + change = tics*DEATHROTATE; + if (curangle + change > iangle) + change = iangle-curangle; + + curangle += change; + player->angle += change; + if (player->angle >= ANGLES) + player->angle -= ANGLES; + + ThreeDRefresh (); + CalcTics (); + } while (curangle != iangle); + } + else + { + // + // rotate counterclockwise + // + if (curangleangle += change; + if (player->angle < 0) + player->angle += ANGLES; + + ThreeDRefresh (); + CalcTics (); + } while (curangle != iangle); + } + +// +// fade to red +// + FinishPaletteShifts (); + + bufferofs += screenofs; + VW_Bar (0,0,viewwidth,viewheight,4); + IN_ClearKeysDown (); + FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,70,false); + bufferofs -= screenofs; + IN_UserInput(100); + SD_WaitSoundDone (); + + if (tedlevel == false) // SO'S YA DON'T GET KILLED WHILE LAUNCHING! + gamestate.lives--; + + if (gamestate.lives > -1) + { + gamestate.health = 100; + gamestate.weapon = gamestate.bestweapon + = gamestate.chosenweapon = wp_pistol; + gamestate.ammo = STARTAMMO; + gamestate.keys = 0; + gamestate.attackframe = gamestate.attackcount = + gamestate.weaponframe = 0; + + DrawKeys (); + DrawWeapon (); + DrawAmmo (); + DrawHealth (); + DrawFace (); + DrawLives (); + } + +} + +//========================================================================== + +/* +=================== += += GameLoop += +=================== +*/ + +void GameLoop (void) +{ + int i,xl,yl,xh,yh; + char num[20]; + boolean died; +#ifdef MYPROFILE + clock_t start,end; +#endif + +restartgame: + ClearMemory (); + SETFONTCOLOR(0,15); + DrawPlayScreen (); + died = false; +restart: + do + { + if (!loadedgame) + gamestate.score = gamestate.oldscore; + DrawScore(); + + startgame = false; + if (loadedgame) + loadedgame = false; + else + SetupGameLevel (); + +#ifdef SPEAR + if (gamestate.mapon == 20) // give them the key allways + { + gamestate.keys |= 1; + DrawKeys (); + } +#endif + + ingame = true; + StartMusic (); + PM_CheckMainMem (); + if (!died) + PreloadGraphics (); + else + died = false; + + fizzlein = true; + DrawLevel (); + +startplayloop: + PlayLoop (); + +#ifdef SPEAR + if (spearflag) + { + SD_StopSound(); + SD_PlaySound(GETSPEARSND); + if (DigiMode != sds_Off) + { + long lasttimecount = TimeCount; + + while(TimeCount < lasttimecount+150) + //while(DigiPlaying!=false) + SD_Poll(); + } + else + SD_WaitSoundDone(); + + ClearMemory (); + gamestate.oldscore = gamestate.score; + gamestate.mapon = 20; + SetupGameLevel (); + StartMusic (); + PM_CheckMainMem (); + player->x = spearx; + player->y = speary; + player->angle = spearangle; + spearflag = false; + Thrust (0,0); + goto startplayloop; + } +#endif + + StopMusic (); + ingame = false; + + if (demorecord && playstate != ex_warped) + FinishDemoRecord (); + + if (startgame || loadedgame) + goto restartgame; + + switch (playstate) + { + case ex_completed: + case ex_secretlevel: + gamestate.keys = 0; + DrawKeys (); + VW_FadeOut (); + + ClearMemory (); + + LevelCompleted (); // do the intermission +#ifdef SPEARDEMO + if (gamestate.mapon == 1) + { + died = true; // don't "get psyched!" + + VW_FadeOut (); + + ClearMemory (); + + CheckHighScore (gamestate.score,gamestate.mapon+1); + + #pragma warn -sus + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + MainMenu[viewscores].routine = CP_ViewScores; + #pragma warn +sus + + return; + } +#endif + +#ifdef JAPDEMO + if (gamestate.mapon == 3) + { + died = true; // don't "get psyched!" + + VW_FadeOut (); + + ClearMemory (); + + CheckHighScore (gamestate.score,gamestate.mapon+1); + + #pragma warn -sus + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + MainMenu[viewscores].routine = CP_ViewScores; + #pragma warn +sus + + return; + } +#endif + + gamestate.oldscore = gamestate.score; + +#ifndef SPEAR + // + // COMING BACK FROM SECRET LEVEL + // + if (gamestate.mapon == 9) + gamestate.mapon = ElevatorBackTo[gamestate.episode]; // back from secret + else + // + // GOING TO SECRET LEVEL + // + if (playstate == ex_secretlevel) + gamestate.mapon = 9; +#else + +#define FROMSECRET1 3 +#define FROMSECRET2 11 + + // + // GOING TO SECRET LEVEL + // + if (playstate == ex_secretlevel) + switch(gamestate.mapon) + { + case FROMSECRET1: gamestate.mapon = 18; break; + case FROMSECRET2: gamestate.mapon = 19; break; + } + else + // + // COMING BACK FROM SECRET LEVEL + // + if (gamestate.mapon == 18 || gamestate.mapon == 19) + switch(gamestate.mapon) + { + case 18: gamestate.mapon = FROMSECRET1+1; break; + case 19: gamestate.mapon = FROMSECRET2+1; break; + } +#endif + else + // + // GOING TO NEXT LEVEL + // + gamestate.mapon++; + + + break; + + case ex_died: + Died (); + died = true; // don't "get psyched!" + + if (gamestate.lives > -1) + break; // more lives left + + VW_FadeOut (); + + ClearMemory (); + + CheckHighScore (gamestate.score,gamestate.mapon+1); + + #pragma warn -sus + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + MainMenu[viewscores].routine = CP_ViewScores; + #pragma warn +sus + + return; + + case ex_victorious: + +#ifndef SPEAR + VW_FadeOut (); +#else + VL_FadeOut (0,255,0,17,17,300); +#endif + ClearMemory (); + + Victory (); + + ClearMemory (); + + CheckHighScore (gamestate.score,gamestate.mapon+1); + + #pragma warn -sus + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + MainMenu[viewscores].routine = CP_ViewScores; + #pragma warn +sus + + return; + + default: + ClearMemory (); + break; + } + + } while (1); + +} + diff --git a/src/lib/hb/inter/wl_inter.c b/src/lib/hb/inter/wl_inter.c new file mode 100755 index 00000000..c74cc9e6 --- /dev/null +++ b/src/lib/hb/inter/wl_inter.c @@ -0,0 +1,1718 @@ +// WL_INTER.C + +#include "WL_DEF.H" +#pragma hdrstop + + +//========================================================================== + +/* +================== += += CLearSplitVWB += +================== +*/ + +void ClearSplitVWB (void) +{ + memset (update,0,sizeof(update)); + WindowX = 0; + WindowY = 0; + WindowW = 320; + WindowH = 160; +} + + +//========================================================================== + +#ifdef SPEAR +#ifndef SPEARDEMO +//////////////////////////////////////////////////////// +// +// End of Spear of Destiny +// +//////////////////////////////////////////////////////// + +void EndScreen (int palette, int screen) +{ + CA_CacheScreen (screen); + VW_UpdateScreen (); + CA_CacheGrChunk (palette); + VL_FadeIn(0,255,grsegs[palette],30); + UNCACHEGRCHUNK (palette); + IN_ClearKeysDown (); + IN_Ack (); + VW_FadeOut (); +} + + +void EndSpear(void) +{ + EndScreen (END1PALETTE, ENDSCREEN11PIC); + + CA_CacheScreen (ENDSCREEN3PIC); + VW_UpdateScreen (); + CA_CacheGrChunk (END3PALETTE); + VL_FadeIn(0,255,grsegs[END3PALETTE],30); + UNCACHEGRCHUNK (END3PALETTE); + fontnumber = 0; + fontcolor = 0xd0; + WindowX = 0; + WindowW = 320; + PrintX = 0; + PrintY = 180; + US_CPrint (STR_ENDGAME1"\n"); + US_CPrint (STR_ENDGAME2); + VW_UpdateScreen (); + IN_StartAck (); + TimeCount = 0; + while (!IN_CheckAck () && TimeCount < 700); + + PrintX = 0; + PrintY = 180; + VWB_Bar(0,180,320,20,0); + US_CPrint (STR_ENDGAME3"\n"); + US_CPrint (STR_ENDGAME4); + VW_UpdateScreen (); + IN_StartAck (); + TimeCount = 0; + while (!IN_CheckAck () && TimeCount < 700); + + VW_FadeOut (); + + EndScreen (END4PALETTE, ENDSCREEN4PIC); + EndScreen (END5PALETTE, ENDSCREEN5PIC); + EndScreen (END6PALETTE, ENDSCREEN6PIC); + EndScreen (END7PALETTE, ENDSCREEN7PIC); + EndScreen (END8PALETTE, ENDSCREEN8PIC); + EndScreen (END9PALETTE, ENDSCREEN9PIC); + + EndScreen (END2PALETTE, ENDSCREEN12PIC); + + MainMenu[savegame].active = 0; +} +#endif +#endif + +//========================================================================== + +/* +================== += += Victory += +================== +*/ + +void Victory (void) +{ +#ifndef SPEARDEMO + long sec; + int i,min,kr,sr,tr,x; + char tempstr[8]; + +#define RATIOX 6 +#define RATIOY 14 +#define TIMEX 14 +#define TIMEY 8 + + +#ifdef SPEAR + StartCPMusic (XTHEEND_MUS); + + CA_CacheGrChunk(BJCOLLAPSE1PIC); + CA_CacheGrChunk(BJCOLLAPSE2PIC); + CA_CacheGrChunk(BJCOLLAPSE3PIC); + CA_CacheGrChunk(BJCOLLAPSE4PIC); + + VWB_Bar(0,0,320,200,VIEWCOLOR); + VWB_DrawPic (124,44,BJCOLLAPSE1PIC); + VW_UpdateScreen (); + VW_FadeIn (); + VW_WaitVBL(2*70); + VWB_DrawPic (124,44,BJCOLLAPSE2PIC); + VW_UpdateScreen (); + VW_WaitVBL(105); + VWB_DrawPic (124,44,BJCOLLAPSE3PIC); + VW_UpdateScreen (); + VW_WaitVBL(105); + VWB_DrawPic (124,44,BJCOLLAPSE4PIC); + VW_UpdateScreen (); + VW_WaitVBL(3*70); + + UNCACHEGRCHUNK(BJCOLLAPSE1PIC); + UNCACHEGRCHUNK(BJCOLLAPSE2PIC); + UNCACHEGRCHUNK(BJCOLLAPSE3PIC); + UNCACHEGRCHUNK(BJCOLLAPSE4PIC); + VL_FadeOut (0,255,0,17,17,5); +#endif + + StartCPMusic (URAHERO_MUS); + ClearSplitVWB (); + CacheLump(LEVELEND_LUMP_START,LEVELEND_LUMP_END); + CA_CacheGrChunk(STARTFONT); + +#ifndef SPEAR + CA_CacheGrChunk(C_TIMECODEPIC); +#endif + + + VWB_Bar (0,0,320,200-STATUSLINES,127); +#ifdef JAPAN +#ifndef JAPDEMO + CA_CacheGrChunk(C_ENDRATIOSPIC); + VWB_DrawPic(0,0,C_ENDRATIOSPIC); + UNCACHEGRCHUNK(C_ENDRATIOSPIC); +#endif +#else + Write(18,2,STR_YOUWIN); + + Write(TIMEX,TIMEY-2,STR_TOTALTIME); + + Write(12,RATIOY-2,"averages"); + + #ifdef SPANISH + Write(RATIOX+2, RATIOY, STR_RATKILL); + Write(RATIOX+2, RATIOY+2, STR_RATSECRET); + Write(RATIOX+2, RATIOY+4,STR_RATTREASURE); + #else + Write(RATIOX+8,RATIOY, STR_RATKILL); + Write(RATIOX+4,RATIOY+2, STR_RATSECRET); + Write(RATIOX, RATIOY+4,STR_RATTREASURE); + #endif + +#endif + +#ifndef JAPDEMO + VWB_DrawPic (8,4,L_BJWINSPIC); +#endif + + +#ifndef SPEAR + for (kr = sr = tr = sec = i = 0;i < 8;i++) +#else + for (kr = sr = tr = sec = i = 0;i < 20;i++) +#endif + { + sec += LevelRatios[i].time; + kr += LevelRatios[i].kill; + sr += LevelRatios[i].secret; + tr += LevelRatios[i].treasure; + } + +#ifndef SPEAR + kr /= 8; + sr /= 8; + tr /= 8; +#else + kr /= 14; + sr /= 14; + tr /= 14; +#endif + + min = sec/60; + sec %= 60; + + if (min > 99) + min = sec = 99; + + i = TIMEX*8+1; + VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(min/10)); + i += 2*8; + VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(min%10)); + i += 2*8; + Write(i/8,TIMEY,":"); + i += 1*8; + VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(sec/10)); + i += 2*8; + VWB_DrawPic(i,TIMEY*8,L_NUM0PIC+(sec%10)); + VW_UpdateScreen (); + + itoa(kr,tempstr,10); + x=RATIOX+24-strlen(tempstr)*2; + Write(x,RATIOY,tempstr); + + itoa(sr,tempstr,10); + x=RATIOX+24-strlen(tempstr)*2; + Write(x,RATIOY+2,tempstr); + + itoa(tr,tempstr,10); + x=RATIOX+24-strlen(tempstr)*2; + Write(x,RATIOY+4,tempstr); + + +#ifndef SPANISH +#ifndef UPLOAD +#ifndef SPEAR + // + // TOTAL TIME VERIFICATION CODE + // + if (gamestate.difficulty>=gd_medium) + { + VWB_DrawPic (30*8,TIMEY*8,C_TIMECODEPIC); + fontnumber = 0; + fontcolor = READHCOLOR; + PrintX = 30*8-3; + PrintY = TIMEY*8+8; + PrintX+=4; + tempstr[0] = (((min/10)^(min%10))^0xa)+'A'; + tempstr[1] = (((sec/10)^(sec%10))^0xa)+'A'; + tempstr[2] = (tempstr[0]^tempstr[1])+'A'; + tempstr[3] = 0; + US_Print(tempstr); + } +#endif +#endif +#endif + + + fontnumber = 1; + + VW_UpdateScreen (); + VW_FadeIn (); + + IN_Ack(); + + #ifndef SPEAR + if (Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + + VW_FadeOut (); + +#ifndef SPEAR + UNCACHEGRCHUNK(C_TIMECODEPIC); +#endif + UnCacheLump(LEVELEND_LUMP_START,LEVELEND_LUMP_END); + +#ifndef SPEAR + EndText(); +#else + EndSpear(); +#endif + +#endif // SPEARDEMO +} + + +//========================================================================== + +#ifndef JAPAN +/* +================== += += PG13 += +================== +*/ + +void PG13 (void) +{ + VW_FadeOut(); + VWB_Bar(0,0,320,200,0x82); // background + + CA_CacheGrChunk (PG13PIC); + VWB_DrawPic (216,110,PG13PIC); + VW_UpdateScreen (); + + UNCACHEGRCHUNK (PG13PIC); + + VW_FadeIn(); + IN_UserInput(TickBase*7); + + VW_FadeOut (); +} +#endif + + +//========================================================================== + +void Write(int x,int y,char *string) +{ + int alpha[]={L_NUM0PIC,L_NUM1PIC,L_NUM2PIC,L_NUM3PIC,L_NUM4PIC,L_NUM5PIC, + L_NUM6PIC,L_NUM7PIC,L_NUM8PIC,L_NUM9PIC,L_COLONPIC,0,0,0,0,0,0,L_APIC,L_BPIC, + L_CPIC,L_DPIC,L_EPIC,L_FPIC,L_GPIC,L_HPIC,L_IPIC,L_JPIC,L_KPIC, + L_LPIC,L_MPIC,L_NPIC,L_OPIC,L_PPIC,L_QPIC,L_RPIC,L_SPIC,L_TPIC, + L_UPIC,L_VPIC,L_WPIC,L_XPIC,L_YPIC,L_ZPIC}; + + int i,ox,nx,ny; + char ch; + + + ox=nx=x*8; + ny=y*8; + for (i=0;i='a') + ch-=('a'-'A'); + ch-='0'; + + switch(string[i]) + { + case '!': + VWB_DrawPic(nx,ny,L_EXPOINTPIC); + nx+=8; + continue; + + case '\'': + VWB_DrawPic(nx,ny,L_APOSTROPHEPIC); + nx+=8; + continue; + + case ' ': break; + case 0x3a: // ':' + + VWB_DrawPic(nx,ny,L_COLONPIC); + nx+=8; + continue; + + case '%': + VWB_DrawPic(nx,ny,L_PERCENTPIC); + break; + + default: + VWB_DrawPic(nx,ny,alpha[ch]); + } + nx+=16; + } +} + + +// +// Breathe Mr. BJ!!! +// +void BJ_Breathe(void) +{ + static int which=0,max=10; + int pics[2]={L_GUYPIC,L_GUY2PIC}; + + + if (TimeCount>max) + { + which^=1; + VWB_DrawPic(0,16,pics[which]); + VW_UpdateScreen(); + TimeCount=0; + max=35; + } +} + + + +/* +================== += += LevelCompleted += += Entered with the screen faded out += Still in split screen mode with the status bar += += Exit with the screen faded out += +================== +*/ + +#ifndef SPEAR +LRstruct LevelRatios[8]; +#else +LRstruct LevelRatios[20]; +#endif + +void LevelCompleted (void) +{ + #define VBLWAIT 30 + #define PAR_AMOUNT 500 + #define PERCENT100AMT 10000 + typedef struct { + float time; + char timestr[6]; + } times; + + int x,i,min,sec,ratio,kr,sr,tr; + unsigned temp; + char tempstr[10]; + long bonus,timeleft=0; + times parTimes[]= + { +#ifndef SPEAR + // + // Episode One Par Times + // + {1.5, "01:30"}, + {2, "02:00"}, + {2, "02:00"}, + {3.5, "03:30"}, + {3, "03:00"}, + {3, "03:00"}, + {2.5, "02:30"}, + {2.5, "02:30"}, + {0, "??:??"}, // Boss level + {0, "??:??"}, // Secret level + + // + // Episode Two Par Times + // + {1.5, "01:30"}, + {3.5, "03:30"}, + {3, "03:00"}, + {2, "02:00"}, + {4, "04:00"}, + {6, "06:00"}, + {1, "01:00"}, + {3, "03:00"}, + {0, "??:??"}, + {0, "??:??"}, + + // + // Episode Three Par Times + // + {1.5, "01:30"}, + {1.5, "01:30"}, + {2.5, "02:30"}, + {2.5, "02:30"}, + {3.5, "03:30"}, + {2.5, "02:30"}, + {2, "02:00"}, + {6, "06:00"}, + {0, "??:??"}, + {0, "??:??"}, + + // + // Episode Four Par Times + // + {2, "02:00"}, + {2, "02:00"}, + {1.5, "01:30"}, + {1, "01:00"}, + {4.5, "04:30"}, + {3.5, "03:30"}, + {2, "02:00"}, + {4.5, "04:30"}, + {0, "??:??"}, + {0, "??:??"}, + + // + // Episode Five Par Times + // + {2.5, "02:30"}, + {1.5, "01:30"}, + {2.5, "02:30"}, + {2.5, "02:30"}, + {4, "04:00"}, + {3, "03:00"}, + {4.5, "04:30"}, + {3.5, "03:30"}, + {0, "??:??"}, + {0, "??:??"}, + + // + // Episode Six Par Times + // + {6.5, "06:30"}, + {4, "04:00"}, + {4.5, "04:30"}, + {6, "06:00"}, + {5, "05:00"}, + {5.5, "05:30"}, + {5.5, "05:30"}, + {8.5, "08:30"}, + {0, "??:??"}, + {0, "??:??"} +#else + // + // SPEAR OF DESTINY TIMES + // + {1.5, "01:30"}, + {3.5, "03:30"}, + {2.75, "02:45"}, + {3.5, "03:30"}, + {0, "??:??"}, // Boss 1 + {4.5, "04:30"}, + {3.25, "03:15"}, + {2.75, "02:45"}, + {4.75, "04:45"}, + {0, "??:??"}, // Boss 2 + {6.5, "06:30"}, + {4.5, "04:30"}, + {2.75, "02:45"}, + {4.5, "04:30"}, + {6, "06:00"}, + {0, "??:??"}, // Boss 3 + {6, "06:00"}, + {0, "??:??"}, // Boss 4 + {0, "??:??"}, // Secret level 1 + {0, "??:??"}, // Secret level 2 +#endif + }; + + + + CacheLump(LEVELEND_LUMP_START,LEVELEND_LUMP_END); + ClearSplitVWB (); // set up for double buffering in split screen + VWB_Bar (0,0,320,200-STATUSLINES,127); + StartCPMusic(ENDLEVEL_MUS); + +// +// do the intermission +// + IN_ClearKeysDown(); + IN_StartAck(); + +#ifdef JAPAN + CA_CacheGrChunk(C_INTERMISSIONPIC); + VWB_DrawPic(0,0,C_INTERMISSIONPIC); + UNCACHEGRCHUNK(C_INTERMISSIONPIC); +#endif + VWB_DrawPic(0,16,L_GUYPIC); + +#ifndef SPEAR + if (mapon<8) +#else + if (mapon != 4 && + mapon != 9 && + mapon != 15 && + mapon < 17) +#endif + { +#ifndef JAPAN + #ifdef SPANISH + Write(14,2,"piso\ncompletado"); + #else + Write(14,2,"floor\ncompleted"); + #endif + + Write(14,7,STR_BONUS" 0"); + Write(16,10,STR_TIME); + Write(16,12,STR_PAR); + + #ifdef SPANISH + Write(11,14, STR_RAT2KILL); + Write(11,16, STR_RAT2SECRET); + Write(11,18,STR_RAT2TREASURE); + #else + Write(9,14, STR_RAT2KILL); + Write(5,16, STR_RAT2SECRET); + Write(1,18,STR_RAT2TREASURE); + #endif + + Write(26,2,itoa(gamestate.mapon+1,tempstr,10)); +#endif + + #ifdef SPANISH + Write(30,12,parTimes[gamestate.episode*10+mapon].timestr); + #else + Write(26,12,parTimes[gamestate.episode*10+mapon].timestr); + #endif + + // + // PRINT TIME + // + sec=gamestate.TimeCount/70; + + if (sec > 99*60) // 99 minutes max + sec = 99*60; + + if (gamestate.TimeCountname); + + // + // level + // + ultoa(s->completed,buffer,10); +#ifndef SPEAR + for (str = buffer;*str;str++) + *str = *str + (129 - '0'); // Used fixed-width numbers (129...) + USL_MeasureString(buffer,&w,&h); + PrintX = (22 * 8)-w; +#else + USL_MeasureString(buffer,&w,&h); + PrintX = 194 - w; +#endif + +#ifndef UPLOAD +#ifndef SPEAR + PrintX -= 6; + itoa(s->episode+1,buffer1,10); + US_Print("E"); + US_Print(buffer1); + US_Print("/L"); +#endif +#endif + +#ifdef SPEAR + if (s->completed == 21) + VWB_DrawPic (PrintX+8,PrintY-1,C_WONSPEARPIC); + else +#endif + US_Print(buffer); + + // + // score + // + ultoa(s->score,buffer,10); +#ifndef SPEAR + for (str = buffer;*str;str++) + *str = *str + (129 - '0'); // Used fixed-width numbers (129...) + USL_MeasureString(buffer,&w,&h); + PrintX = (34 * 8) - 8 - w; +#else + USL_MeasureString(buffer,&w,&h); + PrintX = 292 - w; +#endif + US_Print(buffer); + + #if 0 +#ifndef UPLOAD +#ifndef SPEAR + // + // verification # + // + if (!i) + { + temp=(((s->score >> 28)& 0xf)^ + ((s->score >> 24)& 0xf))+'A'; + temp1=(((s->score >> 20)& 0xf)^ + ((s->score >> 16)& 0xf))+'A'; + temp2=(((s->score >> 12)& 0xf)^ + ((s->score >> 8)& 0xf))+'A'; + temp3=(((s->score >> 4)& 0xf)^ + ((s->score >> 0)& 0xf))+'A'; + + SETFONTCOLOR(0x49,0x29); + PrintX = 35*8; + buffer[0]=temp; + buffer[1]=temp1; + buffer[2]=temp2; + buffer[3]=temp3; + buffer[4]=0; + US_Print(buffer); + SETFONTCOLOR(15,0x29); + } +#endif +#endif + #endif + } + + VW_UpdateScreen (); + +#ifdef SPEAR + UnCacheLump (HIGHSCORES_LUMP_START,HIGHSCORES_LUMP_END); + fontnumber = 0; +#endif +} + +//=========================================================================== + + +/* +======================= += += CheckHighScore += +======================= +*/ + +void CheckHighScore (long score,word other) +{ + word i,j; + int n; + HighScore myscore; + + strcpy(myscore.name,""); + myscore.score = score; + myscore.episode = gamestate.episode; + myscore.completed = other; + + for (i = 0,n = -1;i < MaxScores;i++) + { + if + ( + (myscore.score > Scores[i].score) + || ( + (myscore.score == Scores[i].score) + && (myscore.completed > Scores[i].completed) + ) + ) + { + for (j = MaxScores;--j > i;) + Scores[j] = Scores[j - 1]; + Scores[i] = myscore; + n = i; + break; + } + } + +#ifdef SPEAR + StartCPMusic (XAWARD_MUS); +#else + StartCPMusic (ROSTER_MUS); +#endif + DrawHighScores (); + + VW_FadeIn (); + + if (n != -1) + { + // + // got a high score + // + PrintY = 76 + (16 * n); +#ifndef SPEAR + PrintX = 4*8; + backcolor = BORDCOLOR; + fontcolor = 15; + US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,100); +#else + PrintX = 16; + fontnumber = 1; + VWB_Bar (PrintX-2,PrintY-2,145,15,0x9c); + VW_UpdateScreen (); + backcolor = 0x9c; + fontcolor = 15; + US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,130); +#endif + } + else + { + IN_ClearKeysDown (); + IN_UserInput(500); + } + +} + + +#ifndef UPLOAD +#ifndef SPEAR +#ifndef JAPAN +//////////////////////////////////////////////////////// +// +// NON-SHAREWARE NOTICE +// +//////////////////////////////////////////////////////// +void NonShareware(void) +{ + VW_FadeOut(); + + ClearMScreen(); + DrawStripes(10); + + CA_CacheGrChunk(STARTFONT+1); + fontnumber = 1; + + SETFONTCOLOR(READHCOLOR,BKGDCOLOR); + PrintX=110; + PrintY=15; + + #ifdef SPANISH + US_Print("Atencion"); + #else + US_Print("Attention"); + #endif + + SETFONTCOLOR(HIGHLIGHT,BKGDCOLOR); + WindowX=PrintX=40; + PrintY=60; + #ifdef SPANISH + US_Print("Este juego NO es gratis y\n"); + US_Print("NO es Shareware; favor de\n"); + US_Print("no distribuirlo.\n\n"); + #else + US_Print("This game is NOT shareware.\n"); + US_Print("Please do not distribute it.\n"); + US_Print("Thanks.\n\n"); + #endif + US_Print(" Id Software\n"); + + VW_UpdateScreen (); + VW_FadeIn(); + IN_Ack(); +} +#endif +#endif +#endif + +#ifdef SPEAR +#ifndef SPEARDEMO +//////////////////////////////////////////////////////// +// +// COPY PROTECTION FOR FormGen +// +//////////////////////////////////////////////////////// +char far CopyProFailedStrs[][100] = { + STR_COPY1, + STR_COPY2, + + STR_COPY3, + STR_COPY4, + + STR_COPY5, + STR_COPY6, + + STR_COPY7, + STR_COPY8, + + STR_COPY9, + "", + + STR_COPY10, + STR_COPY11, + + STR_COPY12, + "", + + STR_COPY13, + "", + + STR_COPY14, + "" + }, + + far BackDoorStrs[5][16] = { + "a spoon?", + "bite me!", + "joshua", + "pelt", +#ifdef BETA + "beta" +#else + "snoops" +#endif + }, + + far GoodBoyStrs[10][40] = { + "...is the CORRECT ANSWER!", + "", + + "Consider yourself bitten, sir.", + "", + + "Greetings Professor Falken, would you", + "like to play Spear of Destiny?", + + "Do you have any gold spray paint?", + "", + +#ifdef BETA + "Beta testing approved.", +#else + "I wish I had a 21\" monitor...", +#endif + "" + }, + + far bossstrs[4][24] = { + "DEATH KNIGHT", + "BARNACLE WILHELM", + "UBERMUTANTUBER MUTANT", + "TRANS GROSSE" + }, + + far WordStr[5][20] = { + "New Game", + "Sound...F4", + "Control...F6", + "Change View...F5", + "Quit...F10"}, + + far WordCorrect[5][2] = {"3","4","4","5","5"}, + + far MemberStr[10][40] = { + STR_COPY15, + "", + + STR_COPY16, + "", + + STR_COPY17, + STR_COPY18, + + STR_COPY19, + STR_COPY20, + + STR_COPY21, + STR_COPY22}, + + far MemberCorrect[5][24] = { + "adrian carmack", + "john carmackjohn romero", + "tom hall", + "jay wilbur", + "kevin cloud"}, + + far DosMessages[9][80] = { + STR_NOPE1, + STR_NOPE2, + STR_NOPE3, + STR_NOPE4, + STR_NOPE5, + STR_NOPE6, + STR_NOPE7, + STR_NOPE8, + STR_NOPE9}, + + far MiscTitle[4][20] = { + "BLOOD TEST", + "STRAIGHT-LACED", + "QUITE SHAPELY", + "I AM WHAT I AMMO" + }, + + far MiscStr[12][40] = { + STR_MISC1, + STR_MISC2, + "", + + STR_MISC3, + STR_MISC4, + "", + + STR_MISC5, + STR_MISC6, + "", + + STR_MISC7, + STR_MISC8, + STR_MISC9 + }, + + far MiscCorrect[4][5] = {"ss","8",STR_STAR,"45"}; + + +int BackDoor(char *s) +{ + int i; + + + strlwr(s); + + for (i=0;i<5;i++) + if (!_fstrcmp(s,BackDoorStrs[i])) + { + SETFONTCOLOR(14,15); + fontnumber = 0; + PrintY = 175; + VWB_DrawPic (0,20*8,COPYPROTBOXPIC); + US_CPrint(GoodBoyStrs[i*2]); + US_CPrint(GoodBoyStrs[i*2+1]); + VW_UpdateScreen(); + return 1; + } + + return 0; +} + + +void CopyProtection(void) +{ +#define TYPEBOX_Y 177 +#define TYPEBOX_BKGD 0x9c +#define PRINTCOLOR HIGHLIGHT + + int i,match,whichboss,bossnum,try,whichline,enemypicked[4]={0,0,0,0}, + bosses[4] = { BOSSPIC1PIC,BOSSPIC2PIC,BOSSPIC3PIC,BOSSPIC4PIC }, + whichone,whichpicked[4]={0,0,0,0},quiztype,whichmem, + memberpicked[5]={0,0,0,0,0},wordpicked[5]={0,0,0,0,0},whichword; + + char inputbuffer[20], + message[80]; + + enum + { + debriefing, + checkmanual, + staffquiz, + miscquiz, + + totaltypes + }; + + + + try = 0; + VW_FadeOut(); + CA_CacheGrChunk(C_BACKDROPPIC); + CacheLump(COPYPROT_LUMP_START,COPYPROT_LUMP_END); + CA_CacheGrChunk(STARTFONT+1); + CA_LoadAllSounds(); + StartCPMusic(COPYPRO_MUS); + US_InitRndT(true); + + while (try<3) + { + fontnumber = 1; + SETFONTCOLOR(PRINTCOLOR-2,15); + VWB_DrawPic (0,0,C_BACKDROPPIC); + VWB_DrawPic (0,0,COPYPROTTOPPIC); + VWB_DrawPic (0,20*8,COPYPROTBOXPIC); + WindowX = WindowY = 0; + WindowW = 320; + WindowH = 200; + PrintY = 65; + + quiztype = US_RndT()%totaltypes; + switch(quiztype) + { + // + // BOSSES QUIZ + // + case debriefing: + PrintX = 0; + US_Print(STR_DEBRIEF); + SETFONTCOLOR(PRINTCOLOR,15); + + while (enemypicked[whichboss = US_RndT()&3]); + enemypicked[whichboss] = 1; + bossnum = bosses[whichboss]; + VWB_DrawPic(128,60,bossnum); + fontnumber = 0; + PrintY = 130; + US_CPrint(STR_ENEMY1"\n"); + US_CPrint(STR_ENEMY2"\n\n"); + + VW_UpdateScreen(); + VW_FadeIn(); + + PrintX = 100; + fontcolor = 15; + backcolor = TYPEBOX_BKGD; + inputbuffer[0] = 0; + PrintY = TYPEBOX_Y; + fontnumber = 1; + US_LineInput(PrintX,PrintY,inputbuffer,nil,true,20,100); + + match = 0; + for (i=0;i<_fstrlen(bossstrs[whichboss]);i++) + if (!_fstrnicmp(inputbuffer,bossstrs[whichboss]+i,strlen(inputbuffer)) && + strlen(inputbuffer)>3) + match = 1; + + match += BackDoor(inputbuffer); + break; + + // + // MANUAL CHECK + // + case checkmanual: + while (wordpicked[whichword = US_RndT()%5]); + wordpicked[whichword] = 1; + US_CPrint(STR_CHECKMAN); + SETFONTCOLOR(PRINTCOLOR,15); + PrintY += 25; + US_CPrint(STR_MAN1); + US_CPrint(STR_MAN2); + _fstrcpy(message,STR_MAN3" \""); + _fstrcat(message,WordStr[whichword]); + _fstrcat(message,"\" "STR_MAN4); + US_CPrint(message); + VW_UpdateScreen(); + VW_FadeIn(); + + PrintX = 146; + fontcolor = 15; + backcolor = TYPEBOX_BKGD; + inputbuffer[0] = 0; + PrintY = TYPEBOX_Y; + US_LineInput(PrintX,PrintY,inputbuffer,nil,true,6,100); + + strlwr(inputbuffer); + match = 1-(_fstrcmp(inputbuffer,WordCorrect[whichword])!=0); + match += BackDoor(inputbuffer); + break; + + // + // STAFF QUIZ + // + case staffquiz: + while (memberpicked[whichmem = US_RndT()%5]); + memberpicked[whichmem] = 1; + US_CPrint(STR_ID1); + SETFONTCOLOR(PRINTCOLOR,15); + PrintY += 25; + US_CPrint(MemberStr[whichmem*2]); + US_CPrint(MemberStr[whichmem*2+1]); + VW_UpdateScreen(); + VW_FadeIn(); + + PrintX = 100; + fontcolor = 15; + backcolor = TYPEBOX_BKGD; + inputbuffer[0] = 0; + PrintY = TYPEBOX_Y; + US_LineInput(PrintX,PrintY,inputbuffer,nil,true,20,120); + + strlwr(inputbuffer); + match = 0; + for (i=0;i<_fstrlen(MemberCorrect[whichmem]);i++) + if (!_fstrnicmp(inputbuffer,MemberCorrect[whichmem]+i,strlen(inputbuffer)) && + strlen(inputbuffer)>2) + match = 1; + match += BackDoor(inputbuffer); + break; + + // + // MISCELLANEOUS QUESTIONS + // + case miscquiz: + while (whichpicked[whichone = US_RndT()&3]); + whichpicked[whichone] = 1; + US_CPrint(MiscTitle[whichone]); + SETFONTCOLOR(PRINTCOLOR,15); + PrintY += 25; + US_CPrint(MiscStr[whichone*3]); + US_CPrint(MiscStr[whichone*3+1]); + US_CPrint(MiscStr[whichone*3+2]); + VW_UpdateScreen(); + VW_FadeIn(); + + PrintX = 146; + fontcolor = 15; + backcolor = TYPEBOX_BKGD; + inputbuffer[0] = 0; + PrintY = TYPEBOX_Y; + US_LineInput(PrintX,PrintY,inputbuffer,nil,true,6,100); + + strlwr(inputbuffer); + match = 1-(_fstrcmp(inputbuffer,MiscCorrect[whichone])!=0); + match += BackDoor(inputbuffer); + break; + } + + // + // IF NO MATCH, WE'VE GOT A (MINOR) PROBLEM! + // + + if (!match) + { + whichline = 2*(US_RndT()%9); + SETFONTCOLOR(14,15); + fontnumber = 0; + PrintY = 175; + VWB_DrawPic (0,20*8,COPYPROTBOXPIC); + US_CPrint(CopyProFailedStrs[whichline]); + US_CPrint(CopyProFailedStrs[whichline+1]); + + VW_UpdateScreen(); + SD_PlaySound(NOWAYSND); + IN_UserInput(TickBase*3); + VW_FadeOut(); + try++; + } + else + { + int start; + + + SD_PlaySound(BONUS1UPSND); + SD_WaitSoundDone(); + UNCACHEGRCHUNK (STARTFONT+1); + UNCACHEGRCHUNK (C_BACKDROPPIC); + UnCacheLump (COPYPROT_LUMP_START,COPYPROT_LUMP_END); + + switch(SoundMode) + { + case sdm_Off: return; + case sdm_PC: start = STARTPCSOUNDS; break; + case sdm_AdLib: start = STARTADLIBSOUNDS; + } + + for (i=0;i +#include "WL_DEF.H" +#pragma hdrstop + + +/* +============================================================================= + + WOLFENSTEIN 3-D + + An Id Software production + + by John Carmack + +============================================================================= +*/ + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + + +#define FOCALLENGTH (0x5700l) // in global coordinates +#define VIEWGLOBAL 0x10000 // globals visable flush to wall + +#define VIEWWIDTH 256 // size of view window +#define VIEWHEIGHT 144 + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + +char str[80],str2[20]; +int tedlevelnum; +boolean tedlevel; +boolean nospr; +boolean IsA386; +int dirangle[9] = {0,ANGLES/8,2*ANGLES/8,3*ANGLES/8,4*ANGLES/8, + 5*ANGLES/8,6*ANGLES/8,7*ANGLES/8,ANGLES}; + +// +// proejection variables +// +fixed focallength; +unsigned screenofs; +int viewwidth; +int viewheight; +int centerx; +int shootdelta; // pixels away from centerx a target can be +fixed scale,maxslope; +long heightnumerator; +int minheightdiv; + + +void Quit (char *error); + +boolean startgame,loadedgame,virtualreality; +int mouseadjustment; + +char configname[13]="CONFIG."; + + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +/* +==================== += += ReadConfig += +==================== +*/ + +void ReadConfig(void) +{ + int file; + SDMode sd; + SMMode sm; + SDSMode sds; + + + if ( (file = open(configname,O_BINARY | O_RDONLY)) != -1) + { + // + // valid config file + // + read(file,Scores,sizeof(HighScore) * MaxScores); + + read(file,&sd,sizeof(sd)); + read(file,&sm,sizeof(sm)); + read(file,&sds,sizeof(sds)); + + read(file,&mouseenabled,sizeof(mouseenabled)); + read(file,&joystickenabled,sizeof(joystickenabled)); + read(file,&joypadenabled,sizeof(joypadenabled)); + read(file,&joystickprogressive,sizeof(joystickprogressive)); + read(file,&joystickport,sizeof(joystickport)); + + read(file,&dirscan,sizeof(dirscan)); + read(file,&buttonscan,sizeof(buttonscan)); + read(file,&buttonmouse,sizeof(buttonmouse)); + read(file,&buttonjoy,sizeof(buttonjoy)); + + read(file,&viewsize,sizeof(viewsize)); + read(file,&mouseadjustment,sizeof(mouseadjustment)); + + close(file); + + if (sd == sdm_AdLib && !AdLibPresent && !SoundBlasterPresent) + { + sd = sdm_PC; + sd = smm_Off; + } + + if ((sds == sds_SoundBlaster && !SoundBlasterPresent) || + (sds == sds_SoundSource && !SoundSourcePresent)) + sds = sds_Off; + + if (!MousePresent) + mouseenabled = false; + if (!JoysPresent[joystickport]) + joystickenabled = false; + + MainMenu[6].active=1; + MainItems.curpos=0; + } + else + { + // + // no config file, so select by hardware + // + if (SoundBlasterPresent || AdLibPresent) + { + sd = sdm_AdLib; + sm = smm_AdLib; + } + else + { + sd = sdm_PC; + sm = smm_Off; + } + + if (SoundBlasterPresent) + sds = sds_SoundBlaster; + else if (SoundSourcePresent) + sds = sds_SoundSource; + else + sds = sds_Off; + + if (MousePresent) + mouseenabled = true; + + joystickenabled = false; + joypadenabled = false; + joystickport = 0; + joystickprogressive = false; + + viewsize = 15; + mouseadjustment=5; + } + + SD_SetMusicMode (sm); + SD_SetSoundMode (sd); + SD_SetDigiDevice (sds); + +} + + +/* +==================== += += WriteConfig += +==================== +*/ + +void WriteConfig(void) +{ + int file; + + file = open(configname,O_CREAT | O_BINARY | O_WRONLY, + S_IREAD | S_IWRITE | S_IFREG); + + if (file != -1) + { + write(file,Scores,sizeof(HighScore) * MaxScores); + + write(file,&SoundMode,sizeof(SoundMode)); + write(file,&MusicMode,sizeof(MusicMode)); + write(file,&DigiMode,sizeof(DigiMode)); + + write(file,&mouseenabled,sizeof(mouseenabled)); + write(file,&joystickenabled,sizeof(joystickenabled)); + write(file,&joypadenabled,sizeof(joypadenabled)); + write(file,&joystickprogressive,sizeof(joystickprogressive)); + write(file,&joystickport,sizeof(joystickport)); + + write(file,&dirscan,sizeof(dirscan)); + write(file,&buttonscan,sizeof(buttonscan)); + write(file,&buttonmouse,sizeof(buttonmouse)); + write(file,&buttonjoy,sizeof(buttonjoy)); + + write(file,&viewsize,sizeof(viewsize)); + write(file,&mouseadjustment,sizeof(mouseadjustment)); + + close(file); + } +} + + +//=========================================================================== + + +/* +======================== += += Patch386 += += Patch ldiv to use 32 bit instructions += +======================== +*/ + +char *JHParmStrings[] = {"no386",nil}; +void Patch386 (void) +{ +extern void far jabhack2(void); +extern int far CheckIs386(void); + + int i; + + for (i = 1;i < _argc;i++) + if (US_CheckParm(_argv[i],JHParmStrings) == 0) + { + IsA386 = false; + return; + } + + if (CheckIs386()) + { + IsA386 = true; + jabhack2(); + } + else + IsA386 = false; +} + +//=========================================================================== + +/* +===================== += += NewGame += += Set up new game to start from the beginning += +===================== +*/ + +void NewGame (int difficulty,int episode) +{ + memset (&gamestate,0,sizeof(gamestate)); + gamestate.difficulty = difficulty; + gamestate.weapon = gamestate.bestweapon + = gamestate.chosenweapon = wp_pistol; + gamestate.health = 100; + gamestate.ammo = STARTAMMO; + gamestate.lives = 3; + gamestate.nextextra = EXTRAPOINTS; + gamestate.episode=episode; + + startgame = true; +} + +//=========================================================================== + +void DiskFlopAnim(int x,int y) +{ + static char which=0; + if (!x && !y) + return; + VWB_DrawPic(x,y,C_DISKLOADING1PIC+which); + VW_UpdateScreen(); + which^=1; +} + + +long DoChecksum(byte far *source,unsigned size,long checksum) +{ + unsigned i; + + for (i=0;inext) + size += sizeof(*ob); + size += sizeof(nullobj); + + size += sizeof(gamestate) + + sizeof(LRstruct)*8 + + sizeof(tilemap) + + sizeof(actorat) + + sizeof(laststatobj) + + sizeof(statobjlist) + + sizeof(doorposition) + + sizeof(pwallstate) + + sizeof(pwallx) + + sizeof(pwally) + + sizeof(pwalldir) + + sizeof(pwallpos); + + if (avail < size) + { + Message(STR_NOSPACE1"\n" + STR_NOSPACE2); + return false; + } + + checksum = 0; + + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)&gamestate,sizeof(gamestate)); + checksum = DoChecksum((byte far *)&gamestate,sizeof(gamestate),checksum); + + DiskFlopAnim(x,y); +#ifdef SPEAR + CA_FarWrite (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*20); + checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*20,checksum); +#else + CA_FarWrite (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*8); + checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*8,checksum); +#endif + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)tilemap,sizeof(tilemap)); + checksum = DoChecksum((byte far *)tilemap,sizeof(tilemap),checksum); + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)actorat,sizeof(actorat)); + checksum = DoChecksum((byte far *)actorat,sizeof(actorat),checksum); + + CA_FarWrite (file,(void far *)areaconnect,sizeof(areaconnect)); + CA_FarWrite (file,(void far *)areabyplayer,sizeof(areabyplayer)); + + for (ob = player ; ob ; ob=ob->next) + { + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)ob,sizeof(*ob)); + } + nullobj.active = ac_badobject; // end of file marker + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)&nullobj,sizeof(nullobj)); + + + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)&laststatobj,sizeof(laststatobj)); + checksum = DoChecksum((byte far *)&laststatobj,sizeof(laststatobj),checksum); + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)statobjlist,sizeof(statobjlist)); + checksum = DoChecksum((byte far *)statobjlist,sizeof(statobjlist),checksum); + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)doorposition,sizeof(doorposition)); + checksum = DoChecksum((byte far *)doorposition,sizeof(doorposition),checksum); + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)doorobjlist,sizeof(doorobjlist)); + checksum = DoChecksum((byte far *)doorobjlist,sizeof(doorobjlist),checksum); + + DiskFlopAnim(x,y); + CA_FarWrite (file,(void far *)&pwallstate,sizeof(pwallstate)); + checksum = DoChecksum((byte far *)&pwallstate,sizeof(pwallstate),checksum); + CA_FarWrite (file,(void far *)&pwallx,sizeof(pwallx)); + checksum = DoChecksum((byte far *)&pwallx,sizeof(pwallx),checksum); + CA_FarWrite (file,(void far *)&pwally,sizeof(pwally)); + checksum = DoChecksum((byte far *)&pwally,sizeof(pwally),checksum); + CA_FarWrite (file,(void far *)&pwalldir,sizeof(pwalldir)); + checksum = DoChecksum((byte far *)&pwalldir,sizeof(pwalldir),checksum); + CA_FarWrite (file,(void far *)&pwallpos,sizeof(pwallpos)); + checksum = DoChecksum((byte far *)&pwallpos,sizeof(pwallpos),checksum); + + // + // WRITE OUT CHECKSUM + // + CA_FarWrite (file,(void far *)&checksum,sizeof(checksum)); + + return(true); +} + +//=========================================================================== + +/* +================== += += LoadTheGame += +================== +*/ + +boolean LoadTheGame(int file,int x,int y) +{ + long checksum,oldchecksum; + objtype *ob,nullobj; + + + checksum = 0; + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)&gamestate,sizeof(gamestate)); + checksum = DoChecksum((byte far *)&gamestate,sizeof(gamestate),checksum); + + DiskFlopAnim(x,y); +#ifdef SPEAR + CA_FarRead (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*20); + checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*20,checksum); +#else + CA_FarRead (file,(void far *)&LevelRatios[0],sizeof(LRstruct)*8); + checksum = DoChecksum((byte far *)&LevelRatios[0],sizeof(LRstruct)*8,checksum); +#endif + + DiskFlopAnim(x,y); + SetupGameLevel (); + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)tilemap,sizeof(tilemap)); + checksum = DoChecksum((byte far *)tilemap,sizeof(tilemap),checksum); + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)actorat,sizeof(actorat)); + checksum = DoChecksum((byte far *)actorat,sizeof(actorat),checksum); + + CA_FarRead (file,(void far *)areaconnect,sizeof(areaconnect)); + CA_FarRead (file,(void far *)areabyplayer,sizeof(areabyplayer)); + + + + InitActorList (); + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)player,sizeof(*player)); + + while (1) + { + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)&nullobj,sizeof(nullobj)); + if (nullobj.active == ac_badobject) + break; + GetNewActor (); + // don't copy over the links + memcpy (new,&nullobj,sizeof(nullobj)-4); + } + + + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)&laststatobj,sizeof(laststatobj)); + checksum = DoChecksum((byte far *)&laststatobj,sizeof(laststatobj),checksum); + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)statobjlist,sizeof(statobjlist)); + checksum = DoChecksum((byte far *)statobjlist,sizeof(statobjlist),checksum); + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)doorposition,sizeof(doorposition)); + checksum = DoChecksum((byte far *)doorposition,sizeof(doorposition),checksum); + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)doorobjlist,sizeof(doorobjlist)); + checksum = DoChecksum((byte far *)doorobjlist,sizeof(doorobjlist),checksum); + + DiskFlopAnim(x,y); + CA_FarRead (file,(void far *)&pwallstate,sizeof(pwallstate)); + checksum = DoChecksum((byte far *)&pwallstate,sizeof(pwallstate),checksum); + CA_FarRead (file,(void far *)&pwallx,sizeof(pwallx)); + checksum = DoChecksum((byte far *)&pwallx,sizeof(pwallx),checksum); + CA_FarRead (file,(void far *)&pwally,sizeof(pwally)); + checksum = DoChecksum((byte far *)&pwally,sizeof(pwally),checksum); + CA_FarRead (file,(void far *)&pwalldir,sizeof(pwalldir)); + checksum = DoChecksum((byte far *)&pwalldir,sizeof(pwalldir),checksum); + CA_FarRead (file,(void far *)&pwallpos,sizeof(pwallpos)); + checksum = DoChecksum((byte far *)&pwallpos,sizeof(pwallpos),checksum); + + CA_FarRead (file,(void far *)&oldchecksum,sizeof(oldchecksum)); + + if (oldchecksum != checksum) + { + Message(STR_SAVECHT1"\n" + STR_SAVECHT2"\n" + STR_SAVECHT3"\n" + STR_SAVECHT4); + + IN_ClearKeysDown(); + IN_Ack(); + + gamestate.score = 0; + gamestate.lives = 1; + gamestate.weapon = + gamestate.chosenweapon = + gamestate.bestweapon = wp_pistol; + gamestate.ammo = 8; + } + + return true; +} + +//=========================================================================== + +/* +========================== += += ShutdownId += += Shuts down all ID_?? managers += +========================== +*/ + +void ShutdownId (void) +{ + US_Shutdown (); + SD_Shutdown (); + PM_Shutdown (); + IN_Shutdown (); + VW_Shutdown (); + CA_Shutdown (); + MM_Shutdown (); +} + + +//=========================================================================== + +/* +================== += += BuildTables += += Calculates: += += scale projection constant += sintable/costable overlapping fractional tables += +================== +*/ + +const float radtoint = (float)FINEANGLES/2/PI; + +void BuildTables (void) +{ + int i; + float angle,anglestep; + double tang; + fixed value; + + +// +// calculate fine tangents +// + + for (i=0;i>2 +// + heightnumerator = (TILEGLOBAL*scale)>>6; + minheightdiv = heightnumerator/0x7fff +1; + +// +// calculate the angle offset from view angle of each pixel's ray +// + + for (i=0;i>= 8; +} + + + +//=========================================================================== + +/* +=================== += += SetupWalls += += Map tile values to scaled pics += +=================== +*/ + +void SetupWalls (void) +{ + int i; + + for (i=1;i=0) + { + if (lastsong >= 0) + MusicMenu[start+lastsong].active = 1; + + StartCPMusic(songs[start + which]); + MusicMenu[start+which].active = 2; + DrawMenu (&MusicItems,&MusicMenu[start]); + VW_UpdateScreen(); + lastsong = which; + } + } while(which>=0); + + MenuFadeOut(); + IN_ClearKeysDown(); +#ifdef SPEAR + UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); +#else + UnCacheLump (CONTROLS_LUMP_START,CONTROLS_LUMP_END); +#endif +} +#endif + + +/* +========================== += += InitGame += += Load a few things right away += +========================== +*/ + +void InitGame (void) +{ + int i,x,y; + unsigned *blockstart; + + if (MS_CheckParm ("virtual")) + virtualreality = true; + else + virtualreality = false; + + MM_Startup (); // so the signon screen can be freed + + SignonScreen (); + + VW_Startup (); + IN_Startup (); + PM_Startup (); + PM_UnlockMainMem (); + SD_Startup (); + CA_Startup (); + US_Startup (); + + +#ifndef SPEAR + if (mminfo.mainmem < 235000L) +#else + if (mminfo.mainmem < 257000L && !MS_CheckParm("debugmode")) +#endif + { + memptr screen; + + CA_CacheGrChunk (ERRORSCREEN); + screen = grsegs[ERRORSCREEN]; + ShutdownId(); + movedata ((unsigned)screen,7+7*160,0xb800,0,17*160); + gotoxy (1,23); + exit(1); + } + + +// +// build some tables +// + InitDigiMap (); + + for (i=0;i YEAR || + (d.month >= MONTH && d.day >= DAY)) + { + printf("Sorry, BETA-TESTING is over. Thanks for you help.\n"); + exit(1); + } +#endif + + CheckForEpisodes(); + + Patch386 (); + + InitGame (); + + DemoLoop(); + + Quit("Demo loop exited???"); +} + diff --git a/src/lib/hb/menu/wl_menu.c b/src/lib/hb/menu/wl_menu.c new file mode 100755 index 00000000..7d1521cb --- /dev/null +++ b/src/lib/hb/menu/wl_menu.c @@ -0,0 +1,3986 @@ +//////////////////////////////////////////////////////////////////// +// +// WL_MENU.C +// by John Romero (C) 1992 Id Software, Inc. +// +//////////////////////////////////////////////////////////////////// +#include "wl_def.h" +#pragma hdrstop + +// +// PRIVATE PROTOTYPES +// +void CP_ReadThis(void); + +#ifdef SPEAR +#define STARTITEM newgame + +#else +#ifdef GOODTIMES +#define STARTITEM newgame + +#else +#define STARTITEM readthis +#endif +#endif + +char far endStrings[9][80]= +{ +#ifndef SPEAR + {"Dost thou wish to\nleave with such hasty\nabandon?"}, + {"Chickening out...\nalready?"}, + {"Press N for more carnage.\nPress Y to be a weenie."}, + {"So, you think you can\nquit this easily, huh?"}, + {"Press N to save the world.\nPress Y to abandon it in\nits hour of need."}, + {"Press N if you are brave.\nPress Y to cower in shame."}, + {"Heroes, press N.\nWimps, press Y."}, + {"You are at an intersection.\nA sign says, 'Press Y to quit.'\n>"}, + {"For guns and glory, press N.\nFor work and worry, press Y."} +#else + ENDSTR1, + ENDSTR2, + ENDSTR3, + ENDSTR4, + ENDSTR5, + ENDSTR6, + ENDSTR7, + ENDSTR8, + ENDSTR9 +#endif +}; + +CP_iteminfo + MainItems={MENU_X,MENU_Y,10,STARTITEM,24}, + SndItems={SM_X,SM_Y1,12,0,52}, + LSItems={LSM_X,LSM_Y,10,0,24}, + CtlItems={CTL_X,CTL_Y,6,-1,56}, + CusItems={8,CST_Y+13*2,9,-1,0}, + NewEitems={NE_X,NE_Y,11,0,88}, + NewItems={NM_X,NM_Y,4,2,24}; + +#pragma warn -sus +CP_itemtype far +MainMenu[]= +{ +#ifdef JAPAN + {1,"",CP_NewGame}, + {1,"",CP_Sound}, + {1,"",CP_Control}, + {1,"",CP_LoadGame}, + {0,"",CP_SaveGame}, + {1,"",CP_ChangeView}, + {2,"",CP_ReadThis}, + {1,"",CP_ViewScores}, + {1,"",0}, + {1,"",0} +#else + + {1,STR_NG,CP_NewGame}, + {1,STR_SD,CP_Sound}, + {1,STR_CL,CP_Control}, + {1,STR_LG,CP_LoadGame}, + {0,STR_SG,CP_SaveGame}, + {1,STR_CV,CP_ChangeView}, + +#ifndef GOODTIMES +#ifndef SPEAR + + #ifdef SPANISH + {2,"Ve esto!",CP_ReadThis}, + #else + {2,"Read This!",CP_ReadThis}, + #endif + +#endif +#endif + + {1,STR_VS,CP_ViewScores}, + {1,STR_BD,0}, + {1,STR_QT,0} +#endif +}, + +far SndMenu[]= +{ +#ifdef JAPAN + {1,"",0}, + {1,"",0}, + {1,"",0}, + {0,"",0}, + {0,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {0,"",0}, + {0,"",0}, + {1,"",0}, + {1,"",0}, +#else + {1,STR_NONE,0}, + {1,STR_PC,0}, + {1,STR_ALSB,0}, + {0,"",0}, + {0,"",0}, + {1,STR_NONE,0}, + {1,STR_DISNEY,0}, + {1,STR_SB,0}, + {0,"",0}, + {0,"",0}, + {1,STR_NONE,0}, + {1,STR_ALSB,0} +#endif +}, + +far CtlMenu[]= +{ +#ifdef JAPAN + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",MouseSensitivity}, + {1,"",CustomControls} +#else + {0,STR_MOUSEEN,0}, + {0,STR_JOYEN,0}, + {0,STR_PORT2,0}, + {0,STR_GAMEPAD,0}, + {0,STR_SENS,MouseSensitivity}, + {1,STR_CUSTOM,CustomControls} +#endif +}, + +#pragma warn +sus + +#ifndef SPEAR +far NewEmenu[]= +{ +#ifdef JAPAN +#ifdef JAPDEMO + {1,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, + {0,"",0}, +#else + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0} +#endif +#else + #ifdef SPANISH + {1,"Episodio 1\n" + "Fuga desde Wolfenstein",0}, + {0,"",0}, + {3,"Episodio 2\n" + "Operacion Eisenfaust",0}, + {0,"",0}, + {3,"Episodio 3\n" + "Muere, Fuhrer, Muere!",0}, + {0,"",0}, + {3,"Episodio 4\n" + "Un Negro Secreto",0}, + {0,"",0}, + {3,"Episodio 5\n" + "Huellas del Loco",0}, + {0,"",0}, + {3,"Episodio 6\n" + "Confrontacion",0} + #else + {1,"Episode 1\n" + "Escape from Wolfenstein",0}, + {0,"",0}, + {3,"Episode 2\n" + "Operation: Eisenfaust",0}, + {0,"",0}, + {3,"Episode 3\n" + "Die, Fuhrer, Die!",0}, + {0,"",0}, + {3,"Episode 4\n" + "A Dark Secret",0}, + {0,"",0}, + {3,"Episode 5\n" + "Trail of the Madman",0}, + {0,"",0}, + {3,"Episode 6\n" + "Confrontation",0} + #endif +#endif +}, +#endif + + +far NewMenu[]= +{ +#ifdef JAPAN + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0} +#else + {1,STR_DADDY,0}, + {1,STR_HURTME,0}, + {1,STR_BRINGEM,0}, + {1,STR_DEATH,0} +#endif +}, + +far LSMenu[]= +{ + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0}, + {1,"",0} +}, + +far CusMenu[]= +{ + {1,"",0}, + {0,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {0,"",0}, + {1,"",0}, + {0,"",0}, + {1,"",0} +} +; + + +int color_hlite[]={ + DEACTIVE, + HIGHLIGHT, + READHCOLOR, + 0x67 + }, + + color_norml[]={ + DEACTIVE, + TEXTCOLOR, + READCOLOR, + 0x6b + }; + +int EpisodeSelect[6]={1}; + + +int SaveGamesAvail[10],StartGame,SoundStatus=1,pickquick; +char SaveGameNames[10][32],SaveName[13]="SAVEGAM?."; + + +//////////////////////////////////////////////////////////////////// +// +// INPUT MANAGER SCANCODE TABLES +// +//////////////////////////////////////////////////////////////////// +static byte + *ScanNames[] = // Scan code names with single chars + { + "?","?","1","2","3","4","5","6","7","8","9","0","-","+","?","?", + "Q","W","E","R","T","Y","U","I","O","P","[","]","|","?","A","S", + "D","F","G","H","J","K","L",";","\"","?","?","?","Z","X","C","V", + "B","N","M",",",".","/","?","?","?","?","?","?","?","?","?","?", + "?","?","?","?","?","?","?","?","\xf","?","-","\x15","5","\x11","+","?", + "\x13","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?", + "?","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?", + "?","?","?","?","?","?","?","?","?","?","?","?","?","?","?","?" + }, // DEBUG - consolidate these + far ExtScanCodes[] = // Scan codes with >1 char names + { + 1,0xe,0xf,0x1d,0x2a,0x39,0x3a,0x3b,0x3c,0x3d,0x3e, + 0x3f,0x40,0x41,0x42,0x43,0x44,0x57,0x59,0x46,0x1c,0x36, + 0x37,0x38,0x47,0x49,0x4f,0x51,0x52,0x53,0x45,0x48, + 0x50,0x4b,0x4d,0x00 + }, + *ExtScanNames[] = // Names corresponding to ExtScanCodes + { + "Esc","BkSp","Tab","Ctrl","LShft","Space","CapsLk","F1","F2","F3","F4", + "F5","F6","F7","F8","F9","F10","F11","F12","ScrlLk","Enter","RShft", + "PrtSc","Alt","Home","PgUp","End","PgDn","Ins","Del","NumLk","Up", + "Down","Left","Right","" + }; + + +//////////////////////////////////////////////////////////////////// +// +// Wolfenstein Control Panel! Ta Da! +// +//////////////////////////////////////////////////////////////////// +void US_ControlPanel(byte scancode) +{ + int which,i,start; + + + if (ingame) + if (CP_CheckQuick(scancode)) + return; + + StartCPMusic(MENUSONG); + SetupControlPanel(); + + // + // F-KEYS FROM WITHIN GAME + // + switch(scancode) + { + case sc_F1: + #ifdef SPEAR + BossKey(); + #else + #ifdef GOODTIMES + BossKey(); + #else + HelpScreens(); + #endif + #endif + goto finishup; + + case sc_F2: + CP_SaveGame(0); + goto finishup; + + case sc_F3: + CP_LoadGame(0); + goto finishup; + + case sc_F4: + CP_Sound(); + goto finishup; + + case sc_F5: + CP_ChangeView(); + goto finishup; + + case sc_F6: + CP_Control(); + goto finishup; + + finishup: + CleanupControlPanel(); + #ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + #endif + return; + } + +#ifdef SPEAR + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif + + DrawMainMenu(); + MenuFadeIn(); + StartGame=0; + + // + // MAIN MENU LOOP + // + do + { + which=HandleMenu(&MainItems,&MainMenu[0],NULL); + + #ifdef SPEAR + #ifndef SPEARDEMO + // + // EASTER EGG FOR SPEAR OF DESTINY! + // + if (Keyboard[sc_I] && Keyboard[sc_D]) + { + VW_FadeOut(); + StartCPMusic (XJAZNAZI_MUS); + UnCacheLump(OPTIONS_LUMP_START,OPTIONS_LUMP_END); + UnCacheLump(BACKDROP_LUMP_START,BACKDROP_LUMP_END); + MM_SortMem (); + ClearMemory (); + + + CA_CacheGrChunk (IDGUYS1PIC); + VWB_DrawPic(0,0,IDGUYS1PIC); + UNCACHEGRCHUNK(IDGUYS1PIC); + + CA_CacheGrChunk (IDGUYS2PIC); + VWB_DrawPic(0,80,IDGUYS2PIC); + UNCACHEGRCHUNK(IDGUYS2PIC); + + VW_UpdateScreen(); + + CA_CacheGrChunk (IDGUYSPALETTE); + VL_FadeIn(0,255,grsegs[IDGUYSPALETTE],30); + UNCACHEGRCHUNK(IDGUYSPALETTE); + + while (Keyboard[sc_I] || Keyboard[sc_D]); + IN_ClearKeysDown(); + IN_Ack(); + + VW_FadeOut(); + + CacheLump(BACKDROP_LUMP_START,BACKDROP_LUMP_END); + CacheLump(OPTIONS_LUMP_START,OPTIONS_LUMP_END); + DrawMainMenu(); + StartCPMusic (MENUSONG); + MenuFadeIn(); + } + #endif + #endif + + switch(which) + { + case viewscores: + if (MainMenu[viewscores].routine == NULL) + if (CP_EndGame()) + StartGame=1; + + DrawMainMenu(); + MenuFadeIn(); + break; + + case backtodemo: + #ifdef SPEAR + if (!ingame) + { + // + // DEALLOCATE ALL SOUNDS! + // + switch (SoundMode) + { + case sdm_PC: + start = STARTPCSOUNDS; + break; + case sdm_AdLib: + start = STARTADLIBSOUNDS; + break; + } + + if (SoundMode != sdm_Off) + for (i=0;i"); + while (!Keyboard[sc_Escape]) + IN_ClearKeysDown(); + + SD_MusicOn(); + VL_SetVGAPlaneMode (); + VL_TestPaletteSet (); + VL_SetPalette (&gamepal); + LoadLatchMem(); +} +#endif +#endif + +//////////////////////////////////////////////////////////////////// +// +// CHECK QUICK-KEYS & QUIT (WHILE IN A GAME) +// +//////////////////////////////////////////////////////////////////// +int CP_CheckQuick(unsigned scancode) +{ + switch(scancode) + { + // + // END GAME + // + case sc_F7: + CA_CacheGrChunk(STARTFONT+1); + + WindowH=160; + #ifdef JAPAN + if (GetYorN(7,8,C_JAPQUITPIC)) + #else + if (Confirm(ENDGAMESTR)) + #endif + { + playstate = ex_died; + pickquick = gamestate.lives = 0; + } + + DrawAllPlayBorder(); + WindowH=200; + fontnumber=0; + MainMenu[savegame].active = 0; + return 1; + + // + // QUICKSAVE + // + case sc_F8: + if (SaveGamesAvail[LSItems.curpos] && pickquick) + { + CA_CacheGrChunk(STARTFONT+1); + fontnumber = 1; + Message(STR_SAVING"..."); + CP_SaveGame(1); + fontnumber=0; + } + else + { + #ifndef SPEAR + CA_CacheGrChunk(STARTFONT+1); + CA_CacheGrChunk(C_CURSOR1PIC); + CA_CacheGrChunk(C_CURSOR2PIC); + CA_CacheGrChunk(C_DISKLOADING1PIC); + CA_CacheGrChunk(C_DISKLOADING2PIC); + CA_CacheGrChunk(C_SAVEGAMEPIC); + CA_CacheGrChunk(C_MOUSELBACKPIC); + #else + CacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + CA_CacheGrChunk(C_CURSOR1PIC); + #endif + + VW_FadeOut (); + + StartCPMusic(MENUSONG); + pickquick=CP_SaveGame(0); + + SETFONTCOLOR(0,15); + IN_ClearKeysDown(); + DrawPlayScreen (); + + if (!startgame && !loadedgame) + { + VW_FadeIn (); + StartMusic (); + } + + if (loadedgame) + playstate = ex_abort; + lasttimecount = TimeCount; + + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + + PM_CheckMainMem (); + + #ifndef SPEAR + UNCACHEGRCHUNK(C_CURSOR1PIC); + UNCACHEGRCHUNK(C_CURSOR2PIC); + UNCACHEGRCHUNK(C_DISKLOADING1PIC); + UNCACHEGRCHUNK(C_DISKLOADING2PIC); + UNCACHEGRCHUNK(C_SAVEGAMEPIC); + UNCACHEGRCHUNK(C_MOUSELBACKPIC); + #else + UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + #endif + } + return 1; + + // + // QUICKLOAD + // + case sc_F9: + if (SaveGamesAvail[LSItems.curpos] && pickquick) + { + char string[100]=STR_LGC; + + + CA_CacheGrChunk(STARTFONT+1); + fontnumber = 1; + + strcat(string,SaveGameNames[LSItems.curpos]); + strcat(string,"\"?"); + + if (Confirm(string)) + CP_LoadGame(1); + + DrawAllPlayBorder(); + fontnumber=0; + } + else + { + #ifndef SPEAR + CA_CacheGrChunk(STARTFONT+1); + CA_CacheGrChunk(C_CURSOR1PIC); + CA_CacheGrChunk(C_CURSOR2PIC); + CA_CacheGrChunk(C_DISKLOADING1PIC); + CA_CacheGrChunk(C_DISKLOADING2PIC); + CA_CacheGrChunk(C_LOADGAMEPIC); + CA_CacheGrChunk(C_MOUSELBACKPIC); + #else + CA_CacheGrChunk(C_CURSOR1PIC); + CacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + #endif + + VW_FadeOut (); + + StartCPMusic(MENUSONG); + pickquick=CP_LoadGame(0); + + SETFONTCOLOR(0,15); + IN_ClearKeysDown(); + DrawPlayScreen (); + + if (!startgame && !loadedgame) + { + VW_FadeIn (); + StartMusic (); + } + + if (loadedgame) + playstate = ex_abort; + + lasttimecount = TimeCount; + + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + PM_CheckMainMem (); + + #ifndef SPEAR + UNCACHEGRCHUNK(C_CURSOR1PIC); + UNCACHEGRCHUNK(C_CURSOR2PIC); + UNCACHEGRCHUNK(C_DISKLOADING1PIC); + UNCACHEGRCHUNK(C_DISKLOADING2PIC); + UNCACHEGRCHUNK(C_LOADGAMEPIC); + UNCACHEGRCHUNK(C_MOUSELBACKPIC); + #else + UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + #endif + } + return 1; + + // + // QUIT + // + case sc_F10: + CA_CacheGrChunk(STARTFONT+1); + + WindowX=WindowY=0; + WindowW=320; + WindowH=160; + #ifdef JAPAN + if (GetYorN(7,8,C_QUITMSGPIC)) + #else + #ifdef SPANISH + if (Confirm(ENDGAMESTR)) + #else + if (Confirm(endStrings[US_RndT()&0x7+(US_RndT()&1)])) + #endif + #endif + { + int i; + + + VW_UpdateScreen(); + SD_MusicOff(); + SD_StopSound(); + MenuFadeOut(); + + // + // SHUT-UP THE ADLIB + // + for (i=1;i<=0xf5;i++) + alOut(i,0); + Quit(NULL); + } + + DrawAllPlayBorder(); + WindowH=200; + fontnumber=0; + return 1; + } + + return 0; +} + + +//////////////////////////////////////////////////////////////////// +// +// END THE CURRENT GAME +// +//////////////////////////////////////////////////////////////////// +int CP_EndGame(void) +{ +#ifdef JAPAN + if (!GetYorN(7,8,C_JAPQUITPIC)) +#else + if (!Confirm(ENDGAMESTR)) +#endif + return 0; + + pickquick = gamestate.lives = 0; + playstate = ex_died; + + #pragma warn -sus + MainMenu[savegame].active = 0; + MainMenu[viewscores].routine=CP_ViewScores; + #ifndef JAPAN + _fstrcpy(MainMenu[viewscores].string,STR_VS); + #endif + #pragma warn +sus + + return 1; +} + + +//////////////////////////////////////////////////////////////////// +// +// VIEW THE HIGH SCORES +// +//////////////////////////////////////////////////////////////////// +void CP_ViewScores(void) +{ + fontnumber=0; + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + StartCPMusic (XAWARD_MUS); +#else + StartCPMusic (ROSTER_MUS); +#endif + + DrawHighScores (); + VW_UpdateScreen (); + MenuFadeIn(); + fontnumber=1; + + IN_Ack(); + + StartCPMusic(MENUSONG); + MenuFadeOut(); + +#ifdef SPEAR + CacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif +} + + +//////////////////////////////////////////////////////////////////// +// +// START A NEW GAME +// +//////////////////////////////////////////////////////////////////// +void CP_NewGame(void) +{ + int which,episode; + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif + + +#ifndef SPEAR +firstpart: + + DrawNewEpisode(); + do + { + which=HandleMenu(&NewEitems,&NewEmenu[0],NULL); + switch(which) + { + case -1: + MenuFadeOut(); + return; + + default: + if (!EpisodeSelect[which/2]) + { + SD_PlaySound (NOWAYSND); + Message("Please select \"Read This!\"\n" + "from the Options menu to\n" + "find out how to order this\n" + "episode from Apogee."); + IN_ClearKeysDown(); + IN_Ack(); + DrawNewEpisode(); + which = 0; + } + else + { + episode = which/2; + which = 1; + } + break; + } + + } while (!which); + + ShootSnd(); + + // + // ALREADY IN A GAME? + // + if (ingame) + #ifdef JAPAN + if (!GetYorN(7,8,C_JAPNEWGAMEPIC)) + #else + if (!Confirm(CURGAME)) + #endif + { + MenuFadeOut(); + return; + } + + MenuFadeOut(); + +#else + episode = 0; + + // + // ALREADY IN A GAME? + // + CacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END); + DrawNewGame(); + if (ingame) + if (!Confirm(CURGAME)) + { + MenuFadeOut(); + UnCacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + return; + } + +#endif + + DrawNewGame(); + which=HandleMenu(&NewItems,&NewMenu[0],DrawNewGameDiff); + if (which<0) + { + MenuFadeOut(); + #ifndef SPEAR + goto firstpart; + #else + UnCacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + return; + #endif + } + + ShootSnd(); + NewGame(which,episode); + StartGame=1; + MenuFadeOut(); + + // + // CHANGE "READ THIS!" TO NORMAL COLOR + // + #ifndef SPEAR + #ifndef GOODTIMES + MainMenu[readthis].active=1; + #endif + #endif + + pickquick = 0; + +#ifdef SPEAR + UnCacheLump (NEWGAME_LUMP_START,NEWGAME_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif +} + + +#ifndef SPEAR +///////////////////// +// +// DRAW NEW EPISODE MENU +// +void DrawNewEpisode(void) +{ + int i; + +#ifdef JAPAN + CA_CacheScreen(S_EPISODEPIC); +#else + ClearMScreen(); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + + DrawWindow(NE_X-4,NE_Y-4,NE_W+8,NE_H+8,BKGDCOLOR); + SETFONTCOLOR(READHCOLOR,BKGDCOLOR); + PrintY=2; + WindowX=0; + #ifdef SPANISH + US_CPrint("Cual episodio jugar?"); + #else + US_CPrint("Which episode to play?"); + #endif +#endif + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + DrawMenu(&NewEitems,&NewEmenu[0]); + + for (i=0;i<6;i++) + VWB_DrawPic(NE_X+32,NE_Y+i*26,C_EPISODE1PIC+i); + + VW_UpdateScreen(); + MenuFadeIn(); + WaitKeyUp(); +} +#endif + +///////////////////// +// +// DRAW NEW GAME MENU +// +void DrawNewGame(void) +{ +#ifdef JAPAN + CA_CacheScreen(S_SKILLPIC); +#else + ClearMScreen(); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + + SETFONTCOLOR(READHCOLOR,BKGDCOLOR); + PrintX=NM_X+20; + PrintY=NM_Y-32; + +#ifndef SPEAR + #ifdef SPANISH + US_Print("Eres macho?"); + #else + US_Print("How tough are you?"); + #endif +#else + VWB_DrawPic (PrintX,PrintY,C_HOWTOUGHPIC); +#endif + + DrawWindow(NM_X-5,NM_Y-10,NM_W,NM_H,BKGDCOLOR); +#endif + + DrawMenu(&NewItems,&NewMenu[0]); + DrawNewGameDiff(NewItems.curpos); + VW_UpdateScreen(); + MenuFadeIn(); + WaitKeyUp(); +} + + +//////////////////////// +// +// DRAW NEW GAME GRAPHIC +// +void DrawNewGameDiff(int w) +{ + VWB_DrawPic(NM_X+185,NM_Y+7,w+C_BABYMODEPIC); +} + + +//////////////////////////////////////////////////////////////////// +// +// HANDLE SOUND MENU +// +//////////////////////////////////////////////////////////////////// +void CP_Sound(void) +{ + int which,i; + + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + CacheLump (SOUND_LUMP_START,SOUND_LUMP_END); +#endif + + DrawSoundMenu(); + MenuFadeIn(); + WaitKeyUp(); + + do + { + which=HandleMenu(&SndItems,&SndMenu[0],NULL); + // + // HANDLE MENU CHOICES + // + switch(which) + { + // + // SOUND EFFECTS + // + case 0: + if (SoundMode!=sdm_Off) + { + SD_WaitSoundDone(); + SD_SetSoundMode(sdm_Off); + DrawSoundMenu(); + } + break; + case 1: + if (SoundMode!=sdm_PC) + { + SD_WaitSoundDone(); + SD_SetSoundMode(sdm_PC); + CA_LoadAllSounds(); + DrawSoundMenu(); + ShootSnd(); + } + break; + case 2: + if (SoundMode!=sdm_AdLib) + { + SD_WaitSoundDone(); + SD_SetSoundMode(sdm_AdLib); + CA_LoadAllSounds(); + DrawSoundMenu(); + ShootSnd(); + } + break; + + // + // DIGITIZED SOUND + // + case 5: + if (DigiMode!=sds_Off) + { + SD_SetDigiDevice(sds_Off); + DrawSoundMenu(); + } + break; + case 6: + if (DigiMode!=sds_SoundSource) + { + SD_SetDigiDevice(sds_SoundSource); + DrawSoundMenu(); + ShootSnd(); + } + break; + case 7: + if (DigiMode!=sds_SoundBlaster) + { + SD_SetDigiDevice(sds_SoundBlaster); + DrawSoundMenu(); + ShootSnd(); + } + break; + + // + // MUSIC + // + case 10: + if (MusicMode!=smm_Off) + { + SD_SetMusicMode(smm_Off); + DrawSoundMenu(); + ShootSnd(); + } + break; + case 11: + if (MusicMode!=smm_AdLib) + { + SD_SetMusicMode(smm_AdLib); + DrawSoundMenu(); + ShootSnd(); + StartCPMusic(MENUSONG); + } + break; + } + } while(which>=0); + + MenuFadeOut(); + +#ifdef SPEAR + UnCacheLump (SOUND_LUMP_START,SOUND_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif +} + + +////////////////////// +// +// DRAW THE SOUND MENU +// +void DrawSoundMenu(void) +{ + int i,on; + + +#ifdef JAPAN + CA_CacheScreen(S_SOUNDPIC); +#else + // + // DRAW SOUND MENU + // + ClearMScreen(); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + + DrawWindow(SM_X-8,SM_Y1-3,SM_W,SM_H1,BKGDCOLOR); + DrawWindow(SM_X-8,SM_Y2-3,SM_W,SM_H2,BKGDCOLOR); + DrawWindow(SM_X-8,SM_Y3-3,SM_W,SM_H3,BKGDCOLOR); +#endif + + // + // IF NO ADLIB, NON-CHOOSENESS! + // + if (!AdLibPresent && !SoundBlasterPresent) + { + SndMenu[2].active=SndMenu[10].active=SndMenu[11].active=0; + } + + if (!SoundSourcePresent) + SndMenu[6].active=0; + + if (!SoundBlasterPresent) + SndMenu[7].active=0; + + if (!SoundSourcePresent && !SoundBlasterPresent) + SndMenu[5].active=0; + + DrawMenu(&SndItems,&SndMenu[0]); +#ifndef JAPAN + VWB_DrawPic(100,SM_Y1-20,C_FXTITLEPIC); + VWB_DrawPic(100,SM_Y2-20,C_DIGITITLEPIC); + VWB_DrawPic(100,SM_Y3-20,C_MUSICTITLEPIC); +#endif + + for (i=0;i=0 && SaveGamesAvail[which]) + { + ShootSnd(); + name[7]=which+'0'; + + handle=open(name,O_BINARY); + lseek(handle,32,SEEK_SET); + + DrawLSAction(0); + loadedgame=true; + + LoadTheGame(handle,LSA_X+8,LSA_Y+5); + close(handle); + + StartGame=1; + ShootSnd(); + // + // CHANGE "READ THIS!" TO NORMAL COLOR + // + + #ifndef SPEAR + #ifndef GOODTIMES + MainMenu[readthis].active=1; + #endif + #endif + + exit=1; + break; + } + + } while(which>=0); + + MenuFadeOut(); + +#ifdef SPEAR + UnCacheLump (LOADSAVE_LUMP_START,LOADSAVE_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif + + return exit; +} + + +/////////////////////////////////// +// +// HIGHLIGHT CURRENT SELECTED ENTRY +// +void TrackWhichGame(int w) +{ + static int lastgameon=0; + + PrintLSEntry(lastgameon,TEXTCOLOR); + PrintLSEntry(w,HIGHLIGHT); + + lastgameon=w; +} + + +//////////////////////////// +// +// DRAW THE LOAD/SAVE SCREEN +// +void DrawLoadSaveScreen(int loadsave) +{ + #define DISKX 100 + #define DISKY 0 + + int i; + + + ClearMScreen(); + fontnumber=1; + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + DrawWindow(LSM_X-10,LSM_Y-5,LSM_W,LSM_H,BKGDCOLOR); + DrawStripes(10); + + if (!loadsave) + VWB_DrawPic(60,0,C_LOADGAMEPIC); + else + VWB_DrawPic(60,0,C_SAVEGAMEPIC); + + for (i=0;i<10;i++) + PrintLSEntry(i,TEXTCOLOR); + + DrawMenu(&LSItems,&LSMenu[0]); + VW_UpdateScreen(); + MenuFadeIn(); + WaitKeyUp(); +} + + +/////////////////////////////////////////// +// +// PRINT LOAD/SAVE GAME ENTRY W/BOX OUTLINE +// +void PrintLSEntry(int w,int color) +{ + SETFONTCOLOR(color,BKGDCOLOR); + DrawOutline(LSM_X+LSItems.indent,LSM_Y+w*13,LSM_W-LSItems.indent-15,11,color,color); + PrintX=LSM_X+LSItems.indent+2; + PrintY=LSM_Y+w*13+1; + fontnumber=0; + + if (SaveGamesAvail[w]) + US_Print(SaveGameNames[w]); + else + US_Print(" - "STR_EMPTY" -"); + + fontnumber=1; +} + + +//////////////////////////////////////////////////////////////////// +// +// SAVE CURRENT GAME +// +//////////////////////////////////////////////////////////////////// +int CP_SaveGame(int quick) +{ + int handle,which,exit=0; + unsigned nwritten; + char name[13],input[32]; + + + strcpy(name,SaveName); + + // + // QUICKSAVE? + // + if (quick) + { + which=LSItems.curpos; + + if (SaveGamesAvail[which]) + { + name[7]=which+'0'; + unlink(name); + handle=creat(name,S_IREAD|S_IWRITE); + + strcpy(input,&SaveGameNames[which][0]); + + _dos_write(handle,(void far *)input,32,&nwritten); + lseek(handle,32,SEEK_SET); + SaveTheGame(handle,0,0); + close(handle); + + return 1; + } + } + + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + CacheLump (LOADSAVE_LUMP_START,LOADSAVE_LUMP_END); +#endif + + DrawLoadSaveScreen(1); + + do + { + which=HandleMenu(&LSItems,&LSMenu[0],TrackWhichGame); + if (which>=0) + { + // + // OVERWRITE EXISTING SAVEGAME? + // + if (SaveGamesAvail[which]) + #ifdef JAPAN + if (!GetYorN(7,8,C_JAPSAVEOVERPIC)) + #else + if (!Confirm(GAMESVD)) + #endif + { + DrawLoadSaveScreen(1); + continue; + } + else + { + DrawLoadSaveScreen(1); + PrintLSEntry(which,HIGHLIGHT); + VW_UpdateScreen(); + } + + ShootSnd(); + + strcpy(input,&SaveGameNames[which][0]); + name[7]=which+'0'; + + fontnumber=0; + if (!SaveGamesAvail[which]) + VWB_Bar(LSM_X+LSItems.indent+1,LSM_Y+which*13+1,LSM_W-LSItems.indent-16,10,BKGDCOLOR); + VW_UpdateScreen(); + + if (US_LineInput(LSM_X+LSItems.indent+2,LSM_Y+which*13+1,input,input,true,31,LSM_W-LSItems.indent-30)) + { + SaveGamesAvail[which]=1; + strcpy(&SaveGameNames[which][0],input); + + unlink(name); + handle=creat(name,S_IREAD|S_IWRITE); + _dos_write(handle,(void far *)input,32,&nwritten); + lseek(handle,32,SEEK_SET); + + DrawLSAction(1); + SaveTheGame(handle,LSA_X+8,LSA_Y+5); + + close(handle); + + ShootSnd(); + exit=1; + } + else + { + VWB_Bar(LSM_X+LSItems.indent+1,LSM_Y+which*13+1,LSM_W-LSItems.indent-16,10,BKGDCOLOR); + PrintLSEntry(which,HIGHLIGHT); + VW_UpdateScreen(); + SD_PlaySound(ESCPRESSEDSND); + continue; + } + + fontnumber=1; + break; + } + + } while(which>=0); + + MenuFadeOut(); + +#ifdef SPEAR + UnCacheLump (LOADSAVE_LUMP_START,LOADSAVE_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif + + return exit; +} + + +//////////////////////////////////////////////////////////////////// +// +// CALIBRATE JOYSTICK +// +//////////////////////////////////////////////////////////////////// +int CalibrateJoystick(void) +{ + #define CALX 85 + #define CALY 40 + #define CALW 158 + #define CALH 140 + + unsigned xmin,ymin,xmax,ymax,jb; + + + + #ifdef JAPAN + VWB_DrawPic(CALX,CALY,C_JOY0PIC); + #else + DrawWindow(CALX-5,CALY-5,CALW,CALH,TEXTCOLOR); + DrawOutline(CALX-5,CALY-5,CALW,CALH,0,HIGHLIGHT); + SETFONTCOLOR(0,TEXTCOLOR); + + WindowX = PrintX = CALX; + WindowW = CALW; + WindowH = CALH; + WindowY = PrintY = CALY; + US_Print(" "STR_CALIB"\n "STR_JOYST"\n"); + VWB_DrawPic(CALX+40,CALY+30,C_JOY1PIC); + PrintY = CALY+80; + US_Print(STR_MOVEJOY); + SETFONTCOLOR(BKGDCOLOR,TEXTCOLOR); + US_Print(" "STR_ESCEXIT); + #endif + VW_UpdateScreen(); + + do + { + jb=IN_JoyButtons(); + if (Keyboard[sc_Escape]) + return 0; + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + + } while(!(jb&1)); + + SD_PlaySound(SHOOTSND); + IN_GetJoyAbs(joystickport,&xmin,&ymin); + + + #ifdef JAPAN + VWB_DrawPic(CALX,CALY,C_JOY1PIC); + #else + DrawWindow(CALX-5,CALY-5,CALW,CALH,TEXTCOLOR); + DrawOutline(CALX-5,CALY-5,CALW,CALH,0,HIGHLIGHT); + SETFONTCOLOR(0,TEXTCOLOR); + + PrintX = CALX; + PrintY = CALY; + US_Print(" "STR_CALIB"\n "STR_JOYST"\n"); + VWB_DrawPic(CALX+40,CALY+30,C_JOY2PIC); + PrintY = CALY+80; + US_Print(STR_MOVEJOY2); + SETFONTCOLOR(BKGDCOLOR,TEXTCOLOR); + US_Print(" "STR_ESCEXIT); + #endif + VW_UpdateScreen(); + + do + { + jb=IN_JoyButtons(); + if (Keyboard[sc_Escape]) + return 0; + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + } while(!(jb&2)); + + IN_GetJoyAbs(joystickport,&xmax,&ymax); + SD_PlaySound(SHOOTSND); + + while (IN_JoyButtons()); + + // + // ASSIGN ACTUAL VALUES HERE + // + if ((xmin != xmax) && (ymin != ymax)) + IN_SetupJoy(joystickport,xmin,xmax,ymin,ymax); + else + return 0; + + return 1; +} + + +//////////////////////////////////////////////////////////////////// +// +// DEFINE CONTROLS +// +//////////////////////////////////////////////////////////////////// +void CP_Control(void) +{ + #define CTL_SPC 70 + enum {MOUSEENABLE,JOYENABLE,USEPORT2,PADENABLE,MOUSESENS,CUSTOMIZE}; + int i,which; + + +#ifdef SPEAR + UnCacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); + CacheLump (CONTROL_LUMP_START,CONTROL_LUMP_END); +#endif + + DrawCtlScreen(); + MenuFadeIn(); + WaitKeyUp(); + + do + { + which=HandleMenu(&CtlItems,&CtlMenu[0],NULL); + switch(which) + { + case MOUSEENABLE: + mouseenabled^=1; + _CX=_DX=CENTER; + Mouse(4); + DrawCtlScreen(); + CusItems.curpos=-1; + ShootSnd(); + break; + + case JOYENABLE: + joystickenabled^=1; + if (joystickenabled) + if (!CalibrateJoystick()) + joystickenabled = 0; + DrawCtlScreen(); + CusItems.curpos=-1; + ShootSnd(); + break; + + case USEPORT2: + joystickport^=1; + DrawCtlScreen(); + ShootSnd(); + break; + + case PADENABLE: + joypadenabled^=1; + DrawCtlScreen(); + ShootSnd(); + break; + + case MOUSESENS: + case CUSTOMIZE: + DrawCtlScreen(); + MenuFadeIn(); + WaitKeyUp(); + break; + } + } while(which>=0); + + MenuFadeOut(); + +#ifdef SPEAR + UnCacheLump (CONTROL_LUMP_START,CONTROL_LUMP_END); + CacheLump (OPTIONS_LUMP_START,OPTIONS_LUMP_END); +#endif +} + + +//////////////////////////////// +// +// DRAW MOUSE SENSITIVITY SCREEN +// +void DrawMouseSens(void) +{ +#ifdef JAPAN + CA_CacheScreen(S_MOUSESENSPIC); +#else + ClearMScreen(); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + #ifdef SPANISH + DrawWindow(10,80,300,43,BKGDCOLOR); + #else + DrawWindow(10,80,300,30,BKGDCOLOR); + #endif + + WindowX=0; + WindowW=320; + PrintY=82; + SETFONTCOLOR(READCOLOR,BKGDCOLOR); + US_CPrint(STR_MOUSEADJ); + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=14; + PrintY=95+13; + US_Print(STR_SLOW); + PrintX=252; + US_Print(STR_FAST); + #else + PrintX=14; + PrintY=95; + US_Print(STR_SLOW); + PrintX=269; + US_Print(STR_FAST); + #endif +#endif + + VWB_Bar(60,97,200,10,TEXTCOLOR); + DrawOutline(60,97,200,10,0,HIGHLIGHT); + DrawOutline(60+20*mouseadjustment,97,20,10,0,READCOLOR); + VWB_Bar(61+20*mouseadjustment,98,19,9,READHCOLOR); + + VW_UpdateScreen(); + MenuFadeIn(); +} + + +/////////////////////////// +// +// ADJUST MOUSE SENSITIVITY +// +void MouseSensitivity(void) +{ + ControlInfo ci; + int exit=0,oldMA; + + + oldMA=mouseadjustment; + DrawMouseSens(); + do + { + ReadAnyControl(&ci); + switch(ci.dir) + { + case dir_North: + case dir_West: + if (mouseadjustment) + { + mouseadjustment--; + VWB_Bar(60,97,200,10,TEXTCOLOR); + DrawOutline(60,97,200,10,0,HIGHLIGHT); + DrawOutline(60+20*mouseadjustment,97,20,10,0,READCOLOR); + VWB_Bar(61+20*mouseadjustment,98,19,9,READHCOLOR); + VW_UpdateScreen(); + SD_PlaySound(MOVEGUN1SND); + while(Keyboard[sc_LeftArrow]); + WaitKeyUp(); + } + break; + + case dir_South: + case dir_East: + if (mouseadjustment<9) + { + mouseadjustment++; + VWB_Bar(60,97,200,10,TEXTCOLOR); + DrawOutline(60,97,200,10,0,HIGHLIGHT); + DrawOutline(60+20*mouseadjustment,97,20,10,0,READCOLOR); + VWB_Bar(61+20*mouseadjustment,98,19,9,READHCOLOR); + VW_UpdateScreen(); + SD_PlaySound(MOVEGUN1SND); + while(Keyboard[sc_RightArrow]); + WaitKeyUp(); + } + break; + } + + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + #else + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("debugmode")) + #endif + PicturePause(); + + if (ci.button0 || Keyboard[sc_Space] || Keyboard[sc_Enter]) + exit=1; + else + if (ci.button1 || Keyboard[sc_Escape]) + exit=2; + + } while(!exit); + + if (exit==2) + { + mouseadjustment=oldMA; + SD_PlaySound(ESCPRESSEDSND); + } + else + SD_PlaySound(SHOOTSND); + + WaitKeyUp(); + MenuFadeOut(); +} + + +/////////////////////////// +// +// DRAW CONTROL MENU SCREEN +// +void DrawCtlScreen(void) +{ + int i,x,y; + + +#ifdef JAPAN + CA_CacheScreen(S_CONTROLPIC); +#else + ClearMScreen(); + DrawStripes(10); + VWB_DrawPic(80,0,C_CONTROLPIC); + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + DrawWindow(CTL_X-8,CTL_Y-5,CTL_W,CTL_H,BKGDCOLOR); +#endif + WindowX=0; + WindowW=320; + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + + if (JoysPresent[0]) + CtlMenu[1].active= + CtlMenu[2].active= + CtlMenu[3].active=1; + + CtlMenu[2].active=CtlMenu[3].active=joystickenabled; + + if (MousePresent) + { + CtlMenu[4].active= + CtlMenu[0].active=1; + } + + CtlMenu[4].active=mouseenabled; + + + DrawMenu(&CtlItems,&CtlMenu[0]); + + + x=CTL_X+CtlItems.indent-24; + y=CTL_Y+3; + if (mouseenabled) + VWB_DrawPic(x,y,C_SELECTEDPIC); + else + VWB_DrawPic(x,y,C_NOTSELECTEDPIC); + + y=CTL_Y+16; + if (joystickenabled) + VWB_DrawPic(x,y,C_SELECTEDPIC); + else + VWB_DrawPic(x,y,C_NOTSELECTEDPIC); + + y=CTL_Y+29; + if (joystickport) + VWB_DrawPic(x,y,C_SELECTEDPIC); + else + VWB_DrawPic(x,y,C_NOTSELECTEDPIC); + + y=CTL_Y+42; + if (joypadenabled) + VWB_DrawPic(x,y,C_SELECTEDPIC); + else + VWB_DrawPic(x,y,C_NOTSELECTEDPIC); + + // + // PICK FIRST AVAILABLE SPOT + // + if (CtlItems.curpos<0 || !CtlMenu[CtlItems.curpos].active) + for (i=0;i<6;i++) + if (CtlMenu[i].active) + { + CtlItems.curpos=i; + break; + } + + DrawMenuGun(&CtlItems); + VW_UpdateScreen(); +} + + +//////////////////////////////////////////////////////////////////// +// +// CUSTOMIZE CONTROLS +// +//////////////////////////////////////////////////////////////////// +enum {FIRE,STRAFE,RUN,OPEN}; +char mbarray[4][3]={"b0","b1","b2","b3"}, + order[4]={RUN,OPEN,FIRE,STRAFE}; + + +void CustomControls(void) +{ + int which; + + + DrawCustomScreen(); + do + { + which=HandleMenu(&CusItems,&CusMenu[0],FixupCustom); + switch(which) + { + case 0: + DefineMouseBtns(); + DrawCustMouse(1); + break; + case 3: + DefineJoyBtns(); + DrawCustJoy(0); + break; + case 6: + DefineKeyBtns(); + DrawCustKeybd(0); + break; + case 8: + DefineKeyMove(); + DrawCustKeys(0); + } + } while(which>=0); + + + + MenuFadeOut(); +} + + +//////////////////////// +// +// DEFINE THE MOUSE BUTTONS +// +void DefineMouseBtns(void) +{ + CustomCtrls mouseallowed={0,1,1,1}; + EnterCtrlData(2,&mouseallowed,DrawCustMouse,PrintCustMouse,MOUSE); +} + + +//////////////////////// +// +// DEFINE THE JOYSTICK BUTTONS +// +void DefineJoyBtns(void) +{ + CustomCtrls joyallowed={1,1,1,1}; + EnterCtrlData(5,&joyallowed,DrawCustJoy,PrintCustJoy,JOYSTICK); +} + + +//////////////////////// +// +// DEFINE THE KEYBOARD BUTTONS +// +void DefineKeyBtns(void) +{ + CustomCtrls keyallowed={1,1,1,1}; + EnterCtrlData(8,&keyallowed,DrawCustKeybd,PrintCustKeybd,KEYBOARDBTNS); +} + + +//////////////////////// +// +// DEFINE THE KEYBOARD BUTTONS +// +void DefineKeyMove(void) +{ + CustomCtrls keyallowed={1,1,1,1}; + EnterCtrlData(10,&keyallowed,DrawCustKeys,PrintCustKeys,KEYBOARDMOVE); +} + + +//////////////////////// +// +// ENTER CONTROL DATA FOR ANY TYPE OF CONTROL +// +enum {FWRD,RIGHT,BKWD,LEFT}; +int moveorder[4]={LEFT,RIGHT,FWRD,BKWD}; + +void EnterCtrlData(int index,CustomCtrls *cust,void (*DrawRtn)(int),void (*PrintRtn)(int),int type) +{ + int j,exit,tick,redraw,which,x,picked; + ControlInfo ci; + + + ShootSnd(); + PrintY=CST_Y+13*index; + IN_ClearKeysDown(); + exit=0; + redraw=1; + // + // FIND FIRST SPOT IN ALLOWED ARRAY + // + for (j=0;j<4;j++) + if (cust->allowed[j]) + { + which=j; + break; + } + + do + { + if (redraw) + { + x=CST_START+CST_SPC*which; + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + + DrawRtn(1); + DrawWindow(x-2,PrintY,CST_SPC,11,TEXTCOLOR); + DrawOutline(x-2,PrintY,CST_SPC,11,0,HIGHLIGHT); + SETFONTCOLOR(0,TEXTCOLOR); + PrintRtn(which); + PrintX=x; + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + VW_UpdateScreen(); + WaitKeyUp(); + redraw=0; + } + + ReadAnyControl(&ci); + + if (type==MOUSE || type==JOYSTICK) + if (IN_KeyDown(sc_Enter)||IN_KeyDown(sc_Control)||IN_KeyDown(sc_Alt)) + { + IN_ClearKeysDown(); + ci.button0=ci.button1=false; + } + + // + // CHANGE BUTTON VALUE? + // + if ((ci.button0|ci.button1|ci.button2|ci.button3)|| + ((type==KEYBOARDBTNS||type==KEYBOARDMOVE) && LastScan==sc_Enter)) + { + tick=TimeCount=picked=0; + SETFONTCOLOR(0,TEXTCOLOR); + + do + { + int button,result=0; + + + if (type==KEYBOARDBTNS||type==KEYBOARDMOVE) + IN_ClearKeysDown(); + + // + // FLASH CURSOR + // + if (TimeCount>10) + { + switch(tick) + { + case 0: + VWB_Bar(x,PrintY+1,CST_SPC-2,10,TEXTCOLOR); + break; + case 1: + PrintX=x; + US_Print("?"); + SD_PlaySound(HITWALLSND); + } + tick^=1; + TimeCount=0; + VW_UpdateScreen(); + } + + // + // WHICH TYPE OF INPUT DO WE PROCESS? + // + switch(type) + { + case MOUSE: + Mouse(3); + button=_BX; + switch(button) + { + case 1: result=1; break; + case 2: result=2; break; + case 4: result=3; break; + } + + if (result) + { + int z; + + + for (z=0;z<4;z++) + if (order[which]==buttonmouse[z]) + { + buttonmouse[z]=bt_nobutton; + break; + } + + buttonmouse[result-1]=order[which]; + picked=1; + SD_PlaySound(SHOOTDOORSND); + } + break; + + case JOYSTICK: + if (ci.button0) result=1; + else + if (ci.button1) result=2; + else + if (ci.button2) result=3; + else + if (ci.button3) result=4; + + if (result) + { + int z; + + + for (z=0;z<4;z++) + if (order[which]==buttonjoy[z]) + { + buttonjoy[z]=bt_nobutton; + break; + } + + buttonjoy[result-1]=order[which]; + picked=1; + SD_PlaySound(SHOOTDOORSND); + } + break; + + case KEYBOARDBTNS: + if (LastScan) + { + buttonscan[order[which]]=LastScan; + picked=1; + ShootSnd(); + IN_ClearKeysDown(); + } + break; + + case KEYBOARDMOVE: + if (LastScan) + { + dirscan[moveorder[which]]=LastScan; + picked=1; + ShootSnd(); + IN_ClearKeysDown(); + } + break; + } + + // + // EXIT INPUT? + // + if (IN_KeyDown(sc_Escape)) + { + picked=1; + continue; + } + + } while(!picked); + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + redraw=1; + WaitKeyUp(); + continue; + } + + if (ci.button1 || IN_KeyDown(sc_Escape)) + exit=1; + + // + // MOVE TO ANOTHER SPOT? + // + switch(ci.dir) + { + case dir_West: + do + { + which--; + if (which<0) + which=3; + } while(!cust->allowed[which]); + redraw=1; + SD_PlaySound(MOVEGUN1SND); + while(ReadAnyControl(&ci),ci.dir!=dir_None); + IN_ClearKeysDown(); + break; + + case dir_East: + do + { + which++; + if (which>3) + which=0; + } while(!cust->allowed[which]); + redraw=1; + SD_PlaySound(MOVEGUN1SND); + while(ReadAnyControl(&ci),ci.dir!=dir_None); + IN_ClearKeysDown(); + break; + case dir_North: + case dir_South: + exit=1; + } + } while(!exit); + + SD_PlaySound(ESCPRESSEDSND); + WaitKeyUp(); + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); +} + + +//////////////////////// +// +// FIXUP GUN CURSOR OVERDRAW SHIT +// +void FixupCustom(int w) +{ + static int lastwhich=-1; + int y=CST_Y+26+w*13; + + + VWB_Hlin(7,32,y-1,DEACTIVE); + VWB_Hlin(7,32,y+12,BORD2COLOR); +#ifndef SPEAR + VWB_Hlin(7,32,y-2,BORDCOLOR); + VWB_Hlin(7,32,y+13,BORDCOLOR); +#else + VWB_Hlin(7,32,y-2,BORD2COLOR); + VWB_Hlin(7,32,y+13,BORD2COLOR); +#endif + + switch(w) + { + case 0: DrawCustMouse(1); break; + case 3: DrawCustJoy(1); break; + case 6: DrawCustKeybd(1); break; + case 8: DrawCustKeys(1); + } + + + if (lastwhich>=0) + { + y=CST_Y+26+lastwhich*13; + VWB_Hlin(7,32,y-1,DEACTIVE); + VWB_Hlin(7,32,y+12,BORD2COLOR); +#ifndef SPEAR + VWB_Hlin(7,32,y-2,BORDCOLOR); + VWB_Hlin(7,32,y+13,BORDCOLOR); +#else + VWB_Hlin(7,32,y-2,BORD2COLOR); + VWB_Hlin(7,32,y+13,BORD2COLOR); +#endif + + if (lastwhich!=w) + switch(lastwhich) + { + case 0: DrawCustMouse(0); break; + case 3: DrawCustJoy(0); break; + case 6: DrawCustKeybd(0); break; + case 8: DrawCustKeys(0); + } + } + + lastwhich=w; +} + + +//////////////////////// +// +// DRAW CUSTOMIZE SCREEN +// +void DrawCustomScreen(void) +{ + int i; + + +#ifdef JAPAN + CA_CacheScreen(S_CUSTOMPIC); + fontnumber=1; + + PrintX=CST_START; + PrintY = CST_Y+26; + DrawCustMouse(0); + + PrintX=CST_START; + US_Print("\n\n\n"); + DrawCustJoy(0); + + PrintX=CST_START; + US_Print("\n\n\n"); + DrawCustKeybd(0); + + PrintX=CST_START; + US_Print("\n\n\n"); + DrawCustKeys(0); +#else + ClearMScreen(); + WindowX=0; + WindowW=320; + VWB_DrawPic(112,184,C_MOUSELBACKPIC); + DrawStripes(10); + VWB_DrawPic(80,0,C_CUSTOMIZEPIC); + + // + // MOUSE + // + SETFONTCOLOR(READCOLOR,BKGDCOLOR); + WindowX=0; + WindowW=320; + +#ifndef SPEAR + PrintY=CST_Y; + US_CPrint("Mouse\n"); +#else + PrintY = CST_Y+13; + VWB_DrawPic (128,48,C_MOUSEPIC); +#endif + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=CST_START-16; + US_Print(STR_CRUN); + PrintX=CST_START-16+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START-16+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START-16+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #else + PrintX=CST_START; + US_Print(STR_CRUN); + PrintX=CST_START+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #endif + + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + DrawCustMouse(0); + US_Print("\n"); + + + // + // JOYSTICK/PAD + // +#ifndef SPEAR + SETFONTCOLOR(READCOLOR,BKGDCOLOR); + US_CPrint("Joystick/Gravis GamePad\n"); +#else + PrintY += 13; + VWB_DrawPic (40,88,C_JOYSTICKPIC); +#endif + +#ifdef SPEAR + VWB_DrawPic (112,120,C_KEYBOARDPIC); +#endif + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=CST_START-16; + US_Print(STR_CRUN); + PrintX=CST_START-16+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START-16+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START-16+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #else + PrintX=CST_START; + US_Print(STR_CRUN); + PrintX=CST_START+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #endif + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + DrawCustJoy(0); + US_Print("\n"); + + + // + // KEYBOARD + // +#ifndef SPEAR + SETFONTCOLOR(READCOLOR,BKGDCOLOR); + US_CPrint("Keyboard\n"); +#else + PrintY += 13; +#endif + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=CST_START-16; + US_Print(STR_CRUN); + PrintX=CST_START-16+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START-16+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START-16+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #else + PrintX=CST_START; + US_Print(STR_CRUN); + PrintX=CST_START+CST_SPC*1; + US_Print(STR_COPEN); + PrintX=CST_START+CST_SPC*2; + US_Print(STR_CFIRE); + PrintX=CST_START+CST_SPC*3; + US_Print(STR_CSTRAFE"\n"); + #endif + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + DrawCustKeybd(0); + US_Print("\n"); + + + // + // KEYBOARD MOVE KEYS + // + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + #ifdef SPANISH + PrintX=4; + US_Print(STR_LEFT); + US_Print("/"); + US_Print(STR_RIGHT); + US_Print("/"); + US_Print(STR_FRWD); + US_Print("/"); + US_Print(STR_BKWD"\n"); + #else + PrintX=CST_START; + US_Print(STR_LEFT); + PrintX=CST_START+CST_SPC*1; + US_Print(STR_RIGHT); + PrintX=CST_START+CST_SPC*2; + US_Print(STR_FRWD); + PrintX=CST_START+CST_SPC*3; + US_Print(STR_BKWD"\n"); + #endif + DrawWindow(5,PrintY-1,310,13,BKGDCOLOR); + DrawCustKeys(0); +#endif + // + // PICK STARTING POINT IN MENU + // + if (CusItems.curpos<0) + for (i=0;i19) + newview=19; + ShowViewSize(newview); + VW_UpdateScreen(); + SD_PlaySound(HITWALLSND); + TicDelay(10); + break; + } + + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + #else + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("debugmode")) + #endif + PicturePause(); + + if (ci.button0 || Keyboard[sc_Enter]) + exit=1; + else + if (ci.button1 || Keyboard[sc_Escape]) + { + viewwidth=oldview*16; + SD_PlaySound(ESCPRESSEDSND); + MenuFadeOut(); + return; + } + + } while(!exit); + + + if (oldview!=newview) + { + SD_PlaySound (SHOOTSND); + Message(STR_THINK"..."); + NewViewSize(newview); + } + + ShootSnd(); + MenuFadeOut(); +} + + +///////////////////////////// +// +// DRAW THE CHANGEVIEW SCREEN +// +void DrawChangeView(int view) +{ +#ifdef JAPAN + CA_CacheScreen(S_CHANGEPIC); + + ShowViewSize(view); +#else + VWB_Bar(0,160,320,40,VIEWCOLOR); + ShowViewSize(view); + + PrintY=161; + WindowX=0; + WindowY=320; + SETFONTCOLOR(HIGHLIGHT,BKGDCOLOR); + + US_CPrint(STR_SIZE1"\n"); + US_CPrint(STR_SIZE2"\n"); + US_CPrint(STR_SIZE3); +#endif + VW_UpdateScreen(); + + MenuFadeIn(); +} + + +//////////////////////////////////////////////////////////////////// +// +// QUIT THIS INFERNAL GAME! +// +//////////////////////////////////////////////////////////////////// +void CP_Quit(void) +{ + int i; + + + #ifdef JAPAN + if (GetYorN(7,11,C_QUITMSGPIC)) + #else + + #ifdef SPANISH + if (Confirm(ENDGAMESTR)) + #else + if (Confirm(endStrings[US_RndT()&0x7+(US_RndT()&1)])) + #endif + + #endif + { + VW_UpdateScreen(); + SD_MusicOff(); + SD_StopSound(); + MenuFadeOut(); + // + // SHUT-UP THE ADLIB + // + for (i=1;i<=0xf5;i++) + alOut(i,0); + Quit(NULL); + } + + DrawMainMenu(); +} + + +//////////////////////////////////////////////////////////////////// +// +// HANDLE INTRO SCREEN (SYSTEM CONFIG) +// +//////////////////////////////////////////////////////////////////// +void IntroScreen(void) +{ +#ifdef SPEAR + +#define MAINCOLOR 0x4f +#define EMSCOLOR 0x4f +#define XMSCOLOR 0x4f + +#else + +#define MAINCOLOR 0x6c +#define EMSCOLOR 0x6c +#define XMSCOLOR 0x6c + +#endif +#define FILLCOLOR 14 + + long memory,emshere,xmshere; + int i,num,ems[10]={100,200,300,400,500,600,700,800,900,1000}, + xms[10]={100,200,300,400,500,600,700,800,900,1000}, + main[10]={32,64,96,128,160,192,224,256,288,320}; + + + // + // DRAW MAIN MEMORY + // + memory=(1023l+mminfo.nearheap+mminfo.farheap)/1024l; + for (i=0;i<10;i++) + if (memory>=main[i]) + VWB_Bar(49,163-8*i,6,5,MAINCOLOR-i); + + + // + // DRAW EMS MEMORY + // + if (EMSPresent) + { + emshere=4l*EMSPagesAvail; + for (i=0;i<10;i++) + if (emshere>=ems[i]) + VWB_Bar(89,163-8*i,6,5,EMSCOLOR-i); + } + + // + // DRAW XMS MEMORY + // + if (XMSPresent) + { + xmshere=4l*XMSPagesAvail; + for (i=0;i<10;i++) + if (xmshere>=xms[i]) + VWB_Bar(129,163-8*i,6,5,XMSCOLOR-i); + } + + // + // FILL BOXES + // + if (MousePresent) + VWB_Bar(164,82,12,2,FILLCOLOR); + + if (JoysPresent[0] || JoysPresent[1]) + VWB_Bar(164,105,12,2,FILLCOLOR); + + if (AdLibPresent && !SoundBlasterPresent) + VWB_Bar(164,128,12,2,FILLCOLOR); + + if (SoundBlasterPresent) + VWB_Bar(164,151,12,2,FILLCOLOR); + + if (SoundSourcePresent) + VWB_Bar(164,174,12,2,FILLCOLOR); +} + + +//////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// +// SUPPORT ROUTINES +// +//////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// +// Clear Menu screens to dark red +// +//////////////////////////////////////////////////////////////////// +void ClearMScreen(void) +{ +#ifndef SPEAR + VWB_Bar(0,0,320,200,BORDCOLOR); +#else + VWB_DrawPic(0,0,C_BACKDROPPIC); +#endif +} + + +//////////////////////////////////////////////////////////////////// +// +// Un/Cache a LUMP of graphics +// +//////////////////////////////////////////////////////////////////// +void CacheLump(int lumpstart,int lumpend) +{ + int i; + + for (i=lumpstart;i<=lumpend;i++) + CA_CacheGrChunk(i); +} + + +void UnCacheLump(int lumpstart,int lumpend) +{ + int i; + + for (i=lumpstart;i<=lumpend;i++) + if (grsegs[i]) + UNCACHEGRCHUNK(i); +} + + +//////////////////////////////////////////////////////////////////// +// +// Draw a window for a menu +// +//////////////////////////////////////////////////////////////////// +void DrawWindow(int x,int y,int w,int h,int wcolor) +{ + VWB_Bar(x,y,w,h,wcolor); + DrawOutline(x,y,w,h,BORD2COLOR,DEACTIVE); +} + + +void DrawOutline(int x,int y,int w,int h,int color1,int color2) +{ + VWB_Hlin(x,x+w,y,color2); + VWB_Vlin(y,y+h,x,color2); + VWB_Hlin(x,x+w,y+h,color1); + VWB_Vlin(y,y+h,x+w,color1); +} + + +//////////////////////////////////////////////////////////////////// +// +// Setup Control Panel stuff - graphics, etc. +// +//////////////////////////////////////////////////////////////////// +void SetupControlPanel(void) +{ + struct ffblk f; + char name[13]; + int which,i; + + + // + // CACHE GRAPHICS & SOUNDS + // + CA_CacheGrChunk(STARTFONT+1); +#ifndef SPEAR + CacheLump(CONTROLS_LUMP_START,CONTROLS_LUMP_END); +#else + CacheLump(BACKDROP_LUMP_START,BACKDROP_LUMP_END); +#endif + + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + fontnumber=1; + WindowH=200; + + if (!ingame) + CA_LoadAllSounds(); + else + MainMenu[savegame].active=1; + + // + // SEE WHICH SAVE GAME FILES ARE AVAILABLE & READ STRING IN + // + strcpy(name,SaveName); + if (!findfirst(name,&f,0)) + do + { + which=f.ff_name[7]-'0'; + if (which<10) + { + int handle; + char temp[32]; + + SaveGamesAvail[which]=1; + handle=open(f.ff_name,O_BINARY); + read(handle,temp,32); + close(handle); + strcpy(&SaveGameNames[which][0],temp); + } + } while(!findnext(&f)); + + // + // CENTER MOUSE + // + _CX=_DX=CENTER; + Mouse(4); +} + + +//////////////////////////////////////////////////////////////////// +// +// Clean up all the Control Panel stuff +// +//////////////////////////////////////////////////////////////////// +void CleanupControlPanel(void) +{ +#ifndef SPEAR + UnCacheLump(CONTROLS_LUMP_START,CONTROLS_LUMP_END); +#else + UnCacheLump (BACKDROP_LUMP_START,BACKDROP_LUMP_END); +#endif + + fontnumber = 0; +} + + +//////////////////////////////////////////////////////////////////// +// +// Handle moving gun around a menu +// +//////////////////////////////////////////////////////////////////// +int HandleMenu(CP_iteminfo *item_i,CP_itemtype far *items,void (*routine)(int w)) +{ + char key; + static int redrawitem=1,lastitem=-1; + int i,x,y,basey,exit,which,shape,timer; + ControlInfo ci; + + + which=item_i->curpos; + x=item_i->x&-8; + basey=item_i->y-2; + y=basey+which*13; + + VWB_DrawPic(x,y,C_CURSOR1PIC); + SetTextColor(items+which,1); + if (redrawitem) + { + PrintX=item_i->x+item_i->indent; + PrintY=item_i->y+which*13; + US_Print((items+which)->string); + } + // + // CALL CUSTOM ROUTINE IF IT IS NEEDED + // + if (routine) + routine(which); + VW_UpdateScreen(); + + shape=C_CURSOR1PIC; + timer=8; + exit=0; + TimeCount=0; + IN_ClearKeysDown(); + + + do + { + // + // CHANGE GUN SHAPE + // + if (TimeCount>timer) + { + TimeCount=0; + if (shape==C_CURSOR1PIC) + { + shape=C_CURSOR2PIC; + timer=8; + } + else + { + shape=C_CURSOR1PIC; + timer=70; + } + VWB_DrawPic(x,y,shape); + if (routine) + routine(which); + VW_UpdateScreen(); + } + + CheckPause(); + + // + // SEE IF ANY KEYS ARE PRESSED FOR INITIAL CHAR FINDING + // + key=LastASCII; + if (key) + { + int ok=0; + + // + // CHECK FOR SCREEN CAPTURE + // + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + #else + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("debugmode")) + #endif + PicturePause(); + + + if (key>='a') + key-='a'-'A'; + + for (i=which+1;iamount;i++) + if ((items+i)->active && (items+i)->string[0]==key) + { + EraseGun(item_i,items,x,y,which); + which=i; + DrawGun(item_i,items,x,&y,which,basey,routine); + ok=1; + IN_ClearKeysDown(); + break; + } + + // + // DIDN'T FIND A MATCH FIRST TIME THRU. CHECK AGAIN. + // + if (!ok) + { + for (i=0;iactive && (items+i)->string[0]==key) + { + EraseGun(item_i,items,x,y,which); + which=i; + DrawGun(item_i,items,x,&y,which,basey,routine); + IN_ClearKeysDown(); + break; + } + } + } + + // + // GET INPUT + // + ReadAnyControl(&ci); + switch(ci.dir) + { + //////////////////////////////////////////////// + // + // MOVE UP + // + case dir_North: + + EraseGun(item_i,items,x,y,which); + + // + // ANIMATE HALF-STEP + // + if (which && (items+which-1)->active) + { + y-=6; + DrawHalfStep(x,y); + } + + // + // MOVE TO NEXT AVAILABLE SPOT + // + do + { + if (!which) + which=item_i->amount-1; + else + which--; + } while(!(items+which)->active); + + DrawGun(item_i,items,x,&y,which,basey,routine); + // + // WAIT FOR BUTTON-UP OR DELAY NEXT MOVE + // + TicDelay(20); + break; + + //////////////////////////////////////////////// + // + // MOVE DOWN + // + case dir_South: + + EraseGun(item_i,items,x,y,which); + // + // ANIMATE HALF-STEP + // + if (which!=item_i->amount-1 && (items+which+1)->active) + { + y+=6; + DrawHalfStep(x,y); + } + + do + { + if (which==item_i->amount-1) + which=0; + else + which++; + } while(!(items+which)->active); + + DrawGun(item_i,items,x,&y,which,basey,routine); + + // + // WAIT FOR BUTTON-UP OR DELAY NEXT MOVE + // + TicDelay(20); + break; + } + + if (ci.button0 || + Keyboard[sc_Space] || + Keyboard[sc_Enter]) + exit=1; + + if (ci.button1 || + Keyboard[sc_Escape]) + exit=2; + + } while(!exit); + + + IN_ClearKeysDown(); + + // + // ERASE EVERYTHING + // + if (lastitem!=which) + { + VWB_Bar(x-1,y,25,16,BKGDCOLOR); + PrintX=item_i->x+item_i->indent; + PrintY=item_i->y+which*13; + US_Print((items+which)->string); + redrawitem=1; + } + else + redrawitem=0; + + if (routine) + routine(which); + VW_UpdateScreen(); + + item_i->curpos=which; + + lastitem=which; + switch(exit) + { + case 1: + // + // CALL THE ROUTINE + // + if ((items+which)->routine!=NULL) + { + ShootSnd(); + MenuFadeOut(); + (items+which)->routine(0); + } + return which; + + case 2: + SD_PlaySound(ESCPRESSEDSND); + return -1; + } + + return 0; // JUST TO SHUT UP THE ERROR MESSAGES! +} + + +// +// ERASE GUN & DE-HIGHLIGHT STRING +// +void EraseGun(CP_iteminfo *item_i,CP_itemtype far *items,int x,int y,int which) +{ + VWB_Bar(x-1,y,25,16,BKGDCOLOR); + SetTextColor(items+which,0); + + PrintX=item_i->x+item_i->indent; + PrintY=item_i->y+which*13; + US_Print((items+which)->string); + VW_UpdateScreen(); +} + + +// +// DRAW HALF STEP OF GUN TO NEXT POSITION +// +void DrawHalfStep(int x,int y) +{ + VWB_DrawPic(x,y,C_CURSOR1PIC); + VW_UpdateScreen(); + SD_PlaySound(MOVEGUN1SND); + TimeCount=0; + while(TimeCount<8); +} + + +// +// DRAW GUN AT NEW POSITION +// +void DrawGun(CP_iteminfo *item_i,CP_itemtype far *items,int x,int *y,int which,int basey,void (*routine)(int w)) +{ + VWB_Bar(x-1,*y,25,16,BKGDCOLOR); + *y=basey+which*13; + VWB_DrawPic(x,*y,C_CURSOR1PIC); + SetTextColor(items+which,1); + + PrintX=item_i->x+item_i->indent; + PrintY=item_i->y+which*13; + US_Print((items+which)->string); + + // + // CALL CUSTOM ROUTINE IF IT IS NEEDED + // + if (routine) + routine(which); + VW_UpdateScreen(); + SD_PlaySound(MOVEGUN2SND); +} + +//////////////////////////////////////////////////////////////////// +// +// DELAY FOR AN AMOUNT OF TICS OR UNTIL CONTROLS ARE INACTIVE +// +//////////////////////////////////////////////////////////////////// +void TicDelay(int count) +{ + ControlInfo ci; + + + TimeCount=0; + do + { + ReadAnyControl(&ci); + } while(TimeCountcurpos; + + + WindowX=PrintX=item_i->x+item_i->indent; + WindowY=PrintY=item_i->y; + WindowW=320; + WindowH=200; + + for (i=0;iamount;i++) + { + SetTextColor(items+i,which==i); + + PrintY=item_i->y+i*13; + if ((items+i)->active) + US_Print((items+i)->string); + else + { + SETFONTCOLOR(DEACTIVE,BKGDCOLOR); + US_Print((items+i)->string); + SETFONTCOLOR(TEXTCOLOR,BKGDCOLOR); + } + + US_Print("\n"); + } +} + + +//////////////////////////////////////////////////////////////////// +// +// SET TEXT COLOR (HIGHLIGHT OR NO) +// +//////////////////////////////////////////////////////////////////// +void SetTextColor(CP_itemtype far *items,int hlight) +{ + if (hlight) + {SETFONTCOLOR(color_hlite[items->active],BKGDCOLOR);} + else + {SETFONTCOLOR(color_norml[items->active],BKGDCOLOR);} +} + + +//////////////////////////////////////////////////////////////////// +// +// WAIT FOR CTRLKEY-UP OR BUTTON-UP +// +//////////////////////////////////////////////////////////////////// +void WaitKeyUp(void) +{ + ControlInfo ci; + while(ReadAnyControl(&ci), ci.button0| + ci.button1| + ci.button2| + ci.button3| + Keyboard[sc_Space]| + Keyboard[sc_Enter]| + Keyboard[sc_Escape]); +} + + +//////////////////////////////////////////////////////////////////// +// +// READ KEYBOARD, JOYSTICK AND MOUSE FOR INPUT +// +//////////////////////////////////////////////////////////////////// +void ReadAnyControl(ControlInfo *ci) +{ + int mouseactive=0; + + + IN_ReadControl(0,ci); + + if (mouseenabled) + { + int mousey,mousex; + + + // READ MOUSE MOTION COUNTERS + // RETURN DIRECTION + // HOME MOUSE + // CHECK MOUSE BUTTONS + + Mouse(3); + mousex=_CX; + mousey=_DX; + + if (mouseydir=dir_North; + _CX=_DX=CENTER; + Mouse(4); + mouseactive=1; + } + else + if (mousey>CENTER+SENSITIVE) + { + ci->dir=dir_South; + _CX=_DX=CENTER; + Mouse(4); + mouseactive=1; + } + + if (mousexdir=dir_West; + _CX=_DX=CENTER; + Mouse(4); + mouseactive=1; + } + else + if (mousex>CENTER+SENSITIVE) + { + ci->dir=dir_East; + _CX=_DX=CENTER; + Mouse(4); + mouseactive=1; + } + + if (IN_MouseButtons()) + { + ci->button0=IN_MouseButtons()&1; + ci->button1=IN_MouseButtons()&2; + ci->button2=IN_MouseButtons()&4; + ci->button3=false; + mouseactive=1; + } + } + + if (joystickenabled && !mouseactive) + { + int jx,jy,jb; + + + INL_GetJoyDelta(joystickport,&jx,&jy); + if (jy<-SENSITIVE) + ci->dir=dir_North; + else + if (jy>SENSITIVE) + ci->dir=dir_South; + + if (jx<-SENSITIVE) + ci->dir=dir_West; + else + if (jx>SENSITIVE) + ci->dir=dir_East; + + jb=IN_JoyButtons(); + if (jb) + { + ci->button0=jb&1; + ci->button1=jb&2; + if (joypadenabled) + { + ci->button2=jb&4; + ci->button3=jb&8; + } + else + ci->button2=ci->button3=false; + } + } +} + + +//////////////////////////////////////////////////////////////////// +// +// DRAW DIALOG AND CONFIRM YES OR NO TO QUESTION +// +//////////////////////////////////////////////////////////////////// +int Confirm(char far *string) +{ + int xit=0,i,x,y,tick=0,time,whichsnd[2]={ESCPRESSEDSND,SHOOTSND}; + + + Message(string); + IN_ClearKeysDown(); + + // + // BLINK CURSOR + // + x=PrintX; + y=PrintY; + TimeCount=0; + + do + { + if (TimeCount>=10) + { + switch(tick) + { + case 0: + VWB_Bar(x,y,8,13,TEXTCOLOR); + break; + case 1: + PrintX=x; + PrintY=y; + US_Print("_"); + } + VW_UpdateScreen(); + tick^=1; + TimeCount=0; + } + + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + + #ifdef SPANISH + } while(!Keyboard[sc_S] && !Keyboard[sc_N] && !Keyboard[sc_Escape]); + #else + } while(!Keyboard[sc_Y] && !Keyboard[sc_N] && !Keyboard[sc_Escape]); + #endif + + #ifdef SPANISH + if (Keyboard[sc_S]) + { + xit=1; + ShootSnd(); + } + + while(Keyboard[sc_S] || Keyboard[sc_N] || Keyboard[sc_Escape]); + + #else + + if (Keyboard[sc_Y]) + { + xit=1; + ShootSnd(); + } + + while(Keyboard[sc_Y] || Keyboard[sc_N] || Keyboard[sc_Escape]); + #endif + + IN_ClearKeysDown(); + SD_PlaySound(whichsnd[xit]); + return xit; +} + +#ifdef JAPAN +//////////////////////////////////////////////////////////////////// +// +// DRAW MESSAGE & GET Y OR N +// +//////////////////////////////////////////////////////////////////// +int GetYorN(int x,int y,int pic) +{ + int xit=0,whichsnd[2]={ESCPRESSEDSND,SHOOTSND}; + + + CA_CacheGrChunk(pic); + VWB_DrawPic(x * 8,y * 8,pic); + UNCACHEGRCHUNK(pic); + VW_UpdateScreen(); + IN_ClearKeysDown(); + + do + { + #ifndef SPEAR + if (Keyboard[sc_Tab] && Keyboard[sc_P] && MS_CheckParm("goobers")) + PicturePause(); + #endif + + #ifdef SPANISH + } while(!Keyboard[sc_S] && !Keyboard[sc_N] && !Keyboard[sc_Escape]); + #else + } while(!Keyboard[sc_Y] && !Keyboard[sc_N] && !Keyboard[sc_Escape]); + #endif + + #ifdef SPANISH + if (Keyboard[sc_S]) + { + xit=1; + ShootSnd(); + } + + while(Keyboard[sc_S] || Keyboard[sc_N] || Keyboard[sc_Escape]); + + #else + + if (Keyboard[sc_Y]) + { + xit=1; + ShootSnd(); + } + + while(Keyboard[sc_Y] || Keyboard[sc_N] || Keyboard[sc_Escape]); + #endif + + IN_ClearKeysDown(); + SD_PlaySound(whichsnd[xit]); + return xit; +} +#endif + + +//////////////////////////////////////////////////////////////////// +// +// PRINT A MESSAGE IN A WINDOW +// +//////////////////////////////////////////////////////////////////// +void Message(char far *string) +{ + int h=0,w=0,mw=0,i,x,y,time; + fontstruct _seg *font; + + + CA_CacheGrChunk (STARTFONT+1); + fontnumber=1; + font=grsegs[STARTFONT+fontnumber]; + h=font->height; + for (i=0;i<_fstrlen(string);i++) + if (string[i]=='\n') + { + if (w>mw) + mw=w; + w=0; + h+=font->height; + } + else + w+=font->width[string[i]]; + + if (w+10>mw) + mw=w+10; + + PrintY=(WindowH/2)-h/2; + PrintX=WindowX=160-mw/2; + + DrawWindow(WindowX-5,PrintY-5,mw+10,h+10,TEXTCOLOR); + DrawOutline(WindowX-5,PrintY-5,mw+10,h+10,0,HIGHLIGHT); + SETFONTCOLOR(0,TEXTCOLOR); + US_Print(string); + VW_UpdateScreen(); +} + + +//////////////////////////////////////////////////////////////////// +// +// THIS MAY BE FIXED A LITTLE LATER... +// +//////////////////////////////////////////////////////////////////// +static int lastmusic; + +void StartCPMusic(int song) +{ + musicnames chunk; + + if (audiosegs[STARTMUSIC + lastmusic]) // JDC + MM_FreePtr ((memptr *)&audiosegs[STARTMUSIC + lastmusic]); + lastmusic = song; + + SD_MusicOff(); + chunk = song; + + MM_BombOnError (false); + CA_CacheAudioChunk(STARTMUSIC + chunk); + MM_BombOnError (true); + if (mmerror) + mmerror = false; + else + { + MM_SetLock(&((memptr)audiosegs[STARTMUSIC + chunk]),true); + SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + chunk]); + } +} + +void FreeMusic (void) +{ + if (audiosegs[STARTMUSIC + lastmusic]) // JDC + MM_FreePtr ((memptr *)&audiosegs[STARTMUSIC + lastmusic]); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// IN_GetScanName() - Returns a string containing the name of the +// specified scan code +// +/////////////////////////////////////////////////////////////////////////// +byte * +IN_GetScanName(ScanCode scan) +{ + byte **p; + ScanCode far *s; + + for (s = ExtScanCodes,p = ExtScanNames;*s;p++,s++) + if (*s == scan) + return(*p); + + return(ScanNames[scan]); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// CHECK FOR PAUSE KEY (FOR MUSIC ONLY) +// +/////////////////////////////////////////////////////////////////////////// +void CheckPause(void) +{ + if (Paused) + { + switch(SoundStatus) + { + case 0: SD_MusicOn(); break; + case 1: SD_MusicOff(); break; + } + + SoundStatus^=1; + VW_WaitVBL(3); + IN_ClearKeysDown(); + Paused=false; + } +} + + +/////////////////////////////////////////////////////////////////////////// +// +// DRAW GUN CURSOR AT CORRECT POSITION IN MENU +// +/////////////////////////////////////////////////////////////////////////// +void DrawMenuGun(CP_iteminfo *iteminfo) +{ + int x,y; + + + x=iteminfo->x; + y=iteminfo->y+iteminfo->curpos*13-2; + VWB_DrawPic(x,y,C_CURSOR1PIC); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// DRAW SCREEN TITLE STRIPES +// +/////////////////////////////////////////////////////////////////////////// +void DrawStripes(int y) +{ +#ifndef SPEAR + VWB_Bar(0,y,320,24,0); + VWB_Hlin(0,319,y+22,STRIPE); +#else + VWB_Bar(0,y,320,22,0); + VWB_Hlin(0,319,y+23,0); +#endif +} + +void ShootSnd(void) +{ + SD_PlaySound(SHOOTSND); +} + + +/////////////////////////////////////////////////////////////////////////// +// +// CHECK FOR EPISODES +// +/////////////////////////////////////////////////////////////////////////// +void CheckForEpisodes(void) +{ + struct ffblk f; + +// +// JAPANESE VERSION +// +#ifdef JAPAN +#ifdef JAPDEMO + if (!findfirst("*.WJ1",&f,FA_ARCH)) + { + strcpy(extension,"WJ1"); +#else + if (!findfirst("*.WJ6",&f,FA_ARCH)) + { + strcpy(extension,"WJ6"); +#endif + strcat(configname,extension); + strcat(SaveName,extension); + strcat(PageFileName,extension); + strcat(audioname,extension); + strcat(demoname,extension); + EpisodeSelect[1] = + EpisodeSelect[2] = + EpisodeSelect[3] = + EpisodeSelect[4] = + EpisodeSelect[5] = 1; + } + else + Quit("NO JAPANESE WOLFENSTEIN 3-D DATA FILES to be found!"); +#else + +// +// ENGLISH +// +#ifndef UPLOAD +#ifndef SPEAR + if (!findfirst("*.WL6",&f,FA_ARCH)) + { + strcpy(extension,"WL6"); + NewEmenu[2].active = + NewEmenu[4].active = + NewEmenu[6].active = + NewEmenu[8].active = + NewEmenu[10].active = + EpisodeSelect[1] = + EpisodeSelect[2] = + EpisodeSelect[3] = + EpisodeSelect[4] = + EpisodeSelect[5] = 1; + } + else + if (!findfirst("*.WL3",&f,FA_ARCH)) + { + strcpy(extension,"WL3"); + NewEmenu[2].active = + NewEmenu[4].active = + EpisodeSelect[1] = + EpisodeSelect[2] = 1; + } + else +#endif +#endif + + + +#ifdef SPEAR +#ifndef SPEARDEMO + if (!findfirst("*.SOD",&f,FA_ARCH)) + { + strcpy(extension,"SOD"); + } + else + Quit("NO SPEAR OF DESTINY DATA FILES TO BE FOUND!"); +#else + if (!findfirst("*.SDM",&f,FA_ARCH)) + { + strcpy(extension,"SDM"); + } + else + Quit("NO SPEAR OF DESTINY DEMO DATA FILES TO BE FOUND!"); +#endif + +#else + if (!findfirst("*.WL1",&f,FA_ARCH)) + { + strcpy(extension,"WL1"); + } + else + Quit("NO WOLFENSTEIN 3-D DATA FILES to be found!"); +#endif + + strcat(configname,extension); + strcat(SaveName,extension); + strcat(PageFileName,extension); + strcat(audioname,extension); + strcat(demoname,extension); +#ifndef SPEAR +#ifndef GOODTIMES + strcat(helpfilename,extension); +#endif + strcat(endfilename,extension); +#endif +#endif +} diff --git a/src/lib/hb/menu/wl_menu.h b/src/lib/hb/menu/wl_menu.h new file mode 100755 index 00000000..dc03400c --- /dev/null +++ b/src/lib/hb/menu/wl_menu.h @@ -0,0 +1,234 @@ +// +// WL_MENU.H +// +#ifdef SPEAR + +#define BORDCOLOR 0x99 +#define BORD2COLOR 0x93 +#define DEACTIVE 0x9b +#define BKGDCOLOR 0x9d +//#define STRIPE 0x9c + +#define MenuFadeOut() VL_FadeOut(0,255,0,0,51,10) + +#else + +#define BORDCOLOR 0x29 +#define BORD2COLOR 0x23 +#define DEACTIVE 0x2b +#define BKGDCOLOR 0x2d +#define STRIPE 0x2c + +#define MenuFadeOut() VL_FadeOut(0,255,43,0,0,10) + +#endif + +#define READCOLOR 0x4a +#define READHCOLOR 0x47 +#define VIEWCOLOR 0x7f +#define TEXTCOLOR 0x17 +#define HIGHLIGHT 0x13 +#define MenuFadeIn() VL_FadeIn(0,255,&gamepal,10) + + +#define MENUSONG WONDERIN_MUS + +#ifndef SPEAR +#define INTROSONG NAZI_NOR_MUS +#else +#define INTROSONG XTOWER2_MUS +#endif + +#define SENSITIVE 60 +#define CENTER SENSITIVE*2 + +#define MENU_X 76 +#define MENU_Y 55 +#define MENU_W 178 +#ifndef SPEAR +#define MENU_H 13*10+6 +#else +#define MENU_H 13*9+6 +#endif + +#define SM_X 48 +#define SM_W 250 + +#define SM_Y1 20 +#define SM_H1 4*13-7 +#define SM_Y2 SM_Y1+5*13 +#define SM_H2 4*13-7 +#define SM_Y3 SM_Y2+5*13 +#define SM_H3 3*13-7 + +#define CTL_X 24 +#define CTL_Y 70 +#define CTL_W 284 +#define CTL_H 13*7-7 + +#define LSM_X 85 +#define LSM_Y 55 +#define LSM_W 175 +#define LSM_H 10*13+10 + +#define NM_X 50 +#define NM_Y 100 +#define NM_W 225 +#define NM_H 13*4+15 + +#define NE_X 10 +#define NE_Y 23 +#define NE_W 320-NE_X*2 +#define NE_H 200-NE_Y*2 + +#define CST_X 20 +#define CST_Y 48 +#define CST_START 60 +#define CST_SPC 60 + + +// +// TYPEDEFS +// +typedef struct { + int x,y,amount,curpos,indent; + } CP_iteminfo; + +typedef struct { + int active; + char string[36]; + void (* routine)(int temp1); + } CP_itemtype; + +typedef struct { + int allowed[4]; + } CustomCtrls; + +extern CP_itemtype far MainMenu[],far NewEMenu[]; +extern CP_iteminfo MainItems; + +// +// FUNCTION PROTOTYPES +// +void SetupControlPanel(void); +void CleanupControlPanel(void); + +void DrawMenu(CP_iteminfo *item_i,CP_itemtype far *items); +int HandleMenu(CP_iteminfo *item_i, + CP_itemtype far *items, + void (*routine)(int w)); +void ClearMScreen(void); +void DrawWindow(int x,int y,int w,int h,int wcolor); +void DrawOutline(int x,int y,int w,int h,int color1,int color2); +void WaitKeyUp(void); +void ReadAnyControl(ControlInfo *ci); +void TicDelay(int count); +void CacheLump(int lumpstart,int lumpend); +void UnCacheLump(int lumpstart,int lumpend); +void StartCPMusic(int song); +int Confirm(char far *string); +void Message(char far *string); +void CheckPause(void); +void ShootSnd(void); +void CheckSecretMissions(void); +void BossKey(void); + +void DrawGun(CP_iteminfo *item_i,CP_itemtype far *items,int x,int *y,int which,int basey,void (*routine)(int w)); +void DrawHalfStep(int x,int y); +void EraseGun(CP_iteminfo *item_i,CP_itemtype far *items,int x,int y,int which); +void SetTextColor(CP_itemtype far *items,int hlight); +void DrawMenuGun(CP_iteminfo *iteminfo); +void DrawStripes(int y); + +void DefineMouseBtns(void); +void DefineJoyBtns(void); +void DefineKeyBtns(void); +void DefineKeyMove(void); +void EnterCtrlData(int index,CustomCtrls *cust,void (*DrawRtn)(int),void (*PrintRtn)(int),int type); + +void DrawMainMenu(void); +void DrawSoundMenu(void); +void DrawLoadSaveScreen(int loadsave); +void DrawNewEpisode(void); +void DrawNewGame(void); +void DrawChangeView(int view); +void DrawMouseSens(void); +void DrawCtlScreen(void); +void DrawCustomScreen(void); +void DrawLSAction(int which); +void DrawCustMouse(int hilight); +void DrawCustJoy(int hilight); +void DrawCustKeybd(int hilight); +void DrawCustKeys(int hilight); +void PrintCustMouse(int i); +void PrintCustJoy(int i); +void PrintCustKeybd(int i); +void PrintCustKeys(int i); + +void PrintLSEntry(int w,int color); +void TrackWhichGame(int w); +void DrawNewGameDiff(int w); +void FixupCustom(int w); + +void CP_NewGame(void); +void CP_Sound(void); +int CP_LoadGame(int quick); +int CP_SaveGame(int quick); +void CP_Control(void); +void CP_ChangeView(void); +void CP_ExitOptions(void); +void CP_Quit(void); +void CP_ViewScores(void); +int CP_EndGame(void); +int CP_CheckQuick(unsigned scancode); +void CustomControls(void); +void MouseSensitivity(void); + +void CheckForEpisodes(void); + +// +// VARIABLES +// +extern int SaveGamesAvail[10],StartGame,SoundStatus; +extern char SaveGameNames[10][32],SaveName[13]; + +enum {MOUSE,JOYSTICK,KEYBOARDBTNS,KEYBOARDMOVE}; // FOR INPUT TYPES + +#ifndef USO_FIX1 +extern +#endif +enum +{ + newgame, + soundmenu, + control, + loadgame, + savegame, + changeview, + +#ifndef GOODTIMES +#ifndef SPEAR + readthis, +#endif +#endif + + viewscores, + backtodemo, + quit +} menuitems; + +// +// WL_INTER +// +typedef struct { + int kill,secret,treasure; + long time; + } LRstruct; + +extern LRstruct LevelRatios[]; + +void Write (int x,int y,char *string); +void NonShareware(void); +int GetYorN(int x,int y,int pic); + + diff --git a/src/lib/hb/c3_play.c b/src/lib/hb/play/c3_play.c similarity index 100% rename from src/lib/hb/c3_play.c rename to src/lib/hb/play/c3_play.c diff --git a/src/lib/hb/c6_play.c b/src/lib/hb/play/c6_play.c similarity index 100% rename from src/lib/hb/c6_play.c rename to src/lib/hb/play/c6_play.c diff --git a/src/lib/hb/kd_play.c b/src/lib/hb/play/kd_play.c similarity index 100% rename from src/lib/hb/kd_play.c rename to src/lib/hb/play/kd_play.c diff --git a/src/lib/hb/play/wl_play.c b/src/lib/hb/play/wl_play.c new file mode 100755 index 00000000..447c8937 --- /dev/null +++ b/src/lib/hb/play/wl_play.c @@ -0,0 +1,1473 @@ +// WL_PLAY.C + +#include "WL_DEF.H" +#pragma hdrstop + + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + +#define sc_Question 0x35 + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + +boolean madenoise; // true when shooting or screaming + +exit_t playstate; + +int DebugOk; + +objtype objlist[MAXACTORS],*new,*obj,*player,*lastobj, + *objfreelist,*killerobj; + +unsigned farmapylookup[MAPSIZE]; +byte *nearmapylookup[MAPSIZE]; + +boolean singlestep,godmode,noclip; +int extravbls; + +byte tilemap[MAPSIZE][MAPSIZE]; // wall values only +byte spotvis[MAPSIZE][MAPSIZE]; +objtype *actorat[MAPSIZE][MAPSIZE]; + +// +// replacing refresh manager +// +unsigned mapwidth,mapheight,tics; +boolean compatability; +byte *updateptr; +unsigned mapwidthtable[64]; +unsigned uwidthtable[UPDATEHIGH]; +unsigned blockstarts[UPDATEWIDE*UPDATEHIGH]; +//uso: replace: byte update[UPDATESIZE]; +//uso: is needed? byte update[UPDATEHIGH][UPDATEWIDE]; + +// +// control info +// +boolean mouseenabled,joystickenabled,joypadenabled,joystickprogressive; +int joystickport; +int dirscan[4] = {sc_UpArrow,sc_RightArrow,sc_DownArrow,sc_LeftArrow}; +int buttonscan[NUMBUTTONS] = + {sc_Control,sc_Alt,sc_RShift,sc_Space,sc_1,sc_2,sc_3,sc_4}; +int buttonmouse[4]={bt_attack,bt_strafe,bt_use,bt_nobutton}; +int buttonjoy[4]={bt_attack,bt_strafe,bt_use,bt_run}; + +int viewsize; + +boolean buttonheld[NUMBUTTONS]; + +boolean demorecord,demoplayback; +char far *demoptr, far *lastdemoptr; +memptr demobuffer; + +// +// curent user input +// +int controlx,controly; // range from -100 to 100 per tic +boolean buttonstate[NUMBUTTONS]; + + + +//=========================================================================== + + +void CenterWindow(word w,word h); +void InitObjList (void); +void RemoveObj (objtype *gone); +void PollControls (void); +void StopMusic(void); +void StartMusic(void); +void PlayLoop (void); + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +objtype dummyobj; + +// +// LIST OF SONGS FOR EACH VERSION +// +int songs[]= +{ +#ifndef SPEAR + // + // Episode One + // + GETTHEM_MUS, + SEARCHN_MUS, + POW_MUS, + SUSPENSE_MUS, + GETTHEM_MUS, + SEARCHN_MUS, + POW_MUS, + SUSPENSE_MUS, + + WARMARCH_MUS, // Boss level + CORNER_MUS, // Secret level + + // + // Episode Two + // + NAZI_OMI_MUS, + PREGNANT_MUS, + GOINGAFT_MUS, + HEADACHE_MUS, + NAZI_OMI_MUS, + PREGNANT_MUS, + HEADACHE_MUS, + GOINGAFT_MUS, + + WARMARCH_MUS, // Boss level + DUNGEON_MUS, // Secret level + + // + // Episode Three + // + INTROCW3_MUS, + NAZI_RAP_MUS, + TWELFTH_MUS, + ZEROHOUR_MUS, + INTROCW3_MUS, + NAZI_RAP_MUS, + TWELFTH_MUS, + ZEROHOUR_MUS, + + ULTIMATE_MUS, // Boss level + PACMAN_MUS, // Secret level + + // + // Episode Four + // + GETTHEM_MUS, + SEARCHN_MUS, + POW_MUS, + SUSPENSE_MUS, + GETTHEM_MUS, + SEARCHN_MUS, + POW_MUS, + SUSPENSE_MUS, + + WARMARCH_MUS, // Boss level + CORNER_MUS, // Secret level + + // + // Episode Five + // + NAZI_OMI_MUS, + PREGNANT_MUS, + GOINGAFT_MUS, + HEADACHE_MUS, + NAZI_OMI_MUS, + PREGNANT_MUS, + HEADACHE_MUS, + GOINGAFT_MUS, + + WARMARCH_MUS, // Boss level + DUNGEON_MUS, // Secret level + + // + // Episode Six + // + INTROCW3_MUS, + NAZI_RAP_MUS, + TWELFTH_MUS, + ZEROHOUR_MUS, + INTROCW3_MUS, + NAZI_RAP_MUS, + TWELFTH_MUS, + ZEROHOUR_MUS, + + ULTIMATE_MUS, // Boss level + FUNKYOU_MUS // Secret level +#else + + ////////////////////////////////////////////////////////////// + // + // SPEAR OF DESTINY TRACKS + // + ////////////////////////////////////////////////////////////// + XTIPTOE_MUS, + XFUNKIE_MUS, + XDEATH_MUS, + XGETYOU_MUS, // DON'T KNOW + ULTIMATE_MUS, // Trans Gr”sse + + DUNGEON_MUS, + GOINGAFT_MUS, + POW_MUS, + TWELFTH_MUS, + ULTIMATE_MUS, // Barnacle Wilhelm BOSS + + NAZI_OMI_MUS, + GETTHEM_MUS, + SUSPENSE_MUS, + SEARCHN_MUS, + ZEROHOUR_MUS, + ULTIMATE_MUS, // Super Mutant BOSS + + XPUTIT_MUS, + ULTIMATE_MUS, // Death Knight BOSS + + XJAZNAZI_MUS, // Secret level + XFUNKIE_MUS, // Secret level (DON'T KNOW) + + XEVIL_MUS // Angel of Death BOSS + +#endif +}; + + +/* +============================================================================= + + USER CONTROL + +============================================================================= +*/ + + +#define BASEMOVE 35 +#define RUNMOVE 70 +#define BASETURN 35 +#define RUNTURN 70 + +#define JOYSCALE 2 + +/* +=================== += += PollKeyboardButtons += +=================== +*/ + +void PollKeyboardButtons (void) +{ + int i; + + for (i=0;i 64) + controlx += (joyx-64)*JOYSCALE*tics; + else if (joyx < -64) + controlx -= (-joyx-64)*JOYSCALE*tics; + if (joyy > 64) + controlx += (joyy-64)*JOYSCALE*tics; + else if (joyy < -64) + controly -= (-joyy-64)*JOYSCALE*tics; + } + else if (buttonstate[bt_run]) + { + if (joyx > 64) + controlx += RUNMOVE*tics; + else if (joyx < -64) + controlx -= RUNMOVE*tics; + if (joyy > 64) + controly += RUNMOVE*tics; + else if (joyy < -64) + controly -= RUNMOVE*tics; + } + else + { + if (joyx > 64) + controlx += BASEMOVE*tics; + else if (joyx < -64) + controlx -= BASEMOVE*tics; + if (joyy > 64) + controly += BASEMOVE*tics; + else if (joyy < -64) + controly -= BASEMOVE*tics; + } +} + + +/* +=================== += += PollControls += += Gets user or demo input, call once each frame += += controlx set between -100 and 100 per tic += controly += buttonheld[] the state of the buttons LAST frame += buttonstate[] the state of the buttons THIS frame += +=================== +*/ + +void PollControls (void) +{ + int max,min,i; + byte buttonbits; + +// +// get timing info for last frame +// + if (demoplayback) + { + while (TimeCount>= 1; + } + + controlx = *demoptr++; + controly = *demoptr++; + + if (demoptr == lastdemoptr) + playstate = ex_completed; // demo is done + + controlx *= (int)tics; + controly *= (int)tics; + + return; + } + + +// +// get button states +// + PollKeyboardButtons (); + + if (mouseenabled) + PollMouseButtons (); + + if (joystickenabled) + PollJoystickButtons (); + +// +// get movements +// + PollKeyboardMove (); + + if (mouseenabled) + PollMouseMove (); + + if (joystickenabled) + PollJoystickMove (); + +// +// bound movement to a maximum +// + max = 100*tics; + min = -max; + if (controlx > max) + controlx = max; + else if (controlx < min) + controlx = min; + + if (controly > max) + controly = max; + else if (controly < min) + controly = min; + + if (demorecord) + { + // + // save info out to demo buffer + // + controlx /= (int)tics; + controly /= (int)tics; + + buttonbits = 0; + + for (i=NUMBUTTONS-1;i>=0;i--) + { + buttonbits <<= 1; + if (buttonstate[i]) + buttonbits |= 1; + } + + *demoptr++ = buttonbits; + *demoptr++ = controlx; + *demoptr++ = controly; + + if (demoptr >= lastdemoptr) + Quit ("Demo buffer overflowed!"); + + controlx *= (int)tics; + controly *= (int)tics; + } +} + + + +//========================================================================== + + + +/////////////////////////////////////////////////////////////////////////// +// +// CenterWindow() - Generates a window of a given width & height in the +// middle of the screen +// +/////////////////////////////////////////////////////////////////////////// + +#define MAXX 320 +#define MAXY 160 + +void CenterWindow(word w,word h) +{ + FixOfs (); + US_DrawWindow(((MAXX / 8) - w) / 2,((MAXY / 8) - h) / 2,w,h); +} + +//=========================================================================== + + +/* +===================== += += CheckKeys += +===================== +*/ + +void CheckKeys (void) +{ + int i; + byte scan; + unsigned temp; + + + if (screenfaded || demoplayback) // don't do anything with a faded screen + return; + + scan = LastScan; + + + #ifdef SPEAR + // + // SECRET CHEAT CODE: TAB-G-F10 + // + if (Keyboard[sc_Tab] && + Keyboard[sc_G] && + Keyboard[sc_F10]) + { + WindowH = 160; + if (godmode) + { + Message ("God mode OFF"); + SD_PlaySound (NOBONUSSND); + } + else + { + Message ("God mode ON"); + SD_PlaySound (ENDBONUS2SND); + } + + IN_Ack(); + godmode ^= 1; + DrawAllPlayBorderSides (); + IN_ClearKeysDown(); + return; + } + #endif + + + // + // SECRET CHEAT CODE: 'MLI' + // + if (Keyboard[sc_M] && + Keyboard[sc_L] && + Keyboard[sc_I]) + { + gamestate.health = 100; + gamestate.ammo = 99; + gamestate.keys = 3; + gamestate.score = 0; + gamestate.TimeCount += 42000L; + GiveWeapon (wp_chaingun); + + DrawWeapon(); + DrawHealth(); + DrawKeys(); + DrawAmmo(); + DrawScore(); + + ClearMemory (); + CA_CacheGrChunk (STARTFONT+1); + ClearSplitVWB (); + VW_ScreenToScreen (displayofs,bufferofs,80,160); + + Message(STR_CHEATER1"\n" + STR_CHEATER2"\n\n" + STR_CHEATER3"\n" + STR_CHEATER4"\n" + STR_CHEATER5); + + UNCACHEGRCHUNK(STARTFONT+1); + PM_CheckMainMem (); + IN_ClearKeysDown(); + IN_Ack(); + + DrawAllPlayBorder (); + } + + // + // OPEN UP DEBUG KEYS + // +#ifndef SPEAR + if (Keyboard[sc_BackSpace] && + Keyboard[sc_LShift] && + Keyboard[sc_Alt] && + MS_CheckParm("goobers")) +#else + if (Keyboard[sc_BackSpace] && + Keyboard[sc_LShift] && + Keyboard[sc_Alt] && + MS_CheckParm("debugmode")) +#endif + { + ClearMemory (); + CA_CacheGrChunk (STARTFONT+1); + ClearSplitVWB (); + VW_ScreenToScreen (displayofs,bufferofs,80,160); + + Message("Debugging keys are\nnow available!"); + UNCACHEGRCHUNK(STARTFONT+1); + PM_CheckMainMem (); + IN_ClearKeysDown(); + IN_Ack(); + + DrawAllPlayBorderSides (); + DebugOk=1; + } + + // + // TRYING THE KEEN CHEAT CODE! + // + if (Keyboard[sc_B] && + Keyboard[sc_A] && + Keyboard[sc_T]) + { + ClearMemory (); + CA_CacheGrChunk (STARTFONT+1); + ClearSplitVWB (); + VW_ScreenToScreen (displayofs,bufferofs,80,160); + + Message("Commander Keen is also\n" + "available from Apogee, but\n" + "then, you already know\n" + "that - right, Cheatmeister?!"); + + UNCACHEGRCHUNK(STARTFONT+1); + PM_CheckMainMem (); + IN_ClearKeysDown(); + IN_Ack(); + + DrawAllPlayBorder (); + } + +// +// pause key weirdness can't be checked as a scan code +// + if (Paused) + { + bufferofs = displayofs; + LatchDrawPic (20-4,80-2*8,PAUSEDPIC); + SD_MusicOff(); + IN_Ack(); + IN_ClearKeysDown (); + SD_MusicOn(); + Paused = false; + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + return; + } + + +// +// F1-F7/ESC to enter control panel +// + if ( +#ifndef DEBCHECK + scan == sc_F10 || +#endif + scan == sc_F9 || + scan == sc_F7 || + scan == sc_F8) // pop up quit dialog + { + ClearMemory (); + ClearSplitVWB (); + VW_ScreenToScreen (displayofs,bufferofs,80,160); + US_ControlPanel(scan); + + DrawAllPlayBorderSides (); + + if (scan == sc_F9) + StartMusic (); + + PM_CheckMainMem (); + SETFONTCOLOR(0,15); + IN_ClearKeysDown(); + return; + } + + if ( (scan >= sc_F1 && scan <= sc_F9) || scan == sc_Escape) + { + StopMusic (); + ClearMemory (); + VW_FadeOut (); + + US_ControlPanel(scan); + + SETFONTCOLOR(0,15); + IN_ClearKeysDown(); + DrawPlayScreen (); + if (!startgame && !loadedgame) + { + VW_FadeIn (); + StartMusic (); + } + if (loadedgame) + playstate = ex_abort; + lasttimecount = TimeCount; + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + PM_CheckMainMem (); + return; + } + +// +// TAB-? debug keys +// + if (Keyboard[sc_Tab] && DebugOk) + { + CA_CacheGrChunk (STARTFONT); + fontnumber=0; + SETFONTCOLOR(0,15); + DebugKeys(); + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + lasttimecount = TimeCount; + return; + } + +} + + +//=========================================================================== + +/* +############################################################################# + + The objlist data structure + +############################################################################# + +objlist containt structures for every actor currently playing. The structure +is accessed as a linked list starting at *player, ending when ob->next == +NULL. GetNewObj inserts a new object at the end of the list, meaning that +if an actor spawn another actor, the new one WILL get to think and react the +same frame. RemoveObj unlinks the given object and returns it to the free +list, but does not damage the objects ->next pointer, so if the current object +removes itself, a linked list following loop can still safely get to the +next element. + + + +############################################################################# +*/ + + +/* +========================= += += InitActorList += += Call to clear out the actor object lists returning them all to the free += list. Allocates a special spot for the player. += +========================= +*/ + +int objcount; + +void InitActorList (void) +{ + int i; + +// +// init the actor lists +// + for (i=0;iprev; + memset (new,0,sizeof(*new)); + + if (lastobj) + lastobj->next = new; + new->prev = lastobj; // new->next is allready NULL from memset + + new->active = false; + lastobj = new; + + objcount++; +} + +//=========================================================================== + +/* +========================= += += RemoveObj += += Add the given object back into the free list, and unlink it from it's += neighbors += +========================= +*/ + +void RemoveObj (objtype *gone) +{ + objtype **spotat; + + if (gone == player) + Quit ("RemoveObj: Tried to remove the player!"); + + gone->state = NULL; + +// +// fix the next object's back link +// + if (gone == lastobj) + lastobj = (objtype *)gone->prev; + else + gone->next->prev = gone->prev; + +// +// fix the previous object's forward link +// + gone->prev->next = gone->next; + +// +// add it back in to the free list +// + gone->prev = objfreelist; + objfreelist = gone; + + objcount--; +} + +/* +============================================================================= + + MUSIC STUFF + +============================================================================= +*/ + + +/* +================= += += StopMusic += +================= +*/ + +void StopMusic(void) +{ + int i; + + SD_MusicOff(); + for (i = 0;i < LASTMUSIC;i++) + if (audiosegs[STARTMUSIC + i]) + { + MM_SetPurge(&((memptr)audiosegs[STARTMUSIC + i]),3); + MM_SetLock(&((memptr)audiosegs[STARTMUSIC + i]),false); + } +} + +//========================================================================== + + +/* +================= += += StartMusic += +================= +*/ + +void StartMusic(void) +{ + musicnames chunk; + + SD_MusicOff(); + chunk = songs[gamestate.mapon+gamestate.episode*10]; + +// if ((chunk == -1) || (MusicMode != smm_AdLib)) +//DEBUG control panel return; + + MM_BombOnError (false); + CA_CacheAudioChunk(STARTMUSIC + chunk); + MM_BombOnError (true); + if (mmerror) + mmerror = false; + else + { + MM_SetLock(&((memptr)audiosegs[STARTMUSIC + chunk]),true); + SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC + chunk]); + } +} + + +/* +============================================================================= + + PALETTE SHIFTING STUFF + +============================================================================= +*/ + +#define NUMREDSHIFTS 6 +#define REDSTEPS 8 + +#define NUMWHITESHIFTS 3 +#define WHITESTEPS 20 +#define WHITETICS 6 + + +byte far redshifts[NUMREDSHIFTS][768]; +byte far whiteshifts[NUMREDSHIFTS][768]; + +int damagecount,bonuscount; +boolean palshifted; + +extern byte far gamepal; + +/* +===================== += += InitRedShifts += +===================== +*/ + +void InitRedShifts (void) +{ + byte far *workptr, far *baseptr; + int i,j,delta; + + +// +// fade through intermediate frames +// + for (i=1;i<=NUMREDSHIFTS;i++) + { + workptr = (byte far *)&redshifts[i-1][0]; + baseptr = &gamepal; + + for (j=0;j<=255;j++) + { + delta = 64-*baseptr; + *workptr++ = *baseptr++ + delta * i / REDSTEPS; + delta = -*baseptr; + *workptr++ = *baseptr++ + delta * i / REDSTEPS; + delta = -*baseptr; + *workptr++ = *baseptr++ + delta * i / REDSTEPS; + } + } + + for (i=1;i<=NUMWHITESHIFTS;i++) + { + workptr = (byte far *)&whiteshifts[i-1][0]; + baseptr = &gamepal; + + for (j=0;j<=255;j++) + { + delta = 64-*baseptr; + *workptr++ = *baseptr++ + delta * i / WHITESTEPS; + delta = 62-*baseptr; + *workptr++ = *baseptr++ + delta * i / WHITESTEPS; + delta = 0-*baseptr; + *workptr++ = *baseptr++ + delta * i / WHITESTEPS; + } + } +} + + +/* +===================== += += ClearPaletteShifts += +===================== +*/ + +void ClearPaletteShifts (void) +{ + bonuscount = damagecount = 0; +} + + +/* +===================== += += StartBonusFlash += +===================== +*/ + +void StartBonusFlash (void) +{ + bonuscount = NUMWHITESHIFTS*WHITETICS; // white shift palette +} + + +/* +===================== += += StartDamageFlash += +===================== +*/ + +void StartDamageFlash (int damage) +{ + damagecount += damage; +} + + +/* +===================== += += UpdatePaletteShifts += +===================== +*/ + +void UpdatePaletteShifts (void) +{ + int red,white; + + if (bonuscount) + { + white = bonuscount/WHITETICS +1; + if (white>NUMWHITESHIFTS) + white = NUMWHITESHIFTS; + bonuscount -= tics; + if (bonuscount < 0) + bonuscount = 0; + } + else + white = 0; + + + if (damagecount) + { + red = damagecount/10 +1; + if (red>NUMREDSHIFTS) + red = NUMREDSHIFTS; + + damagecount -= tics; + if (damagecount < 0) + damagecount = 0; + } + else + red = 0; + + if (red) + { + VW_WaitVBL(1); + VL_SetPalette (redshifts[red-1]); + palshifted = true; + } + else if (white) + { + VW_WaitVBL(1); + VL_SetPalette (whiteshifts[white-1]); + palshifted = true; + } + else if (palshifted) + { + VW_WaitVBL(1); + VL_SetPalette (&gamepal); // back to normal + palshifted = false; + } +} + + +/* +===================== += += FinishPaletteShifts += += Resets palette to normal if needed += +===================== +*/ + +void FinishPaletteShifts (void) +{ + if (palshifted) + { + palshifted = 0; + VW_WaitVBL(1); + VL_SetPalette (&gamepal); + } +} + + +/* +============================================================================= + + CORE PLAYLOOP + +============================================================================= +*/ + + +/* +===================== += += DoActor += +===================== +*/ + +void DoActor (objtype *ob) +{ + void (*think)(objtype *); + + if (!ob->active && !areabyplayer[ob->areanumber]) + return; + + if (!(ob->flags&(FL_NONMARK|FL_NEVERMARK)) ) + actorat[ob->tilex][ob->tiley] = NULL; + +// +// non transitional object +// + + if (!ob->ticcount) + { + think = ob->state->think; + if (think) + { + think (ob); + if (!ob->state) + { + RemoveObj (ob); + return; + } + } + + if (ob->flags&FL_NEVERMARK) + return; + + if ( (ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley]) + return; + + actorat[ob->tilex][ob->tiley] = ob; + return; + } + +// +// transitional object +// + ob->ticcount-=tics; + while ( ob->ticcount <= 0) + { + think = ob->state->action; // end of state action + if (think) + { + think (ob); + if (!ob->state) + { + RemoveObj (ob); + return; + } + } + + ob->state = ob->state->next; + + if (!ob->state) + { + RemoveObj (ob); + return; + } + + if (!ob->state->tictime) + { + ob->ticcount = 0; + goto think; + } + + ob->ticcount += ob->state->tictime; + } + +think: + // + // think + // + think = ob->state->think; + if (think) + { + think (ob); + if (!ob->state) + { + RemoveObj (ob); + return; + } + } + + if (ob->flags&FL_NEVERMARK) + return; + + if ( (ob->flags&FL_NONMARK) && actorat[ob->tilex][ob->tiley]) + return; + + actorat[ob->tilex][ob->tiley] = ob; +} + +//========================================================================== + + +/* +=================== += += PlayLoop += +=================== +*/ +long funnyticount; + + +void PlayLoop (void) +{ + int give; + int helmetangle; + + playstate = TimeCount = lasttimecount = 0; + frameon = 0; + running = false; + anglefrac = 0; + facecount = 0; + funnyticount = 0; + memset (buttonstate,0,sizeof(buttonstate)); + ClearPaletteShifts (); + + if (MousePresent) + Mouse(MDelta); // Clear accumulated mouse movement + + if (demoplayback) + IN_StartAck (); + + do + { + if (virtualreality) + { + helmetangle = peek (0x40,0xf0); + player->angle += helmetangle; + if (player->angle >= ANGLES) + player->angle -= ANGLES; + } + + + PollControls(); + +// +// actor thinking +// + madenoise = false; + + MoveDoors (); + MovePWalls (); + + for (obj = player;obj;obj = obj->next) + DoActor (obj); + + UpdatePaletteShifts (); + + ThreeDRefresh (); + + // + // MAKE FUNNY FACE IF BJ DOESN'T MOVE FOR AWHILE + // + #ifdef SPEAR + funnyticount += tics; + if (funnyticount > 30l*70) + { + funnyticount = 0; + StatusDrawPic (17,4,BJWAITING1PIC+(US_RndT()&1)); + facecount = 0; + } + #endif + + gamestate.TimeCount+=tics; + + SD_Poll (); + UpdateSoundLoc(); // JAB + + if (screenfaded) + VW_FadeIn (); + + CheckKeys(); + +// +// debug aids +// + if (singlestep) + { + VW_WaitVBL(14); + lasttimecount = TimeCount; + } + if (extravbls) + VW_WaitVBL(extravbls); + + if (demoplayback) + { + if (IN_CheckAck ()) + { + IN_ClearKeysDown (); + playstate = ex_abort; + } + } + + + if (virtualreality) + { + player->angle -= helmetangle; + if (player->angle < 0) + player->angle += ANGLES; + } + + }while (!playstate && !startgame); + + if (playstate != ex_died) + FinishPaletteShifts (); +} + diff --git a/src/lib/hb/c3_scale.c b/src/lib/hb/scale/c3_scale.c similarity index 100% rename from src/lib/hb/c3_scale.c rename to src/lib/hb/scale/c3_scale.c diff --git a/src/lib/hb/c6_scale.c b/src/lib/hb/scale/c6_scale.c similarity index 100% rename from src/lib/hb/c6_scale.c rename to src/lib/hb/scale/c6_scale.c diff --git a/src/lib/hb/scale/wl_scale.c b/src/lib/hb/scale/wl_scale.c new file mode 100755 index 00000000..9c1e102f --- /dev/null +++ b/src/lib/hb/scale/wl_scale.c @@ -0,0 +1,741 @@ +// WL_SCALE.C + +#include "WL_DEF.H" +#pragma hdrstop + +#define OP_RETF 0xcb + +/* +============================================================================= + + GLOBALS + +============================================================================= +*/ + +t_compscale _seg *scaledirectory[MAXSCALEHEIGHT+1]; +long fullscalefarcall[MAXSCALEHEIGHT+1]; + +int maxscale,maxscaleshl2; + +boolean insetupscaling; + +/* +============================================================================= + + LOCALS + +============================================================================= +*/ + +t_compscale _seg *work; +unsigned BuildCompScale (int height, memptr *finalspot); + +int stepbytwo; + +//=========================================================================== + +/* +============== += += BadScale += +============== +*/ + +void far BadScale (void) +{ + Quit ("BadScale called!"); +} + + +/* +========================== += += SetupScaling += +========================== +*/ + +void SetupScaling (int maxscaleheight) +{ + int i,x,y; + byte far *dest; + + insetupscaling = true; + + maxscaleheight/=2; // one scaler every two pixels + + maxscale = maxscaleheight-1; + maxscaleshl2 = maxscale<<2; + +// +// free up old scalers +// + for (i=1;i=stepbytwo) + i += 2; + } + memset (scaledirectory,0,sizeof(scaledirectory)); + + MM_SortMem (); + +// +// build the compiled scalers +// + stepbytwo = viewheight/2; // save space by double stepping + MM_GetPtr (&(memptr)work,20000); + + for (i=1;i<=maxscaleheight;i++) + { + BuildCompScale (i*2,&(memptr)scaledirectory[i]); + if (i>=stepbytwo) + i+= 2; + } + MM_FreePtr (&(memptr)work); + +// +// compact memory and lock down scalers +// + MM_SortMem (); + for (i=1;i<=maxscaleheight;i++) + { + MM_SetLock (&(memptr)scaledirectory[i],true); + fullscalefarcall[i] = (unsigned)scaledirectory[i]; + fullscalefarcall[i] <<=16; + fullscalefarcall[i] += scaledirectory[i]->codeofs[0]; + if (i>=stepbytwo) + { + scaledirectory[i+1] = scaledirectory[i]; + fullscalefarcall[i+1] = fullscalefarcall[i]; + scaledirectory[i+2] = scaledirectory[i]; + fullscalefarcall[i+2] = fullscalefarcall[i]; + i+=2; + } + } + scaledirectory[0] = scaledirectory[1]; + fullscalefarcall[0] = fullscalefarcall[1]; + +// +// check for oversize wall drawing +// + for (i=maxscaleheight;icode[0]; + toppix = (viewheight-height)/2; + fix = 0; + + for (src=0;src<=64;src++) + { + startpix = fix>>16; + fix += step; + endpix = fix>>16; + + if (endpix>startpix) + work->width[src] = endpix-startpix; + else + work->width[src] = 0; + +// +// mark the start of the code +// + work->codeofs[src] = FP_OFF(code); + +// +// compile some code if the source pixel generates any screen pixels +// + startpix+=toppix; + endpix+=toppix; + + if (startpix == endpix || endpix < 0 || startpix >= viewheight || src == 64) + continue; + + // + // mov al,[si+src] + // + *code++ = 0x8a; + *code++ = 0x44; + *code++ = src; + + for (;startpix= viewheight) + break; // off the bottom of the view area + if (startpix < 0) + continue; // not into the view area + + // + // mov [es:di+heightofs],al + // + *code++ = 0x26; + *code++ = 0x88; + *code++ = 0x85; + *((unsigned far *)code)++ = startpix*SCREENBWIDE; + } + + } + +// +// retf +// + *code++ = 0xcb; + + totalsize = FP_OFF(code); + MM_GetPtr (finalspot,totalsize); + _fmemcpy ((byte _seg *)(*finalspot),(byte _seg *)work,totalsize); + + return totalsize; +} + + +/* +======================= += += ScaleLine += += linescale should have the high word set to the segment of the scaler += +======================= +*/ + +extern int slinex,slinewidth; +extern unsigned far *linecmds; +extern long linescale; +extern unsigned maskword; + +byte mask1,mask2,mask3; + + +void near ScaleLine (void) +{ +asm mov cx,WORD PTR [linescale+2] +asm mov es,cx // segment of scaler + +asm mov bp,WORD PTR [linecmds] +asm mov dx,SC_INDEX+1 // to set SC_MAPMASK + +asm mov bx,[slinex] +asm mov di,bx +asm shr di,1 // X in bytes +asm shr di,1 +asm add di,[bufferofs] +asm and bx,3 +/* begin 8086 hack +asm shl bx,3 +*/ +asm push cx +asm mov cl,3 +asm shl bx,cl +asm pop cx +/* end 8086 hack */ +asm add bx,[slinewidth] // bx = (pixel*8+pixwidth) +asm mov al,BYTE [mapmasks3-1+bx] // -1 because pixwidth of 1 is first +asm mov ds,WORD PTR [linecmds+2] +asm or al,al +asm jz notthreebyte // scale across three bytes +asm jmp threebyte +notthreebyte: +asm mov al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first +asm or al,al +asm jnz twobyte // scale across two bytes + +// +// one byte scaling +// +asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first +asm out dx,al // set map mask register + +scalesingle: + +asm mov bx,[ds:bp] // table location of rtl to patch +asm or bx,bx +asm jz linedone // 0 signals end of segment list +asm mov bx,[es:bx] +asm mov dl,[es:bx] // save old value +asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in +asm mov si,[ds:bp+4] // table location of entry spot +asm mov ax,[es:si] +asm mov WORD PTR ss:[linescale],ax // call here to start scaling +asm mov si,[ds:bp+2] // corrected top of shape for this segment +asm add bp,6 // next segment list + +asm mov ax,SCREENSEG +asm mov es,ax +asm call ss:[linescale] // scale the segment of pixels + +asm mov es,cx // segment of scaler +asm mov BYTE PTR es:[bx],dl // unpatch the RETF +asm jmp scalesingle // do the next segment + + +// +// done +// +linedone: +asm mov ax,ss +asm mov ds,ax +return; + +// +// two byte scaling +// +twobyte: +asm mov ss:[mask2],al +asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first +asm mov ss:[mask1],al + +scaledouble: + +asm mov bx,[ds:bp] // table location of rtl to patch +asm or bx,bx +asm jz linedone // 0 signals end of segment list +asm mov bx,[es:bx] +asm mov cl,[es:bx] // save old value +asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in +asm mov si,[ds:bp+4] // table location of entry spot +asm mov ax,[es:si] +asm mov WORD PTR ss:[linescale],ax // call here to start scaling +asm mov si,[ds:bp+2] // corrected top of shape for this segment +asm add bp,6 // next segment list + +asm mov ax,SCREENSEG +asm mov es,ax +asm mov al,ss:[mask1] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm inc di +asm mov al,ss:[mask2] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm dec di + +asm mov es,WORD PTR ss:[linescale+2] // segment of scaler +asm mov BYTE PTR es:[bx],cl // unpatch the RETF +asm jmp scaledouble // do the next segment + + +// +// three byte scaling +// +threebyte: +asm mov ss:[mask3],al +asm mov al,BYTE PTR ss:[mapmasks2-1+bx] // -1 because pixwidth of 1 is first +asm mov ss:[mask2],al +asm mov al,BYTE PTR ss:[mapmasks1-1+bx] // -1 because pixwidth of 1 is first +asm mov ss:[mask1],al + +scaletriple: + +asm mov bx,[ds:bp] // table location of rtl to patch +asm or bx,bx +asm jz linedone // 0 signals end of segment list +asm mov bx,[es:bx] +asm mov cl,[es:bx] // save old value +asm mov BYTE PTR es:[bx],OP_RETF // patch a RETF in +asm mov si,[ds:bp+4] // table location of entry spot +asm mov ax,[es:si] +asm mov WORD PTR ss:[linescale],ax // call here to start scaling +asm mov si,[ds:bp+2] // corrected top of shape for this segment +asm add bp,6 // next segment list + +asm mov ax,SCREENSEG +asm mov es,ax +asm mov al,ss:[mask1] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm inc di +asm mov al,ss:[mask2] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm inc di +asm mov al,ss:[mask3] +asm out dx,al // set map mask register +asm call ss:[linescale] // scale the segment of pixels +asm dec di +asm dec di + +asm mov es,WORD PTR ss:[linescale+2] // segment of scaler +asm mov BYTE PTR es:[bx],cl // unpatch the RETF +asm jmp scaletriple // do the next segment + + +} + + +/* +======================= += += ScaleShape += += Draws a compiled shape at [scale] pixels high += += each vertical line of the shape has a pointer to segment data: += end of segment pixel*2 (0 terminates line) used to patch rtl in scaler += top of virtual line with segment in proper place += start of segment pixel*2, used to jsl into compiled scaler += += += Setup for call += -------------- += GC_MODE read mode 1, write mode 2 += GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff += GC_INDEX pointing at GC_BITMASK += +======================= +*/ + +static long longtemp; + +void ScaleShape (int xcenter, int shapenum, unsigned height) +{ + t_compshape _seg *shape; + t_compscale _seg *comptable; + unsigned scale,srcx,stopx,tempx; + int t; + unsigned far *cmdptr; + boolean leftvis,rightvis; + + + shape = PM_GetSpritePage (shapenum); + + scale = height>>3; // low three bits are fractional + if (!scale || scale>maxscale) + return; // too close or far away + comptable = scaledirectory[scale]; + + *(((unsigned *)&linescale)+1)=(unsigned)comptable; // seg of far call + *(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape + +// +// scale to the left (from pixel 31 to shape->leftpix) +// + srcx = 32; + slinex = xcenter; + stopx = shape->leftpix; + cmdptr = &shape->dataofs[31-stopx]; + + while ( --srcx >=stopx && slinex>0) + { + (unsigned)linecmds = *cmdptr--; + if ( !(slinewidth = comptable->width[srcx]) ) + continue; + + if (slinewidth == 1) + { + slinex--; + if (slinex= height) + continue; // obscured by closer wall + ScaleLine (); + } + continue; + } + + // + // handle multi pixel lines + // + if (slinex>viewwidth) + { + slinex -= slinewidth; + slinewidth = viewwidth-slinex; + if (slinewidth<1) + continue; // still off the right side + } + else + { + if (slinewidth>slinex) + slinewidth = slinex; + slinex -= slinewidth; + } + + + leftvis = (wallheight[slinex] < height); + rightvis = (wallheight[slinex+slinewidth-1] < height); + + if (leftvis) + { + if (rightvis) + ScaleLine (); + else + { + while (wallheight[slinex+slinewidth-1] >= height) + slinewidth--; + ScaleLine (); + } + } + else + { + if (!rightvis) + continue; // totally obscured + + while (wallheight[slinex] >= height) + { + slinex++; + slinewidth--; + } + ScaleLine (); + break; // the rest of the shape is gone + } + } + + +// +// scale to the right +// + slinex = xcenter; + stopx = shape->rightpix; + if (shape->leftpix<31) + { + srcx = 31; + cmdptr = &shape->dataofs[32-shape->leftpix]; + } + else + { + srcx = shape->leftpix-1; + cmdptr = &shape->dataofs[0]; + } + slinewidth = 0; + + while ( ++srcx <= stopx && (slinex+=slinewidth)width[srcx]) ) + continue; + + if (slinewidth == 1) + { + if (slinex>=0 && wallheight[slinex] < height) + { + ScaleLine (); + } + continue; + } + + // + // handle multi pixel lines + // + if (slinex<0) + { + if (slinewidth <= -slinex) + continue; // still off the left edge + + slinewidth += slinex; + slinex = 0; + } + else + { + if (slinex + slinewidth > viewwidth) + slinewidth = viewwidth-slinex; + } + + + leftvis = (wallheight[slinex] < height); + rightvis = (wallheight[slinex+slinewidth-1] < height); + + if (leftvis) + { + if (rightvis) + { + ScaleLine (); + } + else + { + while (wallheight[slinex+slinewidth-1] >= height) + slinewidth--; + ScaleLine (); + break; // the rest of the shape is gone + } + } + else + { + if (rightvis) + { + while (wallheight[slinex] >= height) + { + slinex++; + slinewidth--; + } + ScaleLine (); + } + else + continue; // totally obscured + } + } +} + + + +/* +======================= += += SimpleScaleShape += += NO CLIPPING, height in pixels += += Draws a compiled shape at [scale] pixels high += += each vertical line of the shape has a pointer to segment data: += end of segment pixel*2 (0 terminates line) used to patch rtl in scaler += top of virtual line with segment in proper place += start of segment pixel*2, used to jsl into compiled scaler += += += Setup for call += -------------- += GC_MODE read mode 1, write mode 2 += GC_COLORDONTCARE set to 0, so all reads from video memory return 0xff += GC_INDEX pointing at GC_BITMASK += +======================= +*/ + +void SimpleScaleShape (int xcenter, int shapenum, unsigned height) +{ + t_compshape _seg *shape; + t_compscale _seg *comptable; + unsigned scale,srcx,stopx,tempx; + int t; + unsigned far *cmdptr; + boolean leftvis,rightvis; + + + shape = PM_GetSpritePage (shapenum); + + scale = height>>1; + comptable = scaledirectory[scale]; + + *(((unsigned *)&linescale)+1)=(unsigned)comptable; // seg of far call + *(((unsigned *)&linecmds)+1)=(unsigned)shape; // seg of shape + +// +// scale to the left (from pixel 31 to shape->leftpix) +// + srcx = 32; + slinex = xcenter; + stopx = shape->leftpix; + cmdptr = &shape->dataofs[31-stopx]; + + while ( --srcx >=stopx ) + { + (unsigned)linecmds = *cmdptr--; + if ( !(slinewidth = comptable->width[srcx]) ) + continue; + + slinex -= slinewidth; + ScaleLine (); + } + + +// +// scale to the right +// + slinex = xcenter; + stopx = shape->rightpix; + if (shape->leftpix<31) + { + srcx = 31; + cmdptr = &shape->dataofs[32-shape->leftpix]; + } + else + { + srcx = shape->leftpix-1; + cmdptr = &shape->dataofs[0]; + } + slinewidth = 0; + + while ( ++srcx <= stopx ) + { + (unsigned)linecmds = *cmdptr++; + if ( !(slinewidth = comptable->width[srcx]) ) + continue; + + ScaleLine (); + slinex+=slinewidth; + } +} + + + + +// +// bit mask tables for drawing scaled strips up to eight pixels wide +// +// down here so the STUPID inline assembler doesn't get confused! +// + + +byte mapmasks1[4][8] = { +{1 ,3 ,7 ,15,15,15,15,15}, +{2 ,6 ,14,14,14,14,14,14}, +{4 ,12,12,12,12,12,12,12}, +{8 ,8 ,8 ,8 ,8 ,8 ,8 ,8} }; + +byte mapmasks2[4][8] = { +{0 ,0 ,0 ,0 ,1 ,3 ,7 ,15}, +{0 ,0 ,0 ,1 ,3 ,7 ,15,15}, +{0 ,0 ,1 ,3 ,7 ,15,15,15}, +{0 ,1 ,3 ,7 ,15,15,15,15} }; + +byte mapmasks3[4][8] = { +{0 ,0 ,0 ,0 ,0 ,0 ,0 ,0}, +{0 ,0 ,0 ,0 ,0 ,0 ,0 ,1}, +{0 ,0 ,0 ,0 ,0 ,0 ,1 ,3}, +{0 ,0 ,0 ,0 ,0 ,1 ,3 ,7} }; + + +unsigned wordmasks[8][8] = { +{0x0080,0x00c0,0x00e0,0x00f0,0x00f8,0x00fc,0x00fe,0x00ff}, +{0x0040,0x0060,0x0070,0x0078,0x007c,0x007e,0x007f,0x807f}, +{0x0020,0x0030,0x0038,0x003c,0x003e,0x003f,0x803f,0xc03f}, +{0x0010,0x0018,0x001c,0x001e,0x001f,0x801f,0xc01f,0xe01f}, +{0x0008,0x000c,0x000e,0x000f,0x800f,0xc00f,0xe00f,0xf00f}, +{0x0004,0x0006,0x0007,0x8007,0xc007,0xe007,0xf007,0xf807}, +{0x0002,0x0003,0x8003,0xc003,0xe003,0xf003,0xf803,0xfc03}, +{0x0001,0x8001,0xc001,0xe001,0xf001,0xf801,0xfc01,0xfe01} }; + +int slinex,slinewidth; +unsigned far *linecmds; +long linescale; +unsigned maskword; + diff --git a/src/lib/hb/c3_state.c b/src/lib/hb/state/c3_state.c similarity index 100% rename from src/lib/hb/c3_state.c rename to src/lib/hb/state/c3_state.c diff --git a/src/lib/hb/c6_state.c b/src/lib/hb/state/c6_state.c similarity index 100% rename from src/lib/hb/c6_state.c rename to src/lib/hb/state/c6_state.c diff --git a/src/lib/hb/state/wl_state.c b/src/lib/hb/state/wl_state.c new file mode 100755 index 00000000..ad534ba9 --- /dev/null +++ b/src/lib/hb/state/wl_state.c @@ -0,0 +1,1480 @@ +// WL_STATE.C + +#include "WL_DEF.H" +#pragma hdrstop + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + +dirtype opposite[9] = + {west,southwest,south,southeast,east,northeast,north,northwest,nodir}; + +dirtype diagonal[9][9] = +{ +/* east */ {nodir,nodir,northeast,nodir,nodir,nodir,southeast,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, +/* north */ {northeast,nodir,nodir,nodir,northwest,nodir,nodir,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, +/* west */ {nodir,nodir,northwest,nodir,nodir,nodir,southwest,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, +/* south */ {southeast,nodir,nodir,nodir,southwest,nodir,nodir,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir}, + {nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir,nodir} +}; + + + +void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state); +void NewState (objtype *ob, statetype *state); + +boolean TryWalk (objtype *ob); +void MoveObj (objtype *ob, long move); + +void KillActor (objtype *ob); +void DamageActor (objtype *ob, unsigned damage); + +boolean CheckLine (objtype *ob); +void FirstSighting (objtype *ob); +boolean CheckSight (objtype *ob); + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + + +//=========================================================================== + + +/* +=================== += += SpawnNewObj += += Spaws a new actor at the given TILE coordinates, with the given state, and += the given size in GLOBAL units. += += new = a pointer to an initialized new actor += +=================== +*/ + +void SpawnNewObj (unsigned tilex, unsigned tiley, statetype *state) +{ + GetNewActor (); + new->state = state; + if (state->tictime) + new->ticcount = US_RndT () % state->tictime; + else + new->ticcount = 0; + + new->tilex = tilex; + new->tiley = tiley; + new->x = ((long)tilex<y = ((long)tiley<dir = nodir; + + actorat[tilex][tiley] = new; + new->areanumber = + *(mapsegs[0] + farmapylookup[new->tiley]+new->tilex) - AREATILE; +} + + + +/* +=================== += += NewState += += Changes ob to a new state, setting ticcount to the max for that state += +=================== +*/ + +void NewState (objtype *ob, statetype *state) +{ + ob->state = state; + ob->ticcount = state->tictime; +} + + + +/* +============================================================================= + + ENEMY TILE WORLD MOVEMENT CODE + +============================================================================= +*/ + + +/* +================================== += += TryWalk += += Attempts to move ob in its current (ob->dir) direction. += += If blocked by either a wall or an actor returns FALSE += += If move is either clear or blocked only by a door, returns TRUE and sets += += ob->tilex = new destination += ob->tiley += ob->areanumber = the floor tile number (0-(NUMAREAS-1)) of destination += ob->distance = TILEGLOBAl, or -doornumber if a door is blocking the way += += If a door is in the way, an OpenDoor call is made to start it opening. += The actor code should wait until += doorobjlist[-ob->distance].action = dr_open, meaning the door has been += fully opened += +================================== +*/ + +#define CHECKDIAG(x,y) \ +{ \ + temp=(unsigned)actorat[x][y]; \ + if (temp) \ + { \ + if (temp<256) \ + return false; \ + if (((objtype *)temp)->flags&FL_SHOOTABLE) \ + return false; \ + } \ +} + +#define CHECKSIDE(x,y) \ +{ \ + temp=(unsigned)actorat[x][y]; \ + if (temp) \ + { \ + if (temp<128) \ + return false; \ + if (temp<256) \ + doornum = temp&63; \ + else if (((objtype *)temp)->flags&FL_SHOOTABLE)\ + return false; \ + } \ +} + + +boolean TryWalk (objtype *ob) +{ + int doornum; + unsigned temp; + + doornum = -1; + + if (ob->obclass == inertobj) + { + switch (ob->dir) + { + case north: + ob->tiley--; + break; + + case northeast: + ob->tilex++; + ob->tiley--; + break; + + case east: + ob->tilex++; + break; + + case southeast: + ob->tilex++; + ob->tiley++; + break; + + case south: + ob->tiley++; + break; + + case southwest: + ob->tilex--; + ob->tiley++; + break; + + case west: + ob->tilex--; + break; + + case northwest: + ob->tilex--; + ob->tiley--; + break; + } + } + else + switch (ob->dir) + { + case north: + if (ob->obclass == dogobj || ob->obclass == fakeobj) + { + CHECKDIAG(ob->tilex,ob->tiley-1); + } + else + { + CHECKSIDE(ob->tilex,ob->tiley-1); + } + ob->tiley--; + break; + + case northeast: + CHECKDIAG(ob->tilex+1,ob->tiley-1); + CHECKDIAG(ob->tilex+1,ob->tiley); + CHECKDIAG(ob->tilex,ob->tiley-1); + ob->tilex++; + ob->tiley--; + break; + + case east: + if (ob->obclass == dogobj || ob->obclass == fakeobj) + { + CHECKDIAG(ob->tilex+1,ob->tiley); + } + else + { + CHECKSIDE(ob->tilex+1,ob->tiley); + } + ob->tilex++; + break; + + case southeast: + CHECKDIAG(ob->tilex+1,ob->tiley+1); + CHECKDIAG(ob->tilex+1,ob->tiley); + CHECKDIAG(ob->tilex,ob->tiley+1); + ob->tilex++; + ob->tiley++; + break; + + case south: + if (ob->obclass == dogobj || ob->obclass == fakeobj) + { + CHECKDIAG(ob->tilex,ob->tiley+1); + } + else + { + CHECKSIDE(ob->tilex,ob->tiley+1); + } + ob->tiley++; + break; + + case southwest: + CHECKDIAG(ob->tilex-1,ob->tiley+1); + CHECKDIAG(ob->tilex-1,ob->tiley); + CHECKDIAG(ob->tilex,ob->tiley+1); + ob->tilex--; + ob->tiley++; + break; + + case west: + if (ob->obclass == dogobj || ob->obclass == fakeobj) + { + CHECKDIAG(ob->tilex-1,ob->tiley); + } + else + { + CHECKSIDE(ob->tilex-1,ob->tiley); + } + ob->tilex--; + break; + + case northwest: + CHECKDIAG(ob->tilex-1,ob->tiley-1); + CHECKDIAG(ob->tilex-1,ob->tiley); + CHECKDIAG(ob->tilex,ob->tiley-1); + ob->tilex--; + ob->tiley--; + break; + + case nodir: + return false; + + default: + Quit ("Walk: Bad dir"); + } + + if (doornum != -1) + { + OpenDoor (doornum); + ob->distance = -doornum-1; + return true; + } + + + ob->areanumber = + *(mapsegs[0] + farmapylookup[ob->tiley]+ob->tilex) - AREATILE; + + ob->distance = TILEGLOBAL; + return true; +} + + + +/* +================================== += += SelectDodgeDir += += Attempts to choose and initiate a movement for ob that sends it towards += the player while dodging += += If there is no possible move (ob is totally surrounded) += += ob->dir = nodir += += Otherwise += += ob->dir = new direction to follow += ob->distance = TILEGLOBAL or -doornumber += ob->tilex = new destination += ob->tiley += ob->areanumber = the floor tile number (0-(NUMAREAS-1)) of destination += +================================== +*/ + +void SelectDodgeDir (objtype *ob) +{ + int deltax,deltay,i; + unsigned absdx,absdy; + dirtype dirtry[5]; + dirtype turnaround,tdir; + + if (ob->flags & FL_FIRSTATTACK) + { + // + // turning around is only ok the very first time after noticing the + // player + // + turnaround = nodir; + ob->flags &= ~FL_FIRSTATTACK; + } + else + turnaround=opposite[ob->dir]; + + deltax = player->tilex - ob->tilex; + deltay = player->tiley - ob->tiley; + +// +// arange 5 direction choices in order of preference +// the four cardinal directions plus the diagonal straight towards +// the player +// + + if (deltax>0) + { + dirtry[1]= east; + dirtry[3]= west; + } + else + { + dirtry[1]= west; + dirtry[3]= east; + } + + if (deltay>0) + { + dirtry[2]= south; + dirtry[4]= north; + } + else + { + dirtry[2]= north; + dirtry[4]= south; + } + +// +// randomize a bit for dodging +// + absdx = abs(deltax); + absdy = abs(deltay); + + if (absdx > absdy) + { + tdir = dirtry[1]; + dirtry[1] = dirtry[2]; + dirtry[2] = tdir; + tdir = dirtry[3]; + dirtry[3] = dirtry[4]; + dirtry[4] = tdir; + } + + if (US_RndT() < 128) + { + tdir = dirtry[1]; + dirtry[1] = dirtry[2]; + dirtry[2] = tdir; + tdir = dirtry[3]; + dirtry[3] = dirtry[4]; + dirtry[4] = tdir; + } + + dirtry[0] = diagonal [ dirtry[1] ] [ dirtry[2] ]; + +// +// try the directions util one works +// + for (i=0;i<5;i++) + { + if ( dirtry[i] == nodir || dirtry[i] == turnaround) + continue; + + ob->dir = dirtry[i]; + if (TryWalk(ob)) + return; + } + +// +// turn around only as a last resort +// + if (turnaround != nodir) + { + ob->dir = turnaround; + + if (TryWalk(ob)) + return; + } + + ob->dir = nodir; +} + + +/* +============================ += += SelectChaseDir += += As SelectDodgeDir, but doesn't try to dodge += +============================ +*/ + +void SelectChaseDir (objtype *ob) +{ + int deltax,deltay,i; + dirtype d[3]; + dirtype tdir, olddir, turnaround; + + + olddir=ob->dir; + turnaround=opposite[olddir]; + + deltax=player->tilex - ob->tilex; + deltay=player->tiley - ob->tiley; + + d[1]=nodir; + d[2]=nodir; + + if (deltax>0) + d[1]= east; + else if (deltax<0) + d[1]= west; + if (deltay>0) + d[2]=south; + else if (deltay<0) + d[2]=north; + + if (abs(deltay)>abs(deltax)) + { + tdir=d[1]; + d[1]=d[2]; + d[2]=tdir; + } + + if (d[1]==turnaround) + d[1]=nodir; + if (d[2]==turnaround) + d[2]=nodir; + + + if (d[1]!=nodir) + { + ob->dir=d[1]; + if (TryWalk(ob)) + return; /*either moved forward or attacked*/ + } + + if (d[2]!=nodir) + { + ob->dir=d[2]; + if (TryWalk(ob)) + return; + } + +/* there is no direct path to the player, so pick another direction */ + + if (olddir!=nodir) + { + ob->dir=olddir; + if (TryWalk(ob)) + return; + } + + if (US_RndT()>128) /*randomly determine direction of search*/ + { + for (tdir=north;tdir<=west;tdir++) + { + if (tdir!=turnaround) + { + ob->dir=tdir; + if ( TryWalk(ob) ) + return; + } + } + } + else + { + for (tdir=west;tdir>=north;tdir--) + { + if (tdir!=turnaround) + { + ob->dir=tdir; + if ( TryWalk(ob) ) + return; + } + } + } + + if (turnaround != nodir) + { + ob->dir=turnaround; + if (ob->dir != nodir) + { + if ( TryWalk(ob) ) + return; + } + } + + ob->dir = nodir; // can't move +} + + +/* +============================ += += SelectRunDir += += Run Away from player += +============================ +*/ + +void SelectRunDir (objtype *ob) +{ + int deltax,deltay,i; + dirtype d[3]; + dirtype tdir, olddir, turnaround; + + + deltax=player->tilex - ob->tilex; + deltay=player->tiley - ob->tiley; + + if (deltax<0) + d[1]= east; + else + d[1]= west; + if (deltay<0) + d[2]=south; + else + d[2]=north; + + if (abs(deltay)>abs(deltax)) + { + tdir=d[1]; + d[1]=d[2]; + d[2]=tdir; + } + + ob->dir=d[1]; + if (TryWalk(ob)) + return; /*either moved forward or attacked*/ + + ob->dir=d[2]; + if (TryWalk(ob)) + return; + +/* there is no direct path to the player, so pick another direction */ + + if (US_RndT()>128) /*randomly determine direction of search*/ + { + for (tdir=north;tdir<=west;tdir++) + { + ob->dir=tdir; + if ( TryWalk(ob) ) + return; + } + } + else + { + for (tdir=west;tdir>=north;tdir--) + { + ob->dir=tdir; + if ( TryWalk(ob) ) + return; + } + } + + ob->dir = nodir; // can't move +} + + +/* +================= += += MoveObj += += Moves ob be move global units in ob->dir direction += Actors are not allowed to move inside the player += Does NOT check to see if the move is tile map valid += += ob->x = adjusted for new position += ob->y += +================= +*/ + +void MoveObj (objtype *ob, long move) +{ + long deltax,deltay; + + switch (ob->dir) + { + case north: + ob->y -= move; + break; + case northeast: + ob->x += move; + ob->y -= move; + break; + case east: + ob->x += move; + break; + case southeast: + ob->x += move; + ob->y += move; + break; + case south: + ob->y += move; + break; + case southwest: + ob->x -= move; + ob->y += move; + break; + case west: + ob->x -= move; + break; + case northwest: + ob->x -= move; + ob->y -= move; + break; + + case nodir: + return; + + default: + Quit ("MoveObj: bad dir!"); + } + +// +// check to make sure it's not on top of player +// + if (areabyplayer[ob->areanumber]) + { + deltax = ob->x - player->x; + if (deltax < -MINACTORDIST || deltax > MINACTORDIST) + goto moveok; + deltay = ob->y - player->y; + if (deltay < -MINACTORDIST || deltay > MINACTORDIST) + goto moveok; + + if (ob->obclass == ghostobj || ob->obclass == spectreobj) + TakeDamage (tics*2,ob); + + // + // back up + // + switch (ob->dir) + { + case north: + ob->y += move; + break; + case northeast: + ob->x -= move; + ob->y += move; + break; + case east: + ob->x -= move; + break; + case southeast: + ob->x -= move; + ob->y -= move; + break; + case south: + ob->y -= move; + break; + case southwest: + ob->x += move; + ob->y -= move; + break; + case west: + ob->x += move; + break; + case northwest: + ob->x += move; + ob->y += move; + break; + + case nodir: + return; + } + return; + } +moveok: + ob->distance -=move; +} + +/* +============================================================================= + + STUFF + +============================================================================= +*/ + +/* +=============== += += DropItem += += Tries to drop a bonus item somewhere in the tiles surrounding the += given tilex/tiley += +=============== +*/ + +void DropItem (stat_t itemtype, int tilex, int tiley) +{ + int x,y,xl,xh,yl,yh; + +// +// find a free spot to put it in +// + if (!actorat[tilex][tiley]) + { + PlaceItemType (itemtype, tilex,tiley); + return; + } + + xl = tilex-1; + xh = tilex+1; + yl = tiley-1; + yh = tiley+1; + + for (x=xl ; x<= xh ; x++) + for (y=yl ; y<= yh ; y++) + if (!actorat[x][y]) + { + PlaceItemType (itemtype, x,y); + return; + } +} + + + +/* +=============== += += KillActor += +=============== +*/ + +void KillActor (objtype *ob) +{ + int tilex,tiley; + + tilex = ob->tilex = ob->x >> TILESHIFT; // drop item on center + tiley = ob->tiley = ob->y >> TILESHIFT; + + switch (ob->obclass) + { + case guardobj: + GivePoints (100); + NewState (ob,&s_grddie1); + PlaceItemType (bo_clip2,tilex,tiley); + break; + + case officerobj: + GivePoints (400); + NewState (ob,&s_ofcdie1); + PlaceItemType (bo_clip2,tilex,tiley); + break; + + case mutantobj: + GivePoints (700); + NewState (ob,&s_mutdie1); + PlaceItemType (bo_clip2,tilex,tiley); + break; + + case ssobj: + GivePoints (500); + NewState (ob,&s_ssdie1); + if (gamestate.bestweapon < wp_machinegun) + PlaceItemType (bo_machinegun,tilex,tiley); + else + PlaceItemType (bo_clip2,tilex,tiley); + break; + + case dogobj: + GivePoints (200); + NewState (ob,&s_dogdie1); + break; + +#ifndef SPEAR + case bossobj: + GivePoints (5000); + NewState (ob,&s_bossdie1); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case gretelobj: + GivePoints (5000); + NewState (ob,&s_greteldie1); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case giftobj: + GivePoints (5000); + gamestate.killx = player->x; + gamestate.killy = player->y; + NewState (ob,&s_giftdie1); + break; + + case fatobj: + GivePoints (5000); + gamestate.killx = player->x; + gamestate.killy = player->y; + NewState (ob,&s_fatdie1); + break; + + case schabbobj: + GivePoints (5000); + gamestate.killx = player->x; + gamestate.killy = player->y; + NewState (ob,&s_schabbdie1); + A_DeathScream(ob); + break; + case fakeobj: + GivePoints (2000); + NewState (ob,&s_fakedie1); + break; + + case mechahitlerobj: + GivePoints (5000); + NewState (ob,&s_mechadie1); + break; + case realhitlerobj: + GivePoints (5000); + gamestate.killx = player->x; + gamestate.killy = player->y; + NewState (ob,&s_hitlerdie1); + A_DeathScream(ob); + break; +#else + case spectreobj: + GivePoints (200); + NewState (ob,&s_spectredie1); + break; + + case angelobj: + GivePoints (5000); + NewState (ob,&s_angeldie1); + break; + + case transobj: + GivePoints (5000); + NewState (ob,&s_transdie0); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case uberobj: + GivePoints (5000); + NewState (ob,&s_uberdie0); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case willobj: + GivePoints (5000); + NewState (ob,&s_willdie1); + PlaceItemType (bo_key1,tilex,tiley); + break; + + case deathobj: + GivePoints (5000); + NewState (ob,&s_deathdie1); + PlaceItemType (bo_key1,tilex,tiley); + break; +#endif + } + + gamestate.killcount++; + ob->flags &= ~FL_SHOOTABLE; + actorat[ob->tilex][ob->tiley] = NULL; + ob->flags |= FL_NONMARK; +} + + + +/* +=================== += += DamageActor += += Called when the player succesfully hits an enemy. += += Does damage points to enemy ob, either putting it into a stun frame or += killing it. += +=================== +*/ + +void DamageActor (objtype *ob, unsigned damage) +{ + madenoise = true; + +// +// do double damage if shooting a non attack mode actor +// + if ( !(ob->flags & FL_ATTACKMODE) ) + damage <<= 1; + + ob->hitpoints -= damage; + + if (ob->hitpoints<=0) + KillActor (ob); + else + { + if (! (ob->flags & FL_ATTACKMODE) ) + FirstSighting (ob); // put into combat mode + + switch (ob->obclass) // dogs only have one hit point + { + case guardobj: + if (ob->hitpoints&1) + NewState (ob,&s_grdpain); + else + NewState (ob,&s_grdpain1); + break; + + case officerobj: + if (ob->hitpoints&1) + NewState (ob,&s_ofcpain); + else + NewState (ob,&s_ofcpain1); + break; + + case mutantobj: + if (ob->hitpoints&1) + NewState (ob,&s_mutpain); + else + NewState (ob,&s_mutpain1); + break; + + case ssobj: + if (ob->hitpoints&1) + NewState (ob,&s_sspain); + else + NewState (ob,&s_sspain1); + + break; + + } + } +} + +/* +============================================================================= + + CHECKSIGHT + +============================================================================= +*/ + + +/* +===================== += += CheckLine += += Returns true if a straight line between the player and ob is unobstructed += +===================== +*/ + +boolean CheckLine (objtype *ob) +{ + int x1,y1,xt1,yt1,x2,y2,xt2,yt2; + int x,y; + int xdist,ydist,xstep,ystep; + int temp; + int partial,delta; + long ltemp; + int xfrac,yfrac,deltafrac; + unsigned value,intercept; + + x1 = ob->x >> UNSIGNEDSHIFT; // 1/256 tile precision + y1 = ob->y >> UNSIGNEDSHIFT; + xt1 = x1 >> 8; + yt1 = y1 >> 8; + + x2 = plux; + y2 = pluy; + xt2 = player->tilex; + yt2 = player->tiley; + + + xdist = abs(xt2-xt1); + + if (xdist > 0) + { + if (xt2 > xt1) + { + partial = 256-(x1&0xff); + xstep = 1; + } + else + { + partial = x1&0xff; + xstep = -1; + } + + deltafrac = abs(x2-x1); + delta = y2-y1; + ltemp = ((long)delta<<8)/deltafrac; + if (ltemp > 0x7fffl) + ystep = 0x7fff; + else if (ltemp < -0x7fffl) + ystep = -0x7fff; + else + ystep = ltemp; + yfrac = y1 + (((long)ystep*partial) >>8); + + x = xt1+xstep; + xt2 += xstep; + do + { + y = yfrac>>8; + yfrac += ystep; + + value = (unsigned)tilemap[x][y]; + x += xstep; + + if (!value) + continue; + + if (value<128 || value>256) + return false; + + // + // see if the door is open enough + // + value &= ~0x80; + intercept = yfrac-ystep/2; + + if (intercept>doorposition[value]) + return false; + + } while (x != xt2); + } + + ydist = abs(yt2-yt1); + + if (ydist > 0) + { + if (yt2 > yt1) + { + partial = 256-(y1&0xff); + ystep = 1; + } + else + { + partial = y1&0xff; + ystep = -1; + } + + deltafrac = abs(y2-y1); + delta = x2-x1; + ltemp = ((long)delta<<8)/deltafrac; + if (ltemp > 0x7fffl) + xstep = 0x7fff; + else if (ltemp < -0x7fffl) + xstep = -0x7fff; + else + xstep = ltemp; + xfrac = x1 + (((long)xstep*partial) >>8); + + y = yt1 + ystep; + yt2 += ystep; + do + { + x = xfrac>>8; + xfrac += xstep; + + value = (unsigned)tilemap[x][y]; + y += ystep; + + if (!value) + continue; + + if (value<128 || value>256) + return false; + + // + // see if the door is open enough + // + value &= ~0x80; + intercept = xfrac-xstep/2; + + if (intercept>doorposition[value]) + return false; + } while (y != yt2); + } + + return true; +} + + + +/* +================ += += CheckSight += += Checks a straight line between player and current object += += If the sight is ok, check alertness and angle to see if they notice += += returns true if the player has been spoted += +================ +*/ + +#define MINSIGHT 0x18000l + +boolean CheckSight (objtype *ob) +{ + long deltax,deltay; + +// +// don't bother tracing a line if the area isn't connected to the player's +// + if (!areabyplayer[ob->areanumber]) + return false; + +// +// if the player is real close, sight is automatic +// + deltax = player->x - ob->x; + deltay = player->y - ob->y; + + if (deltax > -MINSIGHT && deltax < MINSIGHT + && deltay > -MINSIGHT && deltay < MINSIGHT) + return true; + +// +// see if they are looking in the right direction +// + switch (ob->dir) + { + case north: + if (deltay > 0) + return false; + break; + + case east: + if (deltax < 0) + return false; + break; + + case south: + if (deltay < 0) + return false; + break; + + case west: + if (deltax > 0) + return false; + break; + } + +// +// trace a line to check for blocking tiles (corners) +// + return CheckLine (ob); + +} + + + +/* +=============== += += FirstSighting += += Puts an actor into attack mode and possibly reverses the direction += if the player is behind it += +=============== +*/ + +void FirstSighting (objtype *ob) +{ +// +// react to the player +// + switch (ob->obclass) + { + case guardobj: + PlaySoundLocActor(HALTSND,ob); + NewState (ob,&s_grdchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case officerobj: + PlaySoundLocActor(SPIONSND,ob); + NewState (ob,&s_ofcchase1); + ob->speed *= 5; // go faster when chasing player + break; + + case mutantobj: + NewState (ob,&s_mutchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case ssobj: + PlaySoundLocActor(SCHUTZADSND,ob); + NewState (ob,&s_sschase1); + ob->speed *= 4; // go faster when chasing player + break; + + case dogobj: + PlaySoundLocActor(DOGBARKSND,ob); + NewState (ob,&s_dogchase1); + ob->speed *= 2; // go faster when chasing player + break; + +#ifndef SPEAR + case bossobj: + SD_PlaySound(GUTENTAGSND); + NewState (ob,&s_bosschase1); + ob->speed = SPDPATROL*3; // go faster when chasing player + break; + + case gretelobj: + SD_PlaySound(KEINSND); + NewState (ob,&s_gretelchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case giftobj: + SD_PlaySound(EINESND); + NewState (ob,&s_giftchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case fatobj: + SD_PlaySound(ERLAUBENSND); + NewState (ob,&s_fatchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case schabbobj: + SD_PlaySound(SCHABBSHASND); + NewState (ob,&s_schabbchase1); + ob->speed *= 3; // go faster when chasing player + break; + + case fakeobj: + SD_PlaySound(TOT_HUNDSND); + NewState (ob,&s_fakechase1); + ob->speed *= 3; // go faster when chasing player + break; + + case mechahitlerobj: + SD_PlaySound(DIESND); + NewState (ob,&s_mechachase1); + ob->speed *= 3; // go faster when chasing player + break; + + case realhitlerobj: + SD_PlaySound(DIESND); + NewState (ob,&s_hitlerchase1); + ob->speed *= 5; // go faster when chasing player + break; + + case ghostobj: + NewState (ob,&s_blinkychase1); + ob->speed *= 2; // go faster when chasing player + break; +#else + + case spectreobj: + SD_PlaySound(GHOSTSIGHTSND); + NewState (ob,&s_spectrechase1); + ob->speed = 800; // go faster when chasing player + break; + + case angelobj: + SD_PlaySound(ANGELSIGHTSND); + NewState (ob,&s_angelchase1); + ob->speed = 1536; // go faster when chasing player + break; + + case transobj: + SD_PlaySound(TRANSSIGHTSND); + NewState (ob,&s_transchase1); + ob->speed = 1536; // go faster when chasing player + break; + + case uberobj: + NewState (ob,&s_uberchase1); + ob->speed = 3000; // go faster when chasing player + break; + + case willobj: + SD_PlaySound(WILHELMSIGHTSND); + NewState (ob,&s_willchase1); + ob->speed = 2048; // go faster when chasing player + break; + + case deathobj: + SD_PlaySound(KNIGHTSIGHTSND); + NewState (ob,&s_deathchase1); + ob->speed = 2048; // go faster when chasing player + break; + +#endif + } + + if (ob->distance < 0) + ob->distance = 0; // ignore the door opening command + + ob->flags |= FL_ATTACKMODE|FL_FIRSTATTACK; +} + + + +/* +=============== += += SightPlayer += += Called by actors that ARE NOT chasing the player. If the player += is detected (by sight, noise, or proximity), the actor is put into += it's combat frame and true is returned. += += Incorporates a random reaction delay += +=============== +*/ + +boolean SightPlayer (objtype *ob) +{ + if (ob->flags & FL_ATTACKMODE) + Quit ("An actor in ATTACKMODE called SightPlayer!"); + + if (ob->temp2) + { + // + // count down reaction time + // + ob->temp2 -= tics; + if (ob->temp2 > 0) + return false; + ob->temp2 = 0; // time to react + } + else + { + if (!areabyplayer[ob->areanumber]) + return false; + + if (ob->flags & FL_AMBUSH) + { + if (!CheckSight (ob)) + return false; + ob->flags &= ~FL_AMBUSH; + } + else + { + if (!madenoise && !CheckSight (ob)) + return false; + } + + + switch (ob->obclass) + { + case guardobj: + ob->temp2 = 1+US_RndT()/4; + break; + case officerobj: + ob->temp2 = 2; + break; + case mutantobj: + ob->temp2 = 1+US_RndT()/6; + break; + case ssobj: + ob->temp2 = 1+US_RndT()/6; + break; + case dogobj: + ob->temp2 = 1+US_RndT()/8; + break; + + case bossobj: + case schabbobj: + case fakeobj: + case mechahitlerobj: + case realhitlerobj: + case gretelobj: + case giftobj: + case fatobj: + case spectreobj: + case angelobj: + case transobj: + case uberobj: + case willobj: + case deathobj: + ob->temp2 = 1; + break; + } + return false; + } + + FirstSighting (ob); + + return true; +} + +