+++ /dev/null
-/* Reconstructed Commander Keen 4-6 Source Code\r
- * Copyright (C) 2021 K1n9_Duk3\r
- *\r
- * This file is loosely based on:\r
- * Keen Dreams Source Code\r
- * Copyright (C) 2014 Javier M. Chavez\r
- *\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License along\r
- * with this program; if not, write to the Free Software Foundation, Inc.,\r
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
- */\r
-\r
-#include "CK_DEF.H"\r
-\r
-/*\r
-=============================================================================\r
-\r
- GLOBAL VARIABLES\r
-\r
-=============================================================================\r
-*/\r
-\r
-ScanCode firescan = sc_Space;\r
-\r
-boolean singlestep, jumpcheat, godmode, keenkilled;\r
-\r
-exittype playstate;\r
-gametype gamestate;\r
-\r
-objtype *new, *check, *player, *scoreobj;\r
-\r
-Uint16 originxtilemax;\r
-Uint16 originytilemax;\r
-\r
-ControlInfo c;\r
-boolean button2, button3; // never used\r
-\r
-objtype dummyobj;\r
-\r
-Sint16 invincible;\r
-\r
-boolean oldshooting, showscorebox, joypad;\r
-\r
-Sint16 groundslam;\r
-\r
-boolean debugok;\r
-boolean jumpbutton, jumpheld, pogobutton, pogoheld, firebutton, fireheld, upheld;\r
-\r
-\r
-/*\r
-=============================================================================\r
-\r
- LOCAL VARIABLES\r
-\r
-=============================================================================\r
-*/\r
-\r
-objtype *obj;\r
-\r
-Uint16 centerlevel;\r
-\r
-Uint16 objectcount;\r
-objtype objarray[MAXACTORS];\r
-objtype *lastobj;\r
-objtype *objfreelist;\r
-\r
-Sint16 inactivateleft;\r
-Sint16 inactivateright;\r
-Sint16 inactivatetop;\r
-Sint16 inactivatebottom;\r
-\r
-#ifdef KEEN6Ev15\r
-Uint16 __dummy__; // never used, but must be present to recreate the original EXE\r
-#endif\r
-\r
-Uint16 extravbls;\r
-\r
-Uint16 windowofs;\r
-Sint16 vislines;\r
-boolean scrollup;\r
-\r
-Sint16 oldfirecount;\r
-\r
-//===========================================================================\r
-\r
-/*\r
-==================\r
-=\r
-= CountObjects\r
-=\r
-==================\r
-*/\r
-\r
-void CountObjects(void)\r
-{\r
- Uint16 activeobjects, inactiveobjects;\r
- objtype *ob;\r
-\r
- activeobjects = inactiveobjects = 0;\r
- for (ob=player; ob; ob=ob->next)\r
- {\r
- if (ob->active)\r
- {\r
- activeobjects++;\r
- }\r
- else\r
- {\r
- inactiveobjects++;\r
- }\r
- }\r
- VW_FixRefreshBuffer();\r
- US_CenterWindow(18, 4);\r
- PrintY += 7;\r
- US_Print("Active Objects :");\r
- US_PrintUnsigned(activeobjects);\r
- US_Print("\nInactive Objects:");\r
- US_PrintUnsigned(inactiveobjects);\r
- VW_UpdateScreen();\r
- IN_Ack();\r
-}\r
-\r
-/*\r
-==================\r
-=\r
-= DebugMemory\r
-=\r
-==================\r
-*/\r
-\r
-void DebugMemory(void)\r
-{\r
- VW_FixRefreshBuffer();\r
- US_CenterWindow(16, 7);\r
- US_CPrint("Memory Usage");\r
- US_CPrint("------------");\r
- US_Print("Total :");\r
- US_PrintUnsigned((mminfo.mainmem+mminfo.EMSmem+mminfo.XMSmem)/1024);\r
- US_Print("k\nFree :");\r
- US_PrintUnsigned(MM_UnusedMemory()/1024);\r
- US_Print("k\nWith purge:");\r
- US_PrintUnsigned(MM_TotalFree()/1024);\r
- US_Print("k\n");\r
- VW_UpdateScreen();\r
- IN_Ack();\r
-#if GRMODE != CGAGR\r
- MM_ShowMemory();\r
-#endif\r
-}\r
-\r
-/*\r
-===================\r
-=\r
-= TestSprites\r
-=\r
-===================\r
-*/\r
-\r
-void TestSprites(void)\r
-{\r
- Uint16 infox, infoy;\r
- Sint16 chunk, oldchunk;\r
- Sint16 shift;\r
- Uint16 infobottom, drawx;\r
- spritetabletype far *info;\r
- Uint8 _seg *block;\r
- Uint16 size;\r
- Uint16 scan;\r
- Uint32 totalsize;\r
-\r
- VW_FixRefreshBuffer();\r
- US_CenterWindow(30, 17);\r
- totalsize = 0;\r
- US_CPrint("Sprite Test");\r
- US_CPrint("-----------");\r
- infoy = PrintY;\r
- infox = (PrintX + 56) & ~7;\r
- drawx = infox + 40;\r
- US_Print("Chunk:\nWidth:\nHeight:\nOrgx:\nOrgy:\nXl:\nYl:\nXh:\nYh:\nShifts:\nMem:\n");\r
- infobottom = PrintY;\r
- chunk = STARTSPRITES;\r
- shift = 0;\r
- while (1)\r
- {\r
- if (chunk >= STARTSPRITES+NUMSPRITES)\r
- {\r
- chunk = STARTSPRITES+NUMSPRITES-1;\r
- }\r
- else if (chunk < STARTSPRITES)\r
- {\r
- chunk = STARTSPRITES;\r
- }\r
- info = &spritetable[chunk-STARTSPRITES];\r
- block = grsegs[chunk];\r
- VWB_Bar(infox, infoy, 40, infobottom-infoy, WHITE);\r
- PrintX = infox;\r
- PrintY = infoy;\r
- US_PrintUnsigned(chunk);\r
- US_Print("\n");\r
- PrintX = infox;\r
- US_PrintUnsigned(info->width);\r
- US_Print("\n");\r
- PrintX = infox;\r
- US_PrintUnsigned(info->height);\r
- US_Print("\n");\r
- PrintX = infox;\r
- US_PrintSigned(info->orgx);\r
- US_Print("\n");\r
- PrintX = infox;\r
- US_PrintSigned(info->orgy);\r
- US_Print("\n");\r
- PrintX = infox;\r
- US_PrintSigned(info->xl);\r
- US_Print("\n");\r
- PrintX = infox;\r
- US_PrintSigned(info->yl);\r
- US_Print("\n");\r
- PrintX = infox;\r
- US_PrintSigned(info->xh);\r
- US_Print("\n");\r
- PrintX = infox;\r
- US_PrintSigned(info->yh);\r
- US_Print("\n");\r
- PrintX = infox;\r
- US_PrintSigned(info->shifts);\r
- US_Print("\n");\r
- PrintX = infox;\r
- if (!block)\r
- {\r
- US_Print("-----");\r
- }\r
- else\r
- {\r
- size = ((spritetype far *)block)->sourceoffset[3] + ((spritetype far *)block)->planesize[3]*5;\r
- size = (size + 15) & ~15; //round up to multiples of 16\r
- totalsize += size; //useless: the value stored in 'totalsize' is never used\r
- US_PrintUnsigned(size);\r
- US_Print("=");\r
- }\r
- oldchunk = chunk;\r
- do\r
- {\r
- VWB_Bar(drawx, infoy, 110, infobottom-infoy, WHITE);\r
- if (block)\r
- {\r
- PrintX = drawx;\r
- PrintY = infoy;\r
- US_Print("Shift:");\r
- US_PrintUnsigned(shift);\r
- US_Print("\n");\r
- VWB_DrawSprite(drawx + 2*shift + 16, PrintY, chunk);\r
- }\r
- VW_UpdateScreen();\r
- scan = IN_WaitForKey();\r
- switch (scan)\r
- {\r
- case sc_UpArrow:\r
- chunk++;\r
- break;\r
- case sc_DownArrow:\r
- chunk--;\r
- break;\r
- case sc_PgUp:\r
- chunk += 10;\r
- if (chunk >= STARTSPRITES+NUMSPRITES)\r
- {\r
- chunk = STARTSPRITES+NUMSPRITES-1;\r
- }\r
- break;\r
- case sc_PgDn:\r
- chunk -= 10;\r
- if (chunk < STARTSPRITES)\r
- {\r
- chunk = STARTSPRITES;\r
- }\r
- break;\r
- case sc_LeftArrow:\r
- if (--shift == -1)\r
- {\r
- shift = 3;\r
- }\r
- break;\r
- case sc_RightArrow:\r
- if (++shift == 4)\r
- {\r
- shift = 0;\r
- }\r
- break;\r
- case sc_Escape:\r
- return;\r
- }\r
-\r
- } while (chunk == oldchunk);\r
-\r
- }\r
-}\r
-\r
-/*\r
-===================\r
-=\r
-= PicturePause\r
-=\r
-===================\r
-*/\r
-\r
-void PicturePause(void)\r
-{\r
- Uint16 source;\r
- Sint16 y;\r
-\r
-//\r
-// wait for a key press, abort if it's not Enter\r
-//\r
- IN_ClearKeysDown();\r
- while (!LastScan);\r
- if (LastScan != sc_Enter)\r
- {\r
- IN_ClearKeysDown();\r
- return;\r
- }\r
-\r
- SD_PlaySound(SND_JUMP);\r
- SD_WaitSoundDone();\r
-\r
-//\r
-// rearrange onscreen image into base EGA layout, so that it\r
-// can be grabbed correctly by an external screenshot tool\r
-//\r
- source = displayofs + panadjust;\r
-\r
- VW_ColorBorder(15); // white (can't use WHITE as parameter, since that's defined as 3 for CGA and this must use 15)\r
- VW_SetLineWidth(40);\r
- VW_SetScreen(0, 0);\r
-\r
- if (source < 0x10000l-200*64)\r
- {\r
- //\r
- // copy top line first\r
- //\r
- for (y=0; y<200; y++)\r
- {\r
- VW_ScreenToScreen(source+y*64, y*40, 40, 1);\r
- }\r
- }\r
- else\r
- {\r
- //\r
- // copy bottom line first\r
- //\r
- for (y=199; y>=0; y--)\r
- {\r
- VW_ScreenToScreen(source+y*64, y*40, 40, 1);\r
- }\r
- }\r
-\r
-//\r
-// shut down input manager so that screenshot tool can see input again\r
-//\r
- IN_Shutdown();\r
-\r
- SD_PlaySound(SND_EXTRAKEEN);\r
- SD_WaitSoundDone();\r
-\r
-//\r
-// shut down the remaining ID managers, except VW (stay in graphics mode!)\r
-//\r
- US_Shutdown();\r
- SD_Shutdown();\r
- IN_Shutdown();\r
- RF_Shutdown();\r
- CA_Shutdown();\r
- MM_Shutdown();\r
-\r
-//\r
-// wait until user hits Escape\r
-//\r
- while (((bioskey(0) >> 8) & 0xFF) != sc_Escape);\r
-\r
-//\r
-// back to text mode and exit to DOS\r
-//\r
- VW_Shutdown();\r
- exit(0);\r
-}\r
-\r
-/*\r
-===================\r
-=\r
-= MaskOnTile\r
-=\r
-===================\r
-*/\r
-\r
-void MaskOnTile(Uint16 dest, Uint16 source)\r
-{\r
- Sint16 i;\r
- Uint16 _seg *sourceseg;\r
- Uint16 _seg *destseg;\r
- Uint16 sourceval, maskindex, sourcemask;\r
-\r
- sourceseg = (grsegs+STARTTILE16M)[source];\r
- destseg = (grsegs+STARTTILE16M)[dest];\r
- for (i=0; i<64; i++)\r
- {\r
- maskindex = i & 15;\r
-#ifdef KEEN6Ev15\r
- sourceval = sourceseg[16+i];\r
-#else\r
- sourceval = (sourceseg+16)[i];\r
-#endif\r
- sourcemask = sourceseg[maskindex];\r
- destseg[maskindex] &= sourcemask;\r
- destseg[16+i] &= sourcemask;\r
- destseg[16+i] |= sourceval;\r
- }\r
-}\r
-\r
-/*\r
-===================\r
-=\r
-= WallDebug\r
-=\r
-===================\r
-*/\r
-\r
-void WallDebug(void)\r
-{\r
- Sint16 i, val;\r
-\r
- VW_FixRefreshBuffer();\r
- US_CenterWindow(24, 3);\r
- US_PrintCentered("WORKING");\r
- VW_UpdateScreen();\r
- for (i=STARTTILE16M+108; i<STARTTILE16M+124; i++)\r
- {\r
- CA_CacheGrChunk(i);\r
- }\r
- for (i=0; i<NUMTILE16M; i++)\r
- {\r
- if (!grsegs[STARTTILE16M+i])\r
- {\r
- continue;\r
- }\r
- val = tinf[i+NORTHWALL] & 7;\r
- if (val)\r
- {\r
- MaskOnTile(i, val+107);\r
- }\r
- val = tinf[i+SOUTHWALL] & 7;\r
- if (val)\r
- {\r
- MaskOnTile(i, val+115);\r
- }\r
- val = tinf[i+EASTWALL] & 7;\r
- if (val > 1)\r
- {\r
- strcpy(str, "WallDebug: East wall other than 1:");\r
- itoa(i, str2, 10);\r
- strcat(str, str2);\r
- Quit(str);\r
- }\r
- if (val)\r
- {\r
- MaskOnTile(i, val+114); //Note: val is always 1 here, so you could use 115 as 2nd arg\r
- }\r
- val = tinf[i+WESTWALL] & 7;\r
- if (val > 1)\r
- {\r
- strcpy(str, "WallDebug: West wall other than 1:");\r
- itoa(i, str2, 10);\r
- strcat(str, str2);\r
- Quit(str);\r
- }\r
- if (val)\r
- {\r
- MaskOnTile(i, val+122); //Note: val is always 1 here, so you could use 123 as 2nd arg\r
- }\r
- }\r
-}\r
-\r
-\r
-//===========================================================================\r
-\r
-/*\r
-================\r
-=\r
-= DebugKeys\r
-=\r
-================\r
-*/\r
-\r
-boolean DebugKeys(void)\r
-{\r
- Sint16 level, i, esc;\r
-\r
- if (Keyboard[sc_B] && ingame) // B = border color\r
- {\r
- VW_FixRefreshBuffer();\r
- US_CenterWindow(24, 3);\r
- PrintY += 6;\r
- US_Print(" Border color (0-15):");\r
- VW_UpdateScreen();\r
- esc = !US_LineInput(px, py, str, NULL, true, 2, 0);\r
- if (!esc)\r
- {\r
- level = atoi(str);\r
- if (level >= 0 && level <= 15)\r
- {\r
- VW_ColorBorder(level);\r
- }\r
- }\r
- return true;\r
- }\r
-\r
- if (Keyboard[sc_C] && ingame) // C = count objects\r
- {\r
- CountObjects();\r
- return true;\r
- }\r
-\r
- if (Keyboard[sc_D] && ingame) // D = start / end demo record\r
- {\r
- if (DemoMode == demo_Off)\r
- {\r
- StartDemoRecord();\r
- }\r
- else if (DemoMode == demo_Record)\r
- {\r
- EndDemoRecord();\r
- playstate = ex_completed;\r
- }\r
- return true;\r
- }\r
-\r
- if (Keyboard[sc_E] && ingame) // E = quit level\r
- {\r
- if (tedlevel)\r
- {\r
- TEDDeath();\r
- }\r
- playstate = ex_completed;\r
- //BUG? there is no return in this branch (should return false)\r
- }\r
-\r
- if (Keyboard[sc_G] && ingame) // G = god mode\r
- {\r
- VW_FixRefreshBuffer();\r
- US_CenterWindow(12, 2);\r
- if (godmode)\r
- {\r
- US_PrintCentered("God mode OFF");\r
- }\r
- else\r
- {\r
- US_PrintCentered("God mode ON");\r
- }\r
- VW_UpdateScreen();\r
- IN_Ack();\r
- godmode ^= true;\r
- return true;\r
- }\r
- else if (Keyboard[sc_I]) // I = item cheat\r
- {\r
- VW_FixRefreshBuffer();\r
- US_CenterWindow(12, 3);\r
- US_PrintCentered("Free items!");\r
- for (i=0; i<4; i++)\r
- {\r
- gamestate.keys[i] = 99;\r
- }\r
- gamestate.ammo = 99;\r
-#if defined KEEN4\r
- gamestate.wetsuit = true;\r
-#elif defined KEEN5\r
- gamestate.keycard = true;\r
-#elif defined KEEN6\r
- gamestate.passcardstate=gamestate.hookstate=gamestate.sandwichstate = 1;\r
-#endif\r
- VW_UpdateScreen();\r
- IN_Ack();\r
- GivePoints(3000);\r
- return true;\r
- }\r
- else if (Keyboard[sc_J]) // J = jump cheat\r
- {\r
- jumpcheat ^= true;\r
- VW_FixRefreshBuffer();\r
- US_CenterWindow(18, 3);\r
- if (jumpcheat)\r
- {\r
- US_PrintCentered("Jump cheat ON");\r
- }\r
- else\r
- {\r
- US_PrintCentered("Jump cheat OFF");\r
- }\r
- VW_UpdateScreen();\r
- IN_Ack();\r
- return true;\r
- }\r
- else if (Keyboard[sc_M]) // M = memory info\r
- {\r
- DebugMemory();\r
- return true;\r
- }\r
- else if (Keyboard[sc_N]) // N = no clip\r
- {\r
- VW_FixRefreshBuffer();\r
- US_CenterWindow(18, 3);\r
- if (player->needtoclip)\r
- {\r
- US_PrintCentered("No clipping ON");\r
- player->needtoclip = cl_noclip;\r
- }\r
- else\r
- {\r
- US_PrintCentered("No clipping OFF");\r
- player->needtoclip = cl_midclip;\r
- }\r
- VW_UpdateScreen();\r
- IN_Ack();\r
- return true;\r
- }\r
- else if (Keyboard[sc_P]) // P = pause with no screen disruptioon\r
- {\r
- IN_ClearKeysDown();\r
- PicturePause();\r
- return true;\r
- }\r
- else if (Keyboard[sc_S] && ingame) // S = slow motion\r
- {\r
- singlestep ^= true;\r
- VW_FixRefreshBuffer();\r
- US_CenterWindow(18, 3);\r
- if (singlestep)\r
- {\r
- US_PrintCentered("Slow motion ON");\r
- }\r
- else\r
- {\r
- US_PrintCentered("Slow motion OFF");\r
- }\r
- VW_UpdateScreen();\r
- IN_Ack();\r
- return true;\r
- }\r
- else if (Keyboard[sc_T]) // T = sprite test\r
- {\r
- TestSprites();\r
- return true;\r
- }\r
- else if (Keyboard[sc_V]) // V = extra VBLs\r
- {\r
- VW_FixRefreshBuffer();\r
- US_CenterWindow(30, 3);\r
- PrintY += 6;\r
- US_Print(" Add how many extra VBLs(0-8):");\r
- VW_UpdateScreen();\r
- esc = !US_LineInput(px, py, str, NULL, true, 2, 0);\r
- if (!esc)\r
- {\r
- level = atoi(str);\r
- if (level >= 0 && level <= 8)\r
- {\r
- extravbls = level;\r
- }\r
- }\r
- return true;\r
- }\r
- else if (Keyboard[sc_W] && ingame) // W = warp to level\r
- {\r
- VW_FixRefreshBuffer();\r
- US_CenterWindow(26, 3);\r
- PrintY += 6;\r
- US_Print(" Warp to which level(1-18):");\r
- VW_UpdateScreen();\r
- esc = !US_LineInput(px, py, str, NULL, true, 2, 0);\r
- if (!esc)\r
- {\r
- level = atoi(str);\r
- if (level > 0 && level <= 18)\r
- {\r
- gamestate.mapon = level;\r
- playstate = ex_warped;\r
- }\r
- }\r
- return true;\r
- }\r
- else if (Keyboard[sc_Y]) // Y = wall debug\r
- {\r
- WallDebug();\r
- return true;\r
- }\r
- else if (Keyboard[sc_Z]) // Z = game over\r
- {\r
- gamestate.lives = 0;\r
- KillKeen();\r
- return false;\r
- }\r
- return false;\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-================\r
-=\r
-= UserCheat\r
-=\r
-================\r
-*/\r
-\r
-void UserCheat(void)\r
-{\r
- Sint16 i;\r
-\r
- for (i=sc_A; i<=sc_Z; i++) //Note: this does NOT check the keys in alphabetical order!\r
- {\r
- if (i != sc_B && i != sc_A && i != sc_T && Keyboard[i])\r
- {\r
- return;\r
- }\r
- }\r
- US_CenterWindow(20, 7);\r
- PrintY += 2;\r
- US_CPrint(\r
- "Cheat Option!\n"\r
- "\n"\r
- "You just got all\n"\r
- "the keys, 99 shots,\n"\r
- "and an extra keen!");\r
- VW_UpdateScreen();\r
- IN_Ack();\r
- RF_ForceRefresh();\r
- gamestate.ammo = 99;\r
- gamestate.lives++;\r
-#ifdef KEEN5\r
- gamestate.keycard = true;\r
-#endif\r
- gamestate.keys[0] = gamestate.keys[1] = gamestate.keys[2] = gamestate.keys[3] = 1;\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=====================\r
-=\r
-= CheckKeys\r
-=\r
-=====================\r
-*/\r
-\r
-void CheckKeys(void)\r
-{\r
- if (screenfaded) // don't do anything with a faded screen\r
- {\r
- return;\r
- }\r
-\r
-//\r
-// Enter for status screen\r
-//\r
- if (Keyboard[sc_Enter] || (GravisGamepad && GravisAction[ga_Status]))\r
- {\r
- StatusWindow();\r
- IN_ClearKeysDown();\r
- RF_ForceRefresh();\r
- lasttimecount = TimeCount; // BUG: should be the other way around\r
- }\r
-\r
-//\r
-// pause key wierdness can't be checked as a scan code\r
-//\r
- if (Paused)\r
- {\r
- SD_MusicOff();\r
- VW_FixRefreshBuffer();\r
- US_CenterWindow(8, 3);\r
- US_PrintCentered("PAUSED");\r
- VW_UpdateScreen();\r
- IN_Ack();\r
- RF_ForceRefresh();\r
- Paused = false;\r
- SD_MusicOn();\r
- }\r
-\r
-#ifndef KEEN6\r
-//\r
-// F1 to enter help screens\r
-//\r
- if (LastScan == sc_F1)\r
- {\r
- StopMusic();\r
- HelpScreens();\r
- StartMusic(gamestate.mapon);\r
- if (showscorebox)\r
- {\r
- scoreobj->temp2 = -1;\r
- scoreobj->temp1 = -1;\r
- scoreobj->temp3 = -1;\r
- scoreobj->temp4 = -1;\r
- }\r
- RF_ForceRefresh();\r
- }\r
-#endif\r
-\r
- if (!storedemo)\r
- {\r
-//\r
-// F2-F7/ESC to enter control panel\r
-//\r
- if (LastScan >= sc_F2 && LastScan <= sc_F7 || LastScan == sc_Escape)\r
- {\r
- VW_FixRefreshBuffer();\r
- StopMusic();\r
- US_ControlPanel();\r
- RF_FixOfs();\r
- StartMusic(gamestate.mapon);\r
- if (!showscorebox && scoreobj->sprite)\r
- {\r
- RF_RemoveSprite(&scoreobj->sprite);\r
- }\r
- if (showscorebox)\r
- {\r
- scoreobj->temp2 = -1;\r
- scoreobj->temp1 = -1;\r
- scoreobj->temp3 = -1;\r
- scoreobj->temp4 = -1;\r
- }\r
- IN_ClearKeysDown();\r
- if (restartgame)\r
- {\r
- playstate = ex_resetgame;\r
- }\r
- else if (!loadedgame)\r
- {\r
- RF_ForceRefresh();\r
- }\r
- if (abortgame)\r
- {\r
- abortgame = false;\r
- playstate = ex_abortgame;\r
- }\r
- if (loadedgame)\r
- {\r
- playstate = ex_loadedgame;\r
- }\r
- lasttimecount = TimeCount; // BUG: should be the other way around\r
- }\r
-\r
-//\r
-// F9 boss key\r
-//\r
- if (LastScan == sc_F9)\r
- {\r
- VW_Shutdown();\r
- SD_MusicOff();\r
- cputs("C:>");\r
- IN_ClearKeysDown();\r
- while (LastScan != sc_Escape);\r
- VW_SetScreenMode(GRMODE);\r
- VW_ColorBorder(bordercolor);\r
- RF_ForceRefresh();\r
- IN_ClearKeysDown();\r
- lasttimecount = TimeCount; // BUG: should be the other way around\r
- SD_MusicOn();\r
- }\r
- }\r
-\r
-//\r
-// B-A-T cheat code\r
-//\r
- if (Keyboard[sc_B] && Keyboard[sc_A] && Keyboard[sc_T])\r
- {\r
- UserCheat();\r
- }\r
-\r
-//\r
-// F10-? debug keys\r
-//\r
- if (debugok && Keyboard[sc_F10])\r
- {\r
- if (DebugKeys())\r
- {\r
- RF_ForceRefresh();\r
- lasttimecount = TimeCount; // BUG: should be the other way around\r
- }\r
- }\r
-\r
-//\r
-// Ctrl-S toggles sound (only in storedemo mode)\r
-//\r
- if (storedemo && Keyboard[sc_Control] && LastScan == sc_S)\r
- {\r
- if (SoundMode != sdm_Off)\r
- {\r
- SD_SetSoundMode(sdm_Off);\r
- SD_SetMusicMode(smm_Off);\r
- }\r
- else\r
- {\r
- if (AdLibPresent)\r
- {\r
- SD_SetSoundMode(sdm_AdLib);\r
- QuietFX = false;\r
- SD_SetMusicMode(smm_AdLib);\r
- }\r
- else\r
- {\r
- SD_SetSoundMode(sdm_PC);\r
- SD_SetMusicMode(smm_Off);\r
- }\r
- CA_LoadAllSounds();\r
- }\r
- }\r
-\r
-//\r
-// Ctrl-Q quick quit\r
-//\r
- if (Keyboard[sc_Control] && LastScan == sc_Q)\r
- {\r
- IN_ClearKeysDown();\r
- Quit(NULL);\r
- }\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-==================\r
-=\r
-= PrintNumbers\r
-=\r
-==================\r
-*/\r
-\r
-void PrintNumbers(Sint16 x, Sint16 y, Sint16 maxlen, Sint16 basetile, Sint32 number)\r
-{\r
- register Sint16 i;\r
- Sint16 len;\r
- char buffer[20];\r
-\r
- ltoa(number, buffer, 10);\r
- len = strlen(buffer);\r
- i = maxlen;\r
- while (i>len)\r
- {\r
- VWB_DrawTile8(x, y, basetile);\r
- i--;\r
- x += 8;\r
- }\r
- while (i>0)\r
- {\r
- VWB_DrawTile8(x, y, basetile+buffer[len-i]+(1-'0'));\r
- i--;\r
- x += 8;\r
- }\r
-}\r
-\r
-/*\r
-==================\r
-=\r
-= DrawStatusWindow\r
-=\r
-==================\r
-*/\r
-\r
-#if GRMODE == CGAGR\r
-\r
-#define BACKCOLOR WHITE\r
-#define TEXTBACK BLACK\r
-#define NUMBERBACK BLACK\r
-\r
-#else\r
-\r
-#define BACKCOLOR LIGHTGRAY\r
-#define TEXTBACK WHITE\r
-#define NUMBERBACK BLACK\r
-\r
-#endif\r
-\r
-void DrawStatusWindow(void)\r
-{\r
- Sint16 off, x, y, w, h, i;\r
- Uint16 width, height;\r
-\r
- x = 64;\r
- y = 16;\r
- w = 184;\r
- h = 144;\r
- VWB_DrawTile8(x, y, 54);\r
- VWB_DrawTile8(x, y+h, 60);\r
- for (i=x+8; i<=x+w-8; i+=8)\r
- {\r
- VWB_DrawTile8(i, y, 55);\r
- VWB_DrawTile8(i, y+h, 61);\r
- }\r
- VWB_DrawTile8(i, y, 56);\r
- VWB_DrawTile8(i, y+h, 62);\r
- for (i=y+8; i<=y+h-8; i+=8)\r
- {\r
- VWB_DrawTile8(x, i, 57);\r
- VWB_DrawTile8(x+w, i, 59);\r
- }\r
- VWB_Bar(72, 24, 176, 136, BACKCOLOR);\r
-\r
- PrintY = 28;\r
- WindowX = 80;\r
- WindowW = 160;\r
- US_CPrint("LOCATION");\r
- VWB_Bar(79, 38, 162, 20, TEXTBACK);\r
-#ifdef KEEN5\r
- if (mapon == 0 && player->y > 100*TILEGLOBAL)\r
- _fstrcpy(str, levelnames[13]);\r
- else\r
- _fstrcpy(str, levelnames[gamestate.mapon]);\r
-#else\r
- _fstrcpy(str, levelnames[gamestate.mapon]);\r
-#endif\r
- SizeText(str, &width, &height);\r
- PrintY = (20-height)/2+40-2;\r
- US_CPrint(str);\r
-\r
- PrintY = 61;\r
- WindowX = 80;\r
- WindowW = 64;\r
- US_CPrint("SCORE");\r
- VWB_Bar(79, 71, 66, 10, NUMBERBACK);\r
- PrintNumbers(80, 72, 8, 41, gamestate.score);\r
-\r
- PrintY = 61;\r
- WindowX = 176;\r
- WindowW = 64;\r
- US_CPrint("EXTRA");\r
- VWB_Bar(175, 71, 66, 10, NUMBERBACK);\r
- PrintNumbers(176, 72, 8, 41, gamestate.nextextra);\r
-\r
-#if defined KEEN4\r
- PrintY = 85;\r
- WindowX = 80;\r
- WindowW = 64;\r
- US_CPrint("RESCUED");\r
- VWB_Bar(79, 95, 66, 10, NUMBERBACK);\r
- for (i = 0; i < gamestate.rescued; i++, off+=8)\r
- {\r
- VWB_DrawTile8(i*8 + 80, 96, 40);\r
- }\r
-#elif defined KEEN5\r
- PrintY = 92;\r
- PrintX = 80;\r
- US_Print("KEYCARD");\r
- VWB_Bar(135, 91, 10, 10, NUMBERBACK);\r
- if (gamestate.keycard)\r
- {\r
- VWB_DrawTile8(136, 92, 40);\r
- }\r
-#endif\r
-\r
- PrintY = 85;\r
- WindowX = 176;\r
- WindowW = 64;\r
- US_CPrint("LEVEL");\r
- VWB_Bar(175, 95, 66, 10, TEXTBACK);\r
- PrintY = 96;\r
- WindowX = 176;\r
- WindowW = 64;\r
- switch (gamestate.difficulty)\r
- {\r
- case gd_Easy:\r
- US_CPrint("Easy");\r
- break;\r
- case gd_Normal:\r
- US_CPrint("Normal");\r
- break;\r
- case gd_Hard:\r
- US_CPrint("Hard");\r
- break;\r
- }\r
-\r
-#ifdef KEEN6\r
- PrintX = 80;\r
- PrintY = 96;\r
- US_Print("ITEMS");\r
- VWB_Bar(127, 95, 26, 10, NUMBERBACK);\r
- if (gamestate.sandwichstate == 1)\r
- {\r
- VWB_DrawTile8(128, 96, 2);\r
- }\r
- else\r
- {\r
- VWB_DrawTile8(128, 96, 1);\r
- }\r
- if (gamestate.hookstate == 1)\r
- {\r
- VWB_DrawTile8(136, 96, 4);\r
- }\r
- else\r
- {\r
- VWB_DrawTile8(136, 96, 3);\r
- }\r
- if (gamestate.passcardstate == 1)\r
- {\r
- VWB_DrawTile8(144, 96, 6);\r
- }\r
- else\r
- {\r
- VWB_DrawTile8(144, 96, 5);\r
- }\r
-#endif\r
-\r
- PrintX = 80;\r
- PrintY = 112;\r
- US_Print("KEYS");\r
- VWB_Bar(119, 111, 34, 10, NUMBERBACK);\r
- for (i = 0; i < 4; i++)\r
- {\r
- if (gamestate.keys[i])\r
- {\r
- VWB_DrawTile8(i*8+120, 112, 36+i);\r
- }\r
- }\r
-\r
- PrintX = 176;\r
- PrintY = 112;\r
- US_Print("AMMO");\r
- VWB_Bar(215, 111, 26, 10, NUMBERBACK);\r
- PrintNumbers(216, 112, 3, 41, gamestate.ammo);\r
-\r
- PrintX = 80;\r
- PrintY = 128;\r
- US_Print("KEENS");\r
- VWB_Bar(127, 127, 18, 10, NUMBERBACK);\r
- PrintNumbers(128, 128, 2, 41, gamestate.lives);\r
-\r
- PrintX = 176;\r
- PrintY = 128;\r
- US_Print(DROPSNAME);\r
- VWB_Bar(224, 127, 16, 10, NUMBERBACK);\r
- PrintNumbers(224, 128, 2, 41, gamestate.drops);\r
-\r
-#ifdef KEEN4\r
- VWB_Bar(79, 143, 66, 10, TEXTBACK);\r
- PrintY = 144;\r
- WindowX = 80;\r
- WindowW = 64;\r
- if (gamestate.wetsuit)\r
- {\r
- US_CPrint("Wetsuit");\r
- }\r
- else\r
- {\r
- US_CPrint("???");\r
- }\r
-#endif\r
-\r
- // draw the tiles for "PRESS A KEY":\r
- for (i = 0; i < 10; i++)\r
- {\r
- VWB_DrawTile8(i*8+STATUS_PRESSKEY_X, 140, i+72);\r
- VWB_DrawTile8(i*8+STATUS_PRESSKEY_X, 148, i+82);\r
- }\r
-}\r
-\r
-/*\r
-==================\r
-=\r
-= ScrollStatusWindow\r
-=\r
-==================\r
-*/\r
-\r
-void ScrollStatusWindow(void)\r
-{\r
- Uint16 source, dest;\r
- Sint16 height;\r
-\r
- if (vislines > 152)\r
- {\r
- height = vislines - 152;\r
- source = windowofs + panadjust + 8;\r
- dest = bufferofs + panadjust + 8;\r
- VW_ScreenToScreen(source, dest, 192/BYTEPIXELS, height);\r
- VW_ClipDrawMPic((pansx+136)/BYTEPIXELS, -(16-height)+pansy, METALPOLEPICM);\r
- source = windowofs + panadjust + 16*SCREENWIDTH + 8*CHARWIDTH;\r
- dest = bufferofs + panadjust + height*SCREENWIDTH + 8;\r
- height = 152;\r
- }\r
- else\r
- {\r
- source = windowofs + panadjust + (152-vislines)*SCREENWIDTH + 16*SCREENWIDTH + 8*CHARWIDTH;\r
- dest = bufferofs + panadjust + 8;\r
- height = vislines;\r
- }\r
- if (height > 0)\r
- {\r
- VW_ScreenToScreen(source, dest, 192/BYTEPIXELS, height);\r
- }\r
- if (scrollup)\r
- {\r
- height = 168-vislines;\r
- source = masterofs + panadjust + vislines*SCREENWIDTH + 8;\r
- dest = bufferofs + panadjust + vislines*SCREENWIDTH + 8;\r
- VW_ScreenToScreen(source, dest, 192/BYTEPIXELS, height);\r
- height = vislines;\r
- source = windowofs + panadjust + 8 - 24/BYTEPIXELS;\r
- dest = bufferofs + panadjust + 8 - 24/BYTEPIXELS;\r
- if (height > 0)\r
- VW_ScreenToScreen(source, dest, 24/BYTEPIXELS, height);\r
- }\r
- else\r
- {\r
- height = vislines + -72;\r
- if (height > 0)\r
- {\r
- source = windowofs + panadjust + 8 - 24/BYTEPIXELS;\r
- dest = bufferofs + panadjust + 8 - 24/BYTEPIXELS;\r
- if (height > 0)\r
- VW_ScreenToScreen(source, dest, 24/BYTEPIXELS, height);\r
- }\r
- }\r
- if (vislines >= 72)\r
- {\r
- VW_ClipDrawMPic((pansx+40)/BYTEPIXELS, vislines-168+pansy, CORDPICM);\r
- }\r
- VW_UpdateScreen();\r
-}\r
-\r
-/*\r
-==================\r
-=\r
-= StatusWindow\r
-=\r
-==================\r
-*/\r
-\r
-void StatusWindow(void)\r
-{\r
-#if GRMODE == CGAGR\r
-\r
- if (Keyboard[sc_A] && Keyboard[sc_2])\r
- {\r
- US_CenterWindow(20, 2);\r
- PrintY += 2;\r
- US_Print("Debug keys active");\r
- VW_UpdateScreen();\r
- IN_Ack();\r
- debugok = true;\r
- }\r
-\r
- WindowX = 0;\r
- WindowW = 320;\r
- WindowY = 0;\r
- WindowH = 200;\r
- DrawStatusWindow();\r
- VW_UpdateScreen();\r
- IN_ClearKeysDown();\r
- IN_Ack();\r
-\r
-#else\r
-\r
- Uint16 oldbufferofs;\r
-\r
- WindowX = 0;\r
- WindowW = 320;\r
- WindowY = 0;\r
- WindowH = 200;\r
-\r
- if (Keyboard[sc_A] && Keyboard[sc_2])\r
- {\r
- US_CenterWindow(20, 2);\r
- PrintY += 2;\r
- US_Print("Debug keys active");\r
- VW_UpdateScreen();\r
- IN_Ack();\r
- debugok = true;\r
- }\r
-\r
- RF_Refresh();\r
- RFL_InitAnimList();\r
- oldbufferofs = bufferofs;\r
- bufferofs = windowofs = RF_FindFreeBuffer();\r
- VW_ScreenToScreen(displayofs, displayofs, 44, 224); // useless (source and dest offsets are identical)\r
- VW_ScreenToScreen(displayofs, masterofs, 44, 224);\r
- VW_ScreenToScreen(displayofs, bufferofs, 44, 168);\r
- DrawStatusWindow();\r
- bufferofs = oldbufferofs;\r
- RF_Refresh();\r
-\r
- SD_PlaySound(SND_SHOWSTATUS);\r
- vislines = 16;\r
- scrollup = false;\r
- RF_SetRefreshHook(ScrollStatusWindow);\r
-\r
- while (true)\r
- {\r
- RF_Refresh();\r
- if (vislines == 168)\r
- break;\r
- vislines = vislines + tics*8;\r
- if (vislines > 168)\r
- vislines = 168;\r
- }\r
-\r
- RF_Refresh();\r
- RF_SetRefreshHook(NULL);\r
- IN_ClearKeysDown();\r
- IN_Ack();\r
-\r
- SD_PlaySound(SND_HIDESTATUS);\r
- vislines -= 16;\r
- scrollup = true;\r
- RF_SetRefreshHook(ScrollStatusWindow);\r
-\r
- while (true)\r
- {\r
- RF_Refresh();\r
- if (vislines == 0)\r
- break;\r
- vislines = vislines - tics*8;\r
- if (vislines < 0)\r
- vislines = 0;\r
- }\r
-\r
- RF_SetRefreshHook(NULL);\r
-\r
- scoreobj->x = 0; //force scorebox to redraw?\r
-\r
-#endif\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-==================\r
-=\r
-= CenterActor\r
-=\r
-==================\r
-*/\r
-\r
-void CenterActor(objtype *ob)\r
-{\r
- Uint16 orgx, orgy;\r
-\r
- centerlevel = 140;\r
- if (ob->x < 152*PIXGLOBAL)\r
- {\r
- orgx = 0;\r
- }\r
- else\r
- {\r
- orgx = ob->x - 152*PIXGLOBAL;\r
- }\r
- if (mapon == 0)\r
- {\r
- if (ob->y < 80*PIXGLOBAL)\r
- {\r
- orgy = 0;\r
- }\r
- else\r
- {\r
- orgy = ob->y - 80*PIXGLOBAL;\r
- }\r
- }\r
- else\r
- {\r
- if (ob->bottom < 140*PIXGLOBAL)\r
- {\r
- orgy = 0;\r
- }\r
- else\r
- {\r
- orgy = ob->bottom - 140*PIXGLOBAL;\r
- }\r
- }\r
- if (!scorescreenkludge)\r
- {\r
- RF_NewPosition(orgx, orgy);\r
- }\r
-\r
-//\r
-// update limits for onscreen and inactivate checks\r
-//\r
- originxtilemax = (originxtile + PORTTILESWIDE) - 1;\r
- originytilemax = (originytile + PORTTILESHIGH) - 1;\r
- inactivateleft = originxtile - INACTIVATEDIST;\r
- if (inactivateleft < 0)\r
- {\r
- inactivateleft = 0;\r
- }\r
- inactivateright = originxtilemax + INACTIVATEDIST;\r
- if (inactivateright < 0)\r
- {\r
- inactivateright = 0;\r
- }\r
- inactivatetop = originytile - INACTIVATEDIST;\r
- if (inactivatetop < 0)\r
- {\r
- inactivatetop = 0;\r
- }\r
- inactivatebottom = originytilemax + INACTIVATEDIST;\r
- if (inactivatebottom < 0)\r
- {\r
- inactivatebottom = 0;\r
- }\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-==================\r
-=\r
-= WorldScrollScreen\r
-=\r
-= Scroll if Keen is nearing an edge\r
-=\r
-==================\r
-*/\r
-\r
-void WorldScrollScreen(objtype *ob)\r
-{\r
- Sint16 xscroll, yscroll;\r
-\r
- if (keenkilled)\r
- return;\r
-\r
- if (ob->left < originxglobal + 9*TILEGLOBAL)\r
- {\r
- xscroll = ob->left - (originxglobal + 9*TILEGLOBAL);\r
- }\r
- else if (ob->right > originxglobal + 12*TILEGLOBAL)\r
- {\r
- xscroll = ob->right + 16 - (originxglobal + 12*TILEGLOBAL);\r
- }\r
- else\r
- {\r
- xscroll = 0;\r
- }\r
-\r
- if (ob->top < originyglobal + 5*TILEGLOBAL)\r
- {\r
- yscroll = ob->top - (originyglobal + 5*TILEGLOBAL);\r
- }\r
- else if (ob->bottom > originyglobal + 7*TILEGLOBAL)\r
- {\r
- yscroll = ob->bottom - (originyglobal + 7*TILEGLOBAL);\r
- }\r
- else\r
- {\r
- yscroll = 0;\r
- }\r
-\r
- if (!xscroll && !yscroll)\r
- return;\r
-\r
-//\r
-// don't scroll more than one tile per frame\r
-//\r
- if (xscroll >= 0x100)\r
- {\r
- xscroll = 0xFF;\r
- }\r
- else if (xscroll <= -0x100)\r
- {\r
- xscroll = -0xFF;\r
- }\r
- if (yscroll >= 0x100)\r
- {\r
- yscroll = 0xFF;\r
- }\r
- else if (yscroll <= -0x100)\r
- {\r
- yscroll = -0xFF;\r
- }\r
-\r
- RF_Scroll(xscroll, yscroll);\r
-\r
-//\r
-// update limits for onscreen and inactivate checks\r
-//\r
- originxtilemax = (originxtile + PORTTILESWIDE) - 1;\r
- originytilemax = (originytile + PORTTILESHIGH) - 1;\r
- inactivateleft = originxtile - INACTIVATEDIST;\r
- if (inactivateleft < 0)\r
- {\r
- inactivateleft = 0;\r
- }\r
- inactivateright = originxtilemax + INACTIVATEDIST;\r
- if (inactivateright < 0)\r
- {\r
- inactivateright = 0;\r
- }\r
- inactivatetop = originytile - INACTIVATEDIST;\r
- if (inactivatetop < 0)\r
- {\r
- inactivatetop = 0;\r
- }\r
- inactivatebottom = originytilemax + INACTIVATEDIST;\r
- if (inactivatebottom < 0)\r
- {\r
- inactivatebottom = 0;\r
- }\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-==================\r
-=\r
-= ScrollScreen\r
-=\r
-= Scroll if Keen is nearing an edge\r
-= Set playstate to ex_completes\r
-=\r
-==================\r
-*/\r
-\r
-void ScrollScreen(objtype *ob)\r
-{\r
- Sint16 xscroll, yscroll, pix, speed;\r
- Uint16 bottom;\r
-\r
- if (keenkilled)\r
- return;\r
-\r
-//\r
-// walked off edge of map?\r
-//\r
- if (ob->left < originxmin || ob->right > originxmax + 320*PIXGLOBAL)\r
- {\r
- playstate = ex_completed;\r
- return;\r
- }\r
-\r
-//\r
-// fallen off bottom of world?\r
-//\r
- if (ob->bottom > originymax + 13*TILEGLOBAL)\r
- {\r
- ob->y -= ob->bottom - (originymax + 13*TILEGLOBAL);\r
- SD_PlaySound(SND_PLUMMET);\r
- godmode = false;\r
- KillKeen();\r
- return;\r
- }\r
-\r
- xscroll=yscroll=0;\r
-\r
- if (ob->x < originxglobal + 9*TILEGLOBAL)\r
- {\r
- xscroll = ob->x - (originxglobal + 9*TILEGLOBAL);\r
- }\r
- else if (ob->x > originxglobal + 12*TILEGLOBAL)\r
- {\r
- xscroll = ob->x - (originxglobal + 12*TILEGLOBAL);\r
- }\r
-\r
- if (ob->state == &s_keenlookup2)\r
- {\r
- if (centerlevel+tics > 167)\r
- {\r
- pix = 167-centerlevel;\r
- }\r
- else\r
- {\r
- pix = tics;\r
- }\r
- centerlevel += pix;\r
- yscroll = CONVERT_PIXEL_TO_GLOBAL(-pix);\r
- }\r
- else if (ob->state == &s_keenlookdown3)\r
- {\r
- if (centerlevel-tics < 33)\r
- {\r
- pix = centerlevel + -33;\r
- }\r
- else\r
- {\r
- pix = tics;\r
- }\r
- centerlevel -= pix;\r
- yscroll = CONVERT_PIXEL_TO_GLOBAL(pix);\r
- }\r
-\r
-#ifdef KEEN6\r
- if (groundslam)\r
- {\r
- static Sint16 shaketable[] = {0,\r
- -64, -64, -64, 64, 64, 64,\r
- -200, -200, -200, 200, 200, 200,\r
- -250, -250, -250, 250, 250, 250,\r
- -250, -250, -250, 250, 250, 250\r
- };\r
- yscroll = yscroll + (bottom - (ob->bottom + shaketable[groundslam])); // BUG: 'bottom' has not been initialized yet!\r
- }\r
- else\r
-#endif\r
- if ( (ob->hitnorth || !ob->needtoclip || ob->state == &s_keenholdon))\r
- {\r
- if ( ob->state != &s_keenclimbup\r
- && ob->state != &s_keenclimbup2\r
- && ob->state != &s_keenclimbup3\r
- && ob->state != &s_keenclimbup4)\r
- {\r
- yscroll += ob->ymove;\r
- bottom = originyglobal + yscroll + CONVERT_PIXEL_TO_GLOBAL(centerlevel);\r
- if (ob->bottom == bottom)\r
- {\r
- // player didn't move, no additional scrolling\r
- }\r
- else\r
- {\r
- if (ob->bottom < bottom)\r
- {\r
- pix = bottom - ob->bottom;\r
- }\r
- else\r
- {\r
- pix = ob->bottom - bottom;\r
- }\r
- speed = CONVERT_PIXEL_TO_GLOBAL(pix) >> 7;\r
- if (speed > 0x30)\r
- {\r
- speed = 0x30;\r
- }\r
- speed *= tics;\r
- if (speed < 0x10)\r
- {\r
- if (pix < 0x10)\r
- {\r
- speed = pix;\r
- }\r
- else\r
- {\r
- speed = 0x10;\r
- }\r
- }\r
- if (ob->bottom < bottom)\r
- {\r
- yscroll -= speed;\r
- }\r
- else\r
- {\r
- yscroll += speed;\r
- }\r
- }\r
- }\r
- }\r
- else\r
- {\r
- centerlevel = 140;\r
- }\r
-\r
- pix = (ob->bottom-32*PIXGLOBAL)-(originyglobal+yscroll);\r
- if (pix < 0)\r
- {\r
- yscroll += pix;\r
- }\r
- pix = (ob->bottom+32*PIXGLOBAL)-(originyglobal+yscroll+200*PIXGLOBAL);\r
- if (pix > 0)\r
- {\r
- yscroll += pix;\r
- }\r
-\r
- if (xscroll == 0 && yscroll == 0)\r
- return;\r
-\r
-//\r
-// don't scroll more than one tile per frame\r
-//\r
- if (xscroll >= 0x100)\r
- {\r
- xscroll = 0xFF;\r
- }\r
- else if (xscroll <= -0x100)\r
- {\r
- xscroll = -0xFF;\r
- }\r
- if (yscroll >= 0x100)\r
- {\r
- yscroll = 0xFF;\r
- }\r
- else if (yscroll <= -0x100)\r
- {\r
- yscroll = -0xFF;\r
- }\r
- RF_Scroll(xscroll, yscroll);\r
-\r
-//\r
-// update limits for onscreen and inactivate checks\r
-//\r
- originxtilemax = (originxtile + PORTTILESWIDE) - 1;\r
- originytilemax = (originytile + PORTTILESHIGH) - 1;\r
- inactivateleft = originxtile - INACTIVATEDIST;\r
- if (inactivateleft < 0)\r
- {\r
- inactivateleft = 0;\r
- }\r
- inactivateright = originxtilemax + INACTIVATEDIST;\r
- if (inactivateright < 0)\r
- {\r
- inactivateright = 0;\r
- }\r
- inactivatetop = originytile - INACTIVATEDIST;\r
- if (inactivatetop < 0)\r
- {\r
- inactivatetop = 0;\r
- }\r
- inactivatebottom = originytilemax + INACTIVATEDIST;\r
- if (inactivatebottom < 0)\r
- {\r
- inactivatebottom = 0;\r
- }\r
-}\r
-\r
-//===========================================================================\r
-\r
-\r
-/*\r
-#############################################################################\r
-\r
- The objarray data structure\r
-\r
-#############################################################################\r
-\r
-Objarray contains structures for every actor currently playing. The structure\r
-is accessed as a linked list starting at *player, ending when ob->next ==\r
-NULL. GetNewObj inserts a new object at the end of the list, meaning that\r
-if an actor spawns another actor, the new one WILL get to think and react the\r
-same frame. RemoveObj unlinks the given object and returns it to the free\r
-list, but does not damage the objects ->next pointer, so if the current object\r
-removes itself, a linked list following loop can still safely get to the\r
-next element.\r
-\r
-<backwardly linked free list>\r
-\r
-#############################################################################\r
-*/\r
-\r
-\r
-/*\r
-=========================\r
-=\r
-= InitObjArray\r
-=\r
-= Call to clear out the entire object list, returning them all to the free\r
-= list. Allocates a special spot for the player.\r
-=\r
-=========================\r
-*/\r
-\r
-void InitObjArray(void)\r
-{\r
- Sint16 i;\r
-\r
- for (i=0; i<MAXACTORS; i++)\r
- {\r
- objarray[i].prev = &objarray[i+1];\r
- objarray[i].next = NULL;\r
- }\r
-\r
- objarray[MAXACTORS-1].prev = NULL;\r
-\r
- objfreelist = &objarray[0];\r
- lastobj = NULL;\r
-\r
- objectcount = 0;\r
-\r
-//\r
-// give the player and score the first free spots\r
-//\r
- GetNewObj(false);\r
- player = new;\r
- GetNewObj(false);\r
- scoreobj = new;\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=========================\r
-=\r
-= GetNewObj\r
-=\r
-= Sets the global variable new to point to a free spot in objarray.\r
-= The free spot is inserted at the end of the liked list\r
-=\r
-= When the object list is full, the caller can either have it bomb out or\r
-= return a dummy object pointer that will never get used\r
-=\r
-= Returns -1 when list was full, otherwise returns 0.\r
-=\r
-=========================\r
-*/\r
-\r
-Sint16 GetNewObj(boolean usedummy)\r
-{\r
- if (!objfreelist)\r
- {\r
- if (usedummy)\r
- {\r
- new = &dummyobj;\r
- return -1;\r
- }\r
- Quit("GetNewObj: No free spots in objarray!");\r
- }\r
- new = objfreelist;\r
- objfreelist = new->prev;\r
- memset(new, 0, sizeof(*new));\r
- if (lastobj)\r
- {\r
- lastobj->next = new;\r
- }\r
- new->prev = lastobj; // new->next is allready NULL from memset\r
-\r
- new->active = ac_yes;\r
- new->needtoclip = cl_midclip;\r
- lastobj = new;\r
-\r
- objectcount++;\r
- return 0;\r
-}\r
-\r
-//===========================================================================\r
-\r
-/*\r
-=========================\r
-=\r
-= RemoveObj\r
-=\r
-= Add the given object back into the free list, and unlink it from it's\r
-= neighbors\r
-=\r
-=========================\r
-*/\r
-\r
-void RemoveObj(objtype *ob)\r
-{\r
- if (ob == player)\r
- Quit("RemoveObj: Tried to remove the player!");\r
-\r
-//\r
-// erase it from the refresh manager\r
-//\r
- RF_RemoveSprite(&ob->sprite);\r
- if (ob->obclass == stunnedobj)\r
- {\r
- RF_RemoveSprite((void **)&ob->temp3);\r
- }\r
-\r
-//\r
-// fix the next object's back link\r
-//\r
- if (ob == lastobj)\r
- {\r
- lastobj = ob->prev;\r
- }\r
- else\r
- {\r
- ob->next->prev = ob->prev;\r
- }\r
-\r
-//\r
-// fix the previous object's forward link\r
-//\r
- ob->prev->next = ob->next;\r
-\r
-//\r
-// add it back in to the free list\r
-//\r
- ob->prev = objfreelist;\r
- objfreelist = ob;\r
-}\r
-\r
-//==========================================================================\r
-\r
-/*\r
-====================\r
-=\r
-= GivePoints\r
-=\r
-= Grants extra men at 20k,40k,80k,160k,320k\r
-=\r
-====================\r
-*/\r
-\r
-void GivePoints(Uint16 points)\r
-{\r
- gamestate.score += points;\r
- if (!DemoMode && gamestate.score >= gamestate.nextextra)\r
- {\r
- SD_PlaySound(SND_EXTRAKEEN);\r
- gamestate.lives++;\r
- gamestate.nextextra *= 2;\r
- }\r
-}\r
-\r
-//==========================================================================\r
-\r
-/*\r
-===================\r
-=\r
-= PollControls\r
-=\r
-===================\r
-*/\r
-\r
-void PollControls(void)\r
-{\r
- IN_ReadControl(0, &c);\r
- if (c.yaxis != -1)\r
- upheld = false;\r
-\r
- if (GravisGamepad && !DemoMode)\r
- {\r
- jumpbutton = GravisAction[ga_Jump];\r
- pogobutton = GravisAction[ga_Pogo];\r
- firebutton = GravisAction[ga_Fire];\r
- if (!jumpbutton)\r
- jumpheld = false;\r
- if (!pogobutton)\r
- pogoheld = false;\r
- if (!firebutton)\r
- fireheld = false;\r
- }\r
- else if (oldshooting || DemoMode)\r
- {\r
- if (c.button0 && c.button1)\r
- {\r
- firebutton = true;\r
- jumpbutton = pogobutton = jumpheld = pogoheld = false;\r
- }\r
- else\r
- {\r
- firebutton = fireheld = false;\r
- if (c.button0)\r
- {\r
- jumpbutton = true;\r
- }\r
- else\r
- {\r
- jumpbutton = jumpheld = false;\r
- }\r
- if (c.button1)\r
- {\r
- if (oldfirecount <= 8)\r
- {\r
- oldfirecount = oldfirecount + tics;\r
- }\r
- else\r
- {\r
- pogobutton = true;\r
- }\r
- }\r
- else\r
- {\r
- if (oldfirecount != 0)\r
- {\r
- pogobutton = true;\r
- }\r
- else\r
- {\r
- pogobutton = pogoheld = false;\r
- }\r
- oldfirecount = 0;\r
- }\r
- }\r
- }\r
- else\r
- {\r
- jumpbutton = c.button0;\r
- pogobutton = c.button1;\r
- firebutton = Keyboard[firescan];\r
- if (!jumpbutton)\r
- jumpheld = false;\r
- if (!pogobutton)\r
- pogoheld = false;\r
- if (!firebutton)\r
- fireheld = false;\r
- }\r
-}\r
-\r
-//==========================================================================\r
-\r
-\r
-/*\r
-=================\r
-=\r
-= StopMusic\r
-=\r
-=================\r
-*/\r
-\r
-void StopMusic(void)\r
-{\r
- Sint16 i;\r
-\r
- SD_MusicOff();\r
- for (i=0; i<LASTMUSIC; i++)\r
- {\r
- if (audiosegs[STARTMUSIC+i])\r
- {\r
-#ifdef FIX_MUSIC_MEMORY_ISSUES\r
- //unlock any music blocks so that they can be purged\r
- MM_SetLock(&(memptr)audiosegs[STARTMUSIC+i], false);\r
-#endif\r
- MM_SetPurge(&(memptr)audiosegs[STARTMUSIC+i], PURGE_FIRST);\r
- }\r
- }\r
-}\r
-\r
-//==========================================================================\r
-\r
-/*\r
-=================\r
-=\r
-= StartMusic\r
-=\r
-=================\r
-*/\r
-\r
-void StartMusic(Uint16 num)\r
-{\r
- static Sint16 songs[] =\r
- {\r
-#if defined KEEN4\r
- SHADOWS_MUS,\r
- KICKPANT_MUS,\r
- OASIS_MUS,\r
- OASIS_MUS,\r
- TOOHOT_MUS,\r
- TOOHOT_MUS,\r
- KICKPANT_MUS,\r
- OASIS_MUS,\r
- VEGGIES_MUS,\r
- VEGGIES_MUS,\r
- VEGGIES_MUS,\r
- TOOHOT_MUS,\r
- TOOHOT_MUS,\r
- TOOHOT_MUS,\r
- TOOHOT_MUS,\r
- TOOHOT_MUS,\r
- TOOHOT_MUS,\r
- VEGGIES_MUS,\r
- OASIS_MUS,\r
- -1\r
-#elif defined KEEN5\r
- ROBOROCK_MUS,\r
- WEDNESDY_MUS,\r
- BREATHE_MUS,\r
- SPHEREFUL_MUS,\r
- TIGHTER_MUS,\r
- SPHEREFUL_MUS,\r
- TIGHTER_MUS,\r
- SPHEREFUL_MUS,\r
- TIGHTER_MUS,\r
- SPHEREFUL_MUS,\r
- TIGHTER_MUS,\r
- SNOOPING_MUS,\r
- FEARSOME_MUS,\r
- BAGPIPES_MUS,\r
- FANFARE_MUS,\r
- SKATING_MUS,\r
- ROCK_ME_MUS,\r
- HAVING_T_MUS,\r
- CAMEIN_MUS,\r
- SHIKAIRE_MUS,\r
-#elif defined KEEN6\r
- ALIENATE_MUS,\r
- FASTER_MUS,\r
- BRERTAR_MUS,\r
- MAMSNAKE_MUS,\r
- MAMSNAKE_MUS,\r
- MAMSNAKE_MUS,\r
- METAL_MUS,\r
- TOFUTURE_MUS,\r
- METAL_MUS,\r
- BRERTAR_MUS,\r
- FASTER_MUS,\r
- TOFUTURE_MUS,\r
- BRERTAR_MUS,\r
- SPACFUNK_MUS,\r
- SPACFUNK_MUS,\r
- OMINOUS_MUS,\r
- TOFUTURE_MUS,\r
- WONDER_MUS,\r
- WONDER_MUS,\r
- WONDER_MUS\r
-#endif\r
- };\r
-\r
- Sint16 song;\r
- boolean wasfaded;\r
-\r
- if (num >= ARRAYLENGTH(songs) && num != 0xFFFF)\r
- {\r
- Quit("StartMusic() - bad level number");\r
- }\r
-\r
-#ifdef FIX_MUSIC_MEMORY_ISSUES\r
- StopMusic();\r
-#else\r
- SD_MusicOff();\r
-#endif\r
-\r
-#ifdef KEEN4\r
- if (num == 0xFFFF)\r
- {\r
- song = WONDER_MUS;\r
- }\r
- else\r
- {\r
- song = songs[num];\r
- }\r
-#else\r
- song = songs[num];\r
-#endif\r
-\r
- if (song == -1 || MusicMode != smm_AdLib)\r
- {\r
- return;\r
- }\r
-\r
- MM_BombOnError(false);\r
- CA_CacheAudioChunk(STARTMUSIC+song);\r
- MM_BombOnError(true);\r
- if (mmerror)\r
- {\r
- mmerror = false;\r
- if (!DemoMode)\r
- {\r
- US_CenterWindow(20, 8);\r
- PrintY += 20;\r
- US_CPrint("Insufficient memory\nfor background music!");\r
- VW_UpdateScreen();\r
- wasfaded = screenfaded;\r
- if (wasfaded)\r
- {\r
- VW_SetDefaultColors();\r
- }\r
- IN_ClearKeysDown();\r
- IN_UserInput(3*TickBase, false);\r
- if (wasfaded)\r
- {\r
- VW_FadeOut();\r
- }\r
- }\r
- }\r
- else\r
- {\r
-#ifdef FIX_MUSIC_MEMORY_ISSUES\r
- //The current music should be locked, so the memory manager will not\r
- //mess with it when compressing memory blocks in MM_SortMem().\r
- MM_SetLock(&(memptr)audiosegs[STARTMUSIC+song], true);\r
-#endif\r
- SD_StartMusic((MusicGroup far *)audiosegs[STARTMUSIC+song]);\r
- }\r
-}\r
-\r
-//==========================================================================\r
-\r
-\r
-/*\r
-===================\r
-=\r
-= PlayLoop\r
-=\r
-===================\r
-*/\r
-\r
-void PlayLoop(void)\r
-{\r
- objtype *check;\r
-\r
- StartMusic(gamestate.mapon);\r
- fireheld = pogoheld = upheld = jumpheld = false;\r
- ingame = true;\r
- playstate = ex_stillplaying;\r
- invincible = keenkilled = oldfirecount = 0;\r
-\r
- CenterActor(player);\r
-\r
- if (DemoMode)\r
- {\r
- US_InitRndT(false);\r
- }\r
- else\r
- {\r
- US_InitRndT(true);\r
- }\r
- TimeCount = lasttimecount = tics = 3;\r
-\r
- do\r
- {\r
- PollControls();\r
-\r
-//\r
-// go through state changes and propose movements\r
-//\r
- for (obj=player; obj; obj=obj->next)\r
- {\r
- if (!obj->active && obj->tileright >= originxtile-1\r
- && obj->tileleft <= originxtilemax+1 && obj->tiletop <= originytilemax+1\r
- && obj->tilebottom >= originytile-1)\r
- {\r
- obj->needtoreact = true;\r
- obj->active = ac_yes;\r
- }\r
- if (obj->active)\r
- {\r
- if (obj->tileright < inactivateleft\r
- || obj->tileleft > inactivateright\r
- || obj->tiletop > inactivatebottom\r
- || obj->tilebottom < inactivatetop)\r
- {\r
- if (obj->active == ac_removable)\r
- {\r
- RemoveObj(obj);\r
- continue;\r
- }\r
- else if (obj->active != ac_allways)\r
- {\r
- if (US_RndT() < tics*2 || screenfaded || loadedgame)\r
- {\r
- RF_RemoveSprite(&obj->sprite);\r
- if (obj->obclass == stunnedobj)\r
- RF_RemoveSprite((void **)&obj->temp3);\r
- obj->active = ac_no;\r
- continue;\r
- }\r
- }\r
- }\r
- StateMachine(obj);\r
- }\r
- }\r
-\r
- if (gamestate.riding)\r
- {\r
- HandleRiding(player);\r
- }\r
-\r
-//\r
-// check for and handle collisions between objects\r
-//\r
- for (obj=player; obj; obj=obj->next)\r
- {\r
- if (obj->active)\r
- {\r
- for (check=obj->next; check; check=check->next)\r
- {\r
- if (!check->active)\r
- {\r
- continue;\r
- }\r
- if (obj->right > check->left && obj->left < check->right\r
- && obj->top < check->bottom && obj->bottom > check->top)\r
- {\r
- if (obj->state->contact)\r
- {\r
- obj->state->contact(obj, check);\r
- }\r
- if (check->state->contact)\r
- {\r
- check->state->contact(check, obj);\r
- }\r
- if (obj->obclass == nothing) //useless -- obclass is NOT set to nothing by RemoveObj\r
- {\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- }\r
-\r
-//\r
-// check intiles\r
-//\r
- if (mapon != 0)\r
- {\r
- CheckInTiles(player);\r
- }\r
- else\r
- {\r
- CheckWorldInTiles(player);\r
- }\r
-\r
-//\r
-// react to whatever happened, and post sprites to the refresh manager\r
-//\r
- for (obj=player; obj; obj=obj->next)\r
- {\r
- if (!obj->active)\r
- {\r
- continue;\r
- }\r
- if (obj->tilebottom >= mapheight-1)\r
- {\r
- if (obj->obclass == keenobj)\r
- {\r
- playstate = ex_died;\r
- }\r
- else\r
- {\r
- RemoveObj(obj);\r
- }\r
- continue;\r
- }\r
- if (obj->needtoreact && obj->state->react)\r
- {\r
- obj->needtoreact = false;\r
- obj->state->react(obj);\r
- }\r
- }\r
-\r
-//\r
-// scroll the screen and update the score box\r
-//\r
-#ifdef KEEN4\r
- if (mapon != 0 && mapon != 17)\r
-#else\r
- if (mapon != 0)\r
-#endif\r
- {\r
- ScrollScreen(player);\r
- }\r
- else\r
- {\r
- WorldScrollScreen(player);\r
- }\r
- UpdateScore(scoreobj);\r
- if (loadedgame)\r
- {\r
- loadedgame = false;\r
- }\r
-\r
-//\r
-// update the screen and calculate the number of tics it took to execute\r
-// this cycle of events (for adaptive timing of next cycle)\r
-//\r
- RF_Refresh();\r
-\r
- if (invincible)\r
- {\r
- if ((invincible = invincible - tics) < 0)\r
- invincible = 0;\r
- }\r
-\r
-#ifdef KEEN6\r
- if (groundslam)\r
- {\r
- if ((groundslam = groundslam - tics) < 0)\r
- groundslam = 0;\r
- }\r
-#endif\r
-//\r
-// single step debug mode\r
-//\r
- if (singlestep)\r
- {\r
- VW_WaitVBL(14); //reduces framerate to 5 fps on VGA or 4.3 fps on EGA cards\r
- lasttimecount = TimeCount;\r
- }\r
-//\r
-// extra VBLs debug mode\r
-//\r
- if (extravbls)\r
- {\r
- VW_WaitVBL(extravbls);\r
- }\r
-\r
-//\r
-// handle user inputs\r
-//\r
- if (DemoMode == demo_Playback)\r
- {\r
- if (!screenfaded && IN_IsUserInput())\r
- {\r
- playstate = ex_completed;\r
- if (LastScan != sc_F1)\r
- {\r
- LastScan = sc_Space;\r
- }\r
- }\r
- }\r
- else if (DemoMode == demo_PlayDone)\r
- {\r
- playstate = ex_completed;\r
- }\r
- else\r
- {\r
- CheckKeys();\r
- }\r
-\r
-//\r
-// E-N-D cheat\r
-//\r
- if (Keyboard[sc_E] && Keyboard[sc_N] && Keyboard[sc_D])\r
- {\r
-#if defined KEEN4\r
- gamestate.rescued = 7;\r
- playstate = ex_rescued;\r
-#elif defined KEEN5\r
- playstate = ex_qedbroke;\r
-#elif defined KEEN6\r
- playstate = ex_molly;\r
-#endif\r
- }\r
-\r
- } while (playstate == ex_stillplaying);\r
-\r
- ingame = false;\r
- StopMusic();\r
-}
\ No newline at end of file