X-Git-Url: http://4ch.mooo.com/gitweb/?p=16.git;a=blobdiff_plain;f=16%2Fkeen456%2FKEEN4-6%2FCK_KEEN2.C;fp=16%2Fkeen456%2FKEEN4-6%2FCK_KEEN2.C;h=0000000000000000000000000000000000000000;hp=e30e5d7a85e8914c29c803e02e666b1bce76e5e2;hb=a387b1ff6f02e2da93e870a330af886d1c8233da;hpb=7d1948e210bb7b58af0a0412e71f2a0a0a2010af diff --git a/16/keen456/KEEN4-6/CK_KEEN2.C b/16/keen456/KEEN4-6/CK_KEEN2.C deleted file mode 100755 index e30e5d7a..00000000 --- a/16/keen456/KEEN4-6/CK_KEEN2.C +++ /dev/null @@ -1,1606 +0,0 @@ -/* Reconstructed Commander Keen 4-6 Source Code - * Copyright (C) 2021 K1n9_Duk3 - * - * This file is loosely based on: - * Keen Dreams Source Code - * Copyright (C) 2014 Javier M. Chavez - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/* -CK_KEEN2.C -========== - -Contains the following actor types (in this order): - -- Score Box & Demo sprites -- Keen (world map) -- Flags (world map) -- Neural Stunner Shots -- Gem Door Opener -- Card Door Opener (Keen 5 only) - -*/ - -#include "CK_DEF.H" - -Direction opposite[8] = {dir_South, dir_SouthWest, dir_West, dir_NorthWest, dir_North, dir_NorthEast, dir_East, dir_SouthEast}; - -/* -============================================================================= - - SCORE BOX ROUTINES - -============================================================================= -*/ - -statetype s_score = { 0, 0, think, false, false, 0, 0, 0, NULL, NULL, NULL, NULL}; -statetype s_demo = {DEMOPLAQUESPR, DEMOPLAQUESPR, think, false, false, 0, 0, 0, NULL, NULL, NULL, NULL}; - -/* -====================== -= -= SpawnScore -= -====================== -*/ - -void SpawnScore(void) -{ - scoreobj->obclass = inertobj; - scoreobj->priority = 3; - scoreobj->active = ac_allways; - scoreobj->needtoclip = cl_noclip; - scoreobj->temp2 = -1; - scoreobj->temp1 = -1; - scoreobj->temp3 = -1; - scoreobj->temp4 = -1; - if (scorescreenkludge) - { - scoreobj->state = &sc_deadstate; - } - else if (!DemoMode) - { - NewState(scoreobj, &s_score); - } - else - { - NewState(scoreobj, &s_demo); - CA_MarkGrChunk(DEMOPLAQUESPR); - } -} - - -// Taken from Keen Dreams: MemDrawChar and ShiftScore - -/* -====================== -= -= MemDrawChar -= -====================== -*/ - -#if GRMODE == EGAGR - -void MemDrawChar(Sint16 char8, Uint8 far *dest, Uint16 width, Uint16 planesize) -{ - Uint16 source = (Uint16)grsegs[STARTTILE8]; // Note: this differs from Keen Dreams source - -asm mov si,[char8] -asm shl si,1 -asm shl si,1 -asm shl si,1 -asm shl si,1 -asm shl si,1 // index into char 8 segment - -asm mov ds,[WORD PTR source] // Note: this differs from Keen Dreams source -asm mov es,[WORD PTR dest+2] - -asm mov cx,4 // draw four planes -asm mov bx,[width] -asm dec bx - -planeloop: - -asm mov di,[WORD PTR dest] - -asm movsb -asm add di,bx -asm movsb -asm add di,bx -asm movsb -asm add di,bx -asm movsb -asm add di,bx -asm movsb -asm add di,bx -asm movsb -asm add di,bx -asm movsb -asm add di,bx -asm movsb - -asm mov ax,[planesize] -asm add [WORD PTR dest],ax - -asm loop planeloop - -asm mov ax,ss -asm mov ds,ax -} - -#elif GRMODE == CGAGR - -void MemDrawChar (int char8,byte far *dest,unsigned width,unsigned planesize) -{ -asm mov si,[char8] -asm shl si,1 -asm shl si,1 -asm shl si,1 -asm shl si,1 // index into char 8 segment - -asm mov ds,[WORD PTR grsegs+STARTTILE8*2] -asm mov es,[WORD PTR dest+2] - -asm mov bx,[width] -asm sub bx,2 - -asm mov di,[WORD PTR dest] - -asm movsw -asm add di,bx -asm movsw -asm add di,bx -asm movsw -asm add di,bx -asm movsw -asm add di,bx -asm movsw -asm add di,bx -asm movsw -asm add di,bx -asm movsw -asm add di,bx -asm movsw - -asm mov ax,ss -asm mov ds,ax - - planesize++; // shut the compiler up -} -#endif - -/* -==================== -= -= ShiftScore -= -==================== -*/ -#if GRMODE == EGAGR -void ShiftScore (void) -{ - spritetabletype far *spr; - spritetype _seg *dest; - - spr = &spritetable[SCOREBOXSPR-STARTSPRITES]; - dest = (spritetype _seg *)grsegs[SCOREBOXSPR]; - - CAL_ShiftSprite (FP_SEG(dest),dest->sourceoffset[0], - dest->sourceoffset[1],spr->width,spr->height,2); - - CAL_ShiftSprite (FP_SEG(dest),dest->sourceoffset[0], - dest->sourceoffset[2],spr->width,spr->height,4); - - CAL_ShiftSprite (FP_SEG(dest),dest->sourceoffset[0], - dest->sourceoffset[3],spr->width,spr->height,6); -} -#endif - -/* -=============== -= -= UpdateScore -= -=============== -*/ - -void UpdateScore(objtype *ob) -{ - char str[10],*ch; - spritetype _seg *block; - Uint8 far *dest; - Uint16 i, length, width, planesize, number; - boolean changed; - - if (scorescreenkludge) - return; - - if (DemoMode) - { - DrawDemoPlaque(ob); - return; - } - - if (!showscorebox) - return; - - changed = false; - -//code below is a combination of ScoreThink and ScoreReact from Keen Dreams with minor changes - -// -// score changed -// - if ((gamestate.score>>16) != ob->temp1 - || (Uint16)gamestate.score != ob->temp2 ) - { - block = (spritetype _seg *)grsegs[SCOREBOXSPR]; - width = block->width[0]; - planesize = block->planesize[0]; - dest = (Uint8 far *)grsegs[SCOREBOXSPR]+block->sourceoffset[0] - + planesize + width*4; - - ltoa (gamestate.score,str,10); - - // erase leading spaces - length = strlen(str); - for (i=9;i>length;i--) - MemDrawChar (41,dest+=CHARWIDTH,width,planesize); - - // draw digits - ch = str; - while (*ch) - MemDrawChar (*ch++ - '0'+42,dest+=CHARWIDTH,width,planesize); - -#if GRMODE == EGAGR - ShiftScore (); -#endif - ob->needtoreact = true; - ob->temp1 = gamestate.score>>16; - ob->temp2 = gamestate.score; - - changed = true; - } - -// -// ammo changed -// - number = gamestate.ammo; - if (number != ob->temp3) - { - block = (spritetype _seg *)grsegs[SCOREBOXSPR]; - width = block->width[0]; - planesize = block->planesize[0]; - dest = (byte far *)grsegs[SCOREBOXSPR]+block->sourceoffset[0] - + planesize + width*20 + 7*CHARWIDTH; - - if (number > 99) - strcpy (str,"99"); - else - ltoa (number,str,10); - - // erase leading spaces - length = strlen(str); - for (i=2;i>length;i--) - MemDrawChar (41,dest+=CHARWIDTH,width,planesize); - - // draw digits - ch = str; - while (*ch) - MemDrawChar (*ch++ - '0'+42,dest+=CHARWIDTH,width,planesize); - -#if GRMODE == EGAGR - ShiftScore (); -#endif - ob->needtoreact = true; - ob->temp3 = number; - - changed = true; - } - -// -// lives changed -// - if (gamestate.lives != ob->temp4) - { - block = (spritetype _seg *)grsegs[SCOREBOXSPR]; - width = block->width[0]; - planesize = block->planesize[0]; - dest = (byte far *)grsegs[SCOREBOXSPR]+block->sourceoffset[0] - + planesize + width*20 + 2*CHARWIDTH; - - if (gamestate.lives > 99) - strcpy (str,"99"); - else - ltoa (gamestate.lives,str,10); - - // erase leading spaces - length = strlen(str); - for (i=2;i>length;i--) - MemDrawChar (41,dest+=CHARWIDTH,width,planesize); - - // draw digits - ch = str; - while (*ch) - MemDrawChar (*ch++ - '0'+42,dest+=CHARWIDTH,width,planesize); - -#if GRMODE == EGAGR - ShiftScore (); -#endif - ob->needtoreact = true; - ob->temp4 = gamestate.lives; - - changed = true; - } - -/* -Note: ------ - -It would be more efficient to use - - if (changed) - ShiftScore(); - -here instead of the individual ShiftScore() calls above. Because if the player -gains a life by collecting points items, both the score and lives numbers need -to be updated, which means the sprite would be shifted twice. And if the player -fires a shot during the same frame, the ammo number also needs to be updated, -leading to up to three shifts in one frame. -*/ - - if (ob->x != originxglobal || ob->y != originyglobal) - { - ob->x = originxglobal; - ob->y = originyglobal; - changed = true; - } - - if (changed) -#if GRMODE == EGAGR - RF_PlaceSprite(&ob->sprite, ob->x+4*PIXGLOBAL, ob->y+4*PIXGLOBAL, SCOREBOXSPR, spritedraw, 3); -#elif GRMODE == CGAGR - RF_PlaceSprite(&ob->sprite, ob->x+8*PIXGLOBAL, ob->y+8*PIXGLOBAL, SCOREBOXSPR, spritedraw, 3); -#endif -} - -/* -=============== -= -= DrawDemoPlaque -= -=============== -*/ - -void DrawDemoPlaque(objtype *ob) -{ - if (ob->x != originxglobal || ob->y != originyglobal) - { - ob->x = originxglobal; - ob->y = originyglobal; - RF_PlaceSprite(&ob->sprite, ob->x + 160*PIXGLOBAL - 32*PIXGLOBAL, ob->y + 8*PIXGLOBAL, DEMOPLAQUESPR, spritedraw, 3); - } -} - - -/* -============================================================================= - - MINI KEEN - -player->temp1 = dir -player->temp2 = animation stage - -============================================================================= -*/ - -#ifdef KEEN4 -statetype s_keenonfoot1 = {WOLRDKEENRIDE1SPR, WOLRDKEENRIDE1SPR, stepthink, false, false, 30, 0, 0, T_FootFly, NULL, R_Draw, &s_keenonfoot2}; -statetype s_keenonfoot2 = {WOLRDKEENRIDE2SPR, WOLRDKEENRIDE2SPR, stepthink, false, false, 30, 0, 0, T_FootFly, NULL, R_Draw, &s_keenonfoot1}; -statetype s_worldswim = {0, 0, slide, true, false, 6, 16, 16, T_KeenWorldSwim, NULL, R_Draw, &s_worldswim}; -#endif - -#ifdef KEEN5 -statetype s_worldelevate = {-1, -1, think, true, false, 6, 16, 16, T_Elevate, NULL, R_Draw, NULL}; -#endif - -statetype s_worldkeen = {0, 0, stepthink, false, false, 360, 0, 0, T_KeenWorld, NULL, R_Draw, &s_worldkeenwave1}; - -statetype s_worldkeenwave1 = {WORLDKEENWAVE1SPR, WORLDKEENWAVE1SPR, stepthink, false, false, 20, 0, 0, T_KeenWorld, NULL, R_Draw, &s_worldkeenwave2}; -statetype s_worldkeenwave2 = {WORLDKEENWAVE2SPR, WORLDKEENWAVE2SPR, stepthink, false, false, 20, 0, 0, T_KeenWorld, NULL, R_Draw, &s_worldkeenwave3}; -statetype s_worldkeenwave3 = {WORLDKEENWAVE1SPR, WORLDKEENWAVE1SPR, stepthink, false, false, 20, 0, 0, T_KeenWorld, NULL, R_Draw, &s_worldkeenwave4}; -statetype s_worldkeenwave4 = {WORLDKEENWAVE2SPR, WORLDKEENWAVE2SPR, stepthink, false, false, 20, 0, 0, T_KeenWorld, NULL, R_Draw, &s_worldkeenwave5}; -statetype s_worldkeenwave5 = {WORLDKEENWAVE1SPR, WORLDKEENWAVE1SPR, stepthink, false, false, 20, 0, 0, T_KeenWorldWalk, NULL, R_Draw, &s_worldkeen}; - -statetype s_worldkeenwalk = {0, 0, slide, true, false, 4, 24, 24, T_KeenWorldWalk, NULL, R_Draw, &s_worldkeenwalk}; - -Sint16 worldshapes[8] = {WORLDKEENU1SPR-1, WORLDKEENUR1SPR-1, WORLDKEENR1SPR-1, WORLDKEENDR1SPR-1, WORLDKEEND1SPR-1, WORLDKEENDL1SPR-1, WORLDKEENL1SPR-1, WORLDKEENUL1SPR-1}; //-1 to everything because worldanims values are 1-based -Sint16 worldanims[4] = {2, 3, 1, 3}; -#ifdef KEEN4 -Sint16 swimshapes[8] = {WORLDKEENSWIMU1SPR, WORLDKEENSWIMUR1SPR, WORLDKEENSWIMR1SPR, WORLDKEENSWIMDR1SPR, WORLDKEENSWIMD1SPR, WORLDKEENSWIMDL1SPR, WORLDKEENSWIML1SPR, WORLDKEENSWIMUL1SPR}; -#endif -#ifndef KEEN6 -Sint16 tiledir[4] = {dir_South, dir_West, dir_North, dir_East}; -#endif - -/* -====================== -= -= SpawnWorldKeen -= -====================== -*/ - -void SpawnWorldKeen(Sint16 x, Sint16 y) -{ -#ifdef KEEN4 - if (playstate == ex_foot) - { - player->needtoclip = cl_noclip; - player->obclass = keenobj; - player->x = gamestate.worldx; - player->y = gamestate.worldy; - player->active = ac_allways; - player->priority = 3; - player->xdir = 0; - player->ydir = 0; - if (gamestate.worldx < 20*TILEGLOBAL) - { - player->temp1 = 280; - player->xspeed = (30*TILEGLOBAL - player->x)/280 + 1; - player->yspeed = (55*TILEGLOBAL - player->y)/280 + 1; - } - else - { - player->temp1 = 140; - player->xspeed = (Sint16)(16*TILEGLOBAL - player->x)/140 + 1; - player->yspeed = (Sint16)(47*TILEGLOBAL - player->y)/140 + 1; - } - NewState(player, &s_keenonfoot1); - return; - } -#endif - - player->obclass = keenobj; - if (gamestate.worldx == 0) - { - player->x = CONVERT_TILE_TO_GLOBAL(x); - player->y = CONVERT_TILE_TO_GLOBAL(y); - } - else - { - player->x = gamestate.worldx; - player->y = gamestate.worldy; - } - player->active = ac_allways; - player->priority = 1; - player->xdir = 0; - player->ydir = 0; - player->temp1 = dir_West; - player->temp2 = 3; - player->temp3 = 0; - player->shapenum = WORLDKEENL3SPR; - NewState(player, &s_worldkeen); -} - -#ifdef KEEN5 -/* -====================== -= -= SpawnWorldKeenPort -= -====================== -*/ - -void SpawnWorldKeenPort(Uint16 tileX, Uint16 tileY) -{ - player->obclass = keenobj; - player->x = CONVERT_TILE_TO_GLOBAL(tileX); - player->y = CONVERT_TILE_TO_GLOBAL(tileY); - player->active = ac_allways; - player->priority = 1; - player->xdir = 0; - player->ydir = 0; - player->temp1 = dir_West; - player->temp2 = 3; - player->temp3 = 0; - player->shapenum = WORLDKEENL3SPR; - NewState(player, &s_worldkeen); -} -#endif - - -/* -====================== -= -= CheckEnterLevel -= -====================== -*/ - -void CheckEnterLevel(objtype *ob) -{ - Uint16 x, y, info; - - for (y = ob->tiletop; y <= ob->tilebottom; y++) - { - for (x = ob->tileleft; x <= ob->tileright; x++) - { - info = *(mapsegs[2]+mapbwidthtable[y]/2 + x); - if (info > 0xC000 && info <= (0xC000 + 18)) - { - gamestate.worldx = ob->x; - gamestate.worldy = ob->y; - gamestate.mapon = info - 0xC000; - playstate = ex_completed; - SD_PlaySound(SND_ENTERLEVEL); - } - } - } -} - -/* -====================== -= -= T_KeenWorld -= -====================== -*/ - -void T_KeenWorld(objtype *ob) -{ - if (c.dir != dir_None) - { - ob->state = &s_worldkeenwalk; - ob->temp2 = 0; - T_KeenWorldWalk(ob); - } - if (jumpbutton || pogobutton || firebutton) - { - CheckEnterLevel(ob); - } -} - -/* -====================== -= -= T_KeenWorldWalk -= -====================== -*/ - -void T_KeenWorldWalk(objtype *ob) -{ - if (ob->temp3) - { - ob->temp3 -= 4; - if (ob->temp3 < 0) - ob->temp3 = 0; - } - else - { - ob->xdir = c.xaxis; - ob->ydir = c.yaxis; - if (pogobutton || firebutton || jumpbutton) - { - CheckEnterLevel(ob); - } - if (c.dir == dir_None) - { - ob->state = &s_worldkeen; - ob->shapenum = worldshapes[ob->temp1] + 3; - return; - } - ob->temp1 = c.dir; - } - if (++ob->temp2 == 4) - ob->temp2 = 0; - ob->shapenum = worldshapes[ob->temp1] + worldanims[ob->temp2]; - - if (ob->temp2 == 1) - { - SD_PlaySound(SND_WORLDWALK1); - } - else if (ob->temp2 == 3) - { - SD_PlaySound(SND_WORLDWALK2); - } -} - -#ifdef KEEN4 -/* -====================== -= -= T_FootFly -= -====================== -*/ - -void T_FootFly(objtype *ob) -{ - ob->temp1 = ob->temp1 - tics; - xtry = ob->xspeed * tics; - ytry = ob->yspeed * tics; - if (ob->temp1 <= 0) - { - xtry -= ob->xspeed * -ob->temp1; - ytry -= ob->yspeed * -ob->temp1; - ob->priority = 1; - ob->temp1 = dir_West; - ob->temp2 = 3; - ob->temp3 = 0; - player->xdir = 0; - player->ydir = 0; - ob->state = &s_worldkeen; - ob->shapenum = WORLDKEENL3SPR; - ob->needtoclip = cl_midclip; - } -} - -/* -====================== -= -= T_KeenWorldSwim -= -====================== -*/ - -void T_KeenWorldSwim(objtype *ob) -{ - if (ob->temp3) - { - ob->temp3 -= 6; - if (ob->temp3 < 0) - ob->temp3 = 0; - } - else - { - ob->xdir = c.xaxis; - ob->ydir = c.yaxis; - if (c.xaxis || c.yaxis) - ob->temp1 = c.dir; - } - ob->shapenum = swimshapes[ob->temp1] + ob->temp2; - if (++ob->temp2 == 2) - ob->temp2 = 0; - - if (ob->temp2 == 0) - { - SD_PlaySound(SND_SWIM1); - } - else - { - SD_PlaySound(SND_SWIM2); - } -} - -#else // NOT Keen 4 (i.e. Keen 5 & 6): - -/* -====================== -= -= Teleport -= -====================== -*/ - -void Teleport(Uint16 tileX, Uint16 tileY) -{ - Uint16 tile, globalx, globaly, duration, move; - objtype *o; - objtype *ob = player; - - // - // enter the teleporter - // - SD_PlaySound(SND_TELEPORT); - globalx = CONVERT_TILE_TO_GLOBAL(tileX); - globaly = CONVERT_TILE_TO_GLOBAL(tileY); - -#ifdef KEEN6Ev15 - // We need to make the compiler "forget" that duration starts at 0 - // to make sure the while-loop check is performed when entering the - // loop. Can't change compiler settings since we do need that loop - // optimization for the for-loop at the end of this routine. - if (true) - duration = 0; -#else - duration = 0; -#endif - - while (duration < 130) - { - RF_Refresh(); - move = tics*2; - duration += tics; - - if (ob->x == globalx && ob->y == globaly) - break; - - if (ob->y < globaly) - { - ob->y += move; - if (ob->y > globaly) - ob->y = globaly; - } - else if (ob->y > globaly) - { - ob->y -= move; - if (ob->y < globaly) - ob->y = globaly; - } - - if (ob->x < globalx) - { - ob->x += move; - if (ob->x > globalx) - ob->x = globalx; - } - else if (ob->x > globalx) - { - ob->x -= move; - if (ob->x < globalx) - ob->x = globalx; - } - - ob->shapenum = ((TimeCount >> 3) % 3) + WORLDKEENU1SPR; - RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority); - - tile = ((TimeCount >> 2) & TELEPORERTILEMASK) + TELEPORTERTILE1; - RF_MemToMap(&tile, 1, tileX, tileY, 1, 1); - } - - tile = TELEPORTERTILE2; - RF_MemToMap(&tile, 1, tileX, tileY, 1, 1); - - // - // teleport to new location - // - tile = *(mapsegs[2]+mapbwidthtable[tileY]/2 + tileX); - tileX = tile >> 8; - tileY = tile & 0x7F; // BUG? y coordinate is limited to 1..127 - ob->x = CONVERT_TILE_TO_GLOBAL(tileX); - ob->y = CONVERT_TILE_TO_GLOBAL(tileY); - ob->xdir = 0; - ob->ydir = 1; - ob->temp1 = dir_South; - NewState(ob, ob->state); - CenterActor(ob); - - // - // draw flags/signs for new location - // - for (o=player->next; o; o=o->next) - { - if (!o->active && o->obclass == flagobj - && o->tileright >= originxtile-1 && o->tileleft <= originxtilemax+1 - && o->tiletop <= originytilemax+1 && o->tilebottom >= originytile-1) - { - o->needtoreact = true; - o->active = ac_yes; - RF_PlaceSprite(&o->sprite, o->x, o->y, o->shapenum, spritedraw, o->priority); - } - } - UpdateScore(scoreobj); - RF_Refresh(); - RF_Refresh(); - - // - // leave teleporter - // - SD_PlaySound(SND_TELEPORT); - - for (duration = 0; duration < 90; ) - { - RF_Refresh(); - duration += tics; - ob->y += tics*2 + tics; - - ob->shapenum = ((TimeCount >> 3) % 3) + WORLDKEEND1SPR; - RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority); - - tile = ((TimeCount >> 2) & TELEPORERTILEMASK) + TELEPORTERTILE3; - RF_MemToMap(&tile, 1, tileX, tileY, 1, 1); - } - - tile = TELEPORTERTILE4; - RF_MemToMap(&tile, 1, tileX, tileY, 1, 1); - xtry = ytry = 0; - ClipToWalls(ob); -} - -#ifdef KEEN5 - -/* -====================== -= -= T_Elevate -= -====================== -*/ - -void T_Elevate(objtype *ob) -{ - Sint16 i, x, y, tx, ty; - Uint16 tiles[2][2]; - - ytry = ob->ydir * 64 * tics; - if (ob->x != ob->temp2) - { - xtry = ob->xdir * 12 * tics; - if ( (ob->xdir == 1 && ob->x + xtry > ob->temp2) - || (ob->xdir == -1 && ob->x + xtry < ob->temp2) ) - { - xtry = ob->temp2 - ob->x; - } - } - - // - // Keen has no sprite in this state, so we need to update the hitbox manually - // to avoid issues (the screen scrolling routines use left/right/top/bottom) - // - ob->left = ob->x + xtry; - ob->right = ob->left + (TILEGLOBAL-1); - ob->top = ob->y + ytry; - ob->bottom = ob->top + (TILEGLOBAL-1); - - if (ob->ydir == 1) - { - if (ob->y + ytry < ob->temp1) - return; - } - else - { - if (ob->y + ytry > ob->temp1) - return; - } - - // - // the invisible Keen has arrived at its destination - // - ytry = 0; - xtry = 0; - ob->x = ob->temp2; - ob->y = ob->temp1; - ob->priority = 1; - ob->temp1 = 4; - ob->temp2 = 3; - ob->temp3 = 0; - player->xdir = 0; - player->ydir = 0; - ob->state = &s_worldkeen; - ob->shapenum = WORLDKEEND3SPR; - ob->needtoclip = cl_midclip; - tx = CONVERT_GLOBAL_TO_TILE(ob->x); - ty = CONVERT_GLOBAL_TO_TILE(ob->y); - WorldScrollScreen(ob); - UpdateScore(scoreobj); - RF_Refresh(); - RF_Refresh(); - - ob->y -= TILEGLOBAL; - RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority); - - // - // open the elevator door - // - SD_PlaySound(SND_ELEVATORDOOR); - for (i=0; i<=5; i++) - { - for (y=0; y<2; y++) - { - for (x=0; x<2; x++) - { - tiles[y][x] = *(mapsegs[1]+mapbwidthtable[y]/2 + i*2 + x); - } - } - RF_MemToMap(&tiles[0][0], 1, tx, ty-2, 2, 2); - RF_Refresh(); - VW_WaitVBL(8); - } - - // - // make Keen walk out of the elevator - // - for (y=0; y<32; y++) - { - ob->y += 8; // move half a pixel every frame for 32 frames -> move down 16 pixels total - ob->shapenum = (y / 4) % 3 + WORLDKEEND1SPR; - RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority); - RF_Refresh(); - } - ob->needtoclip = cl_midclip; // redundant, but doesn't do any harm -} - -/* -====================== -= -= Elevator -= -====================== -*/ - -void Elevator(Uint16 tileX, Uint16 tileY, Sint16 dir) -{ - Uint16 info, globalx, globaly, duration, move; - Sint16 x, y, i; - Uint16 tiles[2][2]; - objtype *ob = player; - - globalx = CONVERT_TILE_TO_GLOBAL(tileX); - globaly = CONVERT_TILE_TO_GLOBAL(tileY); - - // - // make Keen walk into the elevator - // - for (duration = 0; duration < 130; ) - { - CalcBounds(ob); - WorldScrollScreen(ob); - UpdateScore(scoreobj); - RF_Refresh(); - - move = tics * 2; - duration += tics; - - if (ob->x == globalx && ob->y == globaly) - break; - - if (ob->y < globaly) - { - ob->y += move; - if (ob->y > globaly) - ob->y = globaly; - } - else if (ob->y > globaly) - { - ob->y -= move; - if (ob->y < globaly) - ob->y = globaly; - } - - if (ob->x < globalx) - { - ob->x += move; - if (ob->x > globalx) - ob->x = globalx; - } - else if (ob->x > globalx) - { - ob->x -= move; - if (ob->x < globalx) - ob->x = globalx; - } - - ob->shapenum = ((duration / 8) % 3) + WORLDKEENU1SPR; - RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority); - } - - // - // close the elevator door - // - SD_PlaySound(SND_ELEVATORDOOR); - for (i=5; i >= 0; i--) - { - for (y=0; y<2; y++) - { - for (x=0; x<2; x++) - { - tiles[y][x] = *(mapsegs[1]+mapbwidthtable[y]/2 + i*2 + x); - } - } - RF_MemToMap(&tiles[0][0], 1, tileX+dir, tileY-1, 2, 2); - RF_Refresh(); - VW_WaitVBL(8); - } - - // - // make Keen invisible (and not clipping) and send him to the destination - // - RF_RemoveSprite(&ob->sprite); - info = *(mapsegs[2] + mapbwidthtable[tileY]/2 + tileX); - ob->temp2 = CONVERT_TILE_TO_GLOBAL(info >> 8); - ob->temp1 = CONVERT_TILE_TO_GLOBAL((info & 0x7F) + 1); // BUG? y coordinate is limited to 1..127 - if (ob->temp1 < ob->y) - { - ob->ydir = -1; - } - else - { - ob->ydir = 1; - } - if (ob->temp2 < ob->x) - { - ob->xdir = -1; - } - else - { - ob->xdir = 1; - } - ob->needtoclip = cl_noclip; - ob->state = &s_worldelevate; -} - -#endif //ifdef KEEN5 - -#endif //ifdef KEEN4 ... else ... - -/* -====================== -= -= CheckWorldInTiles -= -====================== -*/ - -void CheckWorldInTiles(objtype *ob) -{ - Uint16 tx, ty, intile; - - if (ob->temp3) - return; - - tx = ob->tilemidx; - ty = CONVERT_GLOBAL_TO_TILE(ob->top + (ob->bottom-ob->top)/2); - intile = tinf[INTILE + *(mapsegs[1]+mapbwidthtable[ty]/2+tx)]; -#if defined KEEN4 - if (intile == INTILE_SHORESOUTH || intile == INTILE_SHORENORTH - || intile == INTILE_SHOREEAST || intile == INTILE_SHOREWEST) - { - if (!gamestate.wetsuit) - { - SD_PlaySound(SND_NOWAY); - CantSwim(); - RF_ForceRefresh(); - xtry = -ob->xmove; - ytry = -ob->ymove; - ob->xdir = ob->ydir = 0; - ClipToWalls(ob); - } - else - { - ob->temp1 = tiledir[intile-INTILE_SHORESOUTH]; - if (ob->state == &s_worldswim) - { - ob->temp1 = opposite[ob->temp1]; - } - switch (ob->temp1) - { - case dir_North: - ob->xdir = 0; - ob->ydir = -1; - break; - case dir_East: - ob->xdir = 1; - ob->ydir = 0; - break; - case dir_South: - ob->xdir = 0; - ob->ydir = 1; - break; - case dir_West: - ob->xdir = -1; - ob->ydir = 0; - break; - } - ob->temp2 = 0; - ob->temp3 = 18; - if (ob->state == &s_worldswim) - { - ChangeState(ob, &s_worldkeenwalk); - } - else - { - ChangeState(ob, &s_worldswim); - } - } - } -#elif defined KEEN5 - switch (intile) - { - case INTILE_TELEPORT: - Teleport(tx, ty); - break; - case INTILE_ELEVATORLEFT: - Elevator(tx, ty, 0); - break; - case INTILE_ELEVATORRIGHT: - Elevator(tx, ty, -1); - break; - } -#elif defined KEEN6 - switch (intile) - { - case INTILE_TELEPORT: - Teleport(tx, ty); - break; - } -#endif -} - -/* -============================================================================= - - FLAGS - -temp1 = x destination for the thrown flag -temp2 = y destination for the thrown flag -temp3 = amount of time passed since flag was thrown (in tics) - -============================================================================= -*/ - -statetype s_flagwave1 = {FLAGFLAP1SPR, FLAGFLAP1SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, &s_flagwave2}; -statetype s_flagwave2 = {FLAGFLAP2SPR, FLAGFLAP2SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, &s_flagwave3}; -statetype s_flagwave3 = {FLAGFLAP3SPR, FLAGFLAP3SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, &s_flagwave4}; -statetype s_flagwave4 = {FLAGFLAP4SPR, FLAGFLAP4SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, &s_flagwave1}; - -#ifndef KEEN5 -statetype s_throwflag0 = {FLAGFLIP1SPR, FLAGFLIP1SPR, think, false, false, 6, 0, 0, TossThink, NULL, R_Draw, &s_throwflag1}; -statetype s_throwflag1 = {FLAGFLIP1SPR, FLAGFLIP1SPR, stepthink, false, false, 12, 0, 0, PathThink, NULL, R_Draw, &s_throwflag2}; -statetype s_throwflag2 = {FLAGFLIP2SPR, FLAGFLIP2SPR, stepthink, false, false, 12, 0, 0, PathThink, NULL, R_Draw, &s_throwflag3}; -statetype s_throwflag3 = {FLAGFLIP3SPR, FLAGFLIP3SPR, stepthink, false, false, 12, 0, 0, PathThink, NULL, R_Draw, &s_throwflag4}; -statetype s_throwflag4 = {FLAGFLIP4SPR, FLAGFLIP4SPR, stepthink, false, false, 12, 0, 0, PathThink, NULL, R_Draw, &s_throwflag5}; -statetype s_throwflag5 = {FLAGFALL1SPR, FLAGFALL1SPR, stepthink, false, false, 12, 0, 0, PathThink, NULL, R_Draw, &s_throwflag6}; -statetype s_throwflag6 = {FLAGFALL1SPR, FLAGFALL1SPR, stepthink, true, false, 1, 0, 0, FlagAlign, NULL, R_Draw, &s_flagwave1}; -#endif - -Sint16 flagx, flagy; -Point flagpath[30]; - -/* -====================== -= -= SpawnFlag -= -====================== -*/ - -void SpawnFlag(Sint16 x, Sint16 y) -{ - GetNewObj(false); - new->needtoclip = cl_noclip; - new->priority = 3; - new->obclass = flagobj; - new->active = ac_yes; -#if defined KEEN4 - new->x = CONVERT_TILE_TO_GLOBAL(x) + 6*PIXGLOBAL; - new->y = CONVERT_TILE_TO_GLOBAL(y) + -30*PIXGLOBAL; -#elif defined KEEN5 - new->x = CONVERT_TILE_TO_GLOBAL(x) + -5*PIXGLOBAL; - new->y = CONVERT_TILE_TO_GLOBAL(y) + -30*PIXGLOBAL; -#elif defined KEEN6 - new->x = CONVERT_TILE_TO_GLOBAL(x) + 6*PIXGLOBAL; // useless! - new->y = CONVERT_TILE_TO_GLOBAL(y) + -30*PIXGLOBAL; // useless! -#if GRMODE == CGAGR - new->x = CONVERT_TILE_TO_GLOBAL(x) + 10*PIXGLOBAL; -#else - new->x = CONVERT_TILE_TO_GLOBAL(x) + 14*PIXGLOBAL; -#endif - new->y = CONVERT_TILE_TO_GLOBAL(y) + -26*PIXGLOBAL; - { - Uint16 tile = *(mapsegs[1]+mapbwidthtable[y]/2 + x) + 1; - RF_MemToMap(&tile, 1, x, y, 1, 1); - } -#endif - new->ticcount = US_RndT() / 16; - NewState(new, &s_flagwave1); -} - -#ifndef KEEN5 -/* -====================== -= -= SpawnThrowFlag -= -====================== -*/ - -void SpawnThrowFlag(Sint16 x, Sint16 y) -{ - Sint16 i; - Sint32 xdist, ydist; - - GetNewObj(false); - new->needtoclip = cl_noclip; - new->priority = 3; - new->obclass = flagobj; - new->active = ac_allways; - new->x = gamestate.worldx - 16*PIXGLOBAL; - new->y = gamestate.worldy - 16*PIXGLOBAL; -#if defined KEEN4 - new->temp1 = CONVERT_TILE_TO_GLOBAL(x) + 6*PIXGLOBAL; - new->temp2 = CONVERT_TILE_TO_GLOBAL(y) + -38*PIXGLOBAL; -#elif defined KEEN6 - flagx = x; - flagy = y; -#if GRMODE == CGAGR - new->temp1 = CONVERT_TILE_TO_GLOBAL(x) + 10*PIXGLOBAL; -#else - new->temp1 = CONVERT_TILE_TO_GLOBAL(x) + 14*PIXGLOBAL; -#endif - new->temp2 = CONVERT_TILE_TO_GLOBAL(y) + -34*PIXGLOBAL; -#endif - xdist = (Sint32)new->temp1 - (Sint32)new->x; - ydist = (Sint32)new->temp2 - (Sint32)new->y; - for (i = 0; i < 30; i++) - { - flagpath[i].x = new->x + (xdist * min(i, 24))/24; - flagpath[i].y = new->y + (ydist * i)/30; - if (i < 10) - { - flagpath[i].y -= i*3*PIXGLOBAL; - } - else if (i < 15) - { - flagpath[i].y -= i*PIXGLOBAL + 20*PIXGLOBAL; - } - else if (i < 20) - { - flagpath[i].y -= (20-i)*PIXGLOBAL + 30*PIXGLOBAL; - } - else - { - flagpath[i].y -= (29-i)*3*PIXGLOBAL; - } - } - NewState(new, &s_throwflag0); -} - -/* -====================== -= -= TossThink -= -====================== -*/ - -void TossThink(objtype *ob) -{ - if (screenfaded) - return; - - SD_StopSound(); - SD_PlaySound(SND_FLAGSPIN); - ob->state = ob->state->nextstate; -} - -/* -====================== -= -= PathThink -= -====================== -*/ - -void PathThink(objtype *ob) -{ - ob->temp3 = ob->temp3 + tics; - if (ob->temp3 > 58) - ob->temp3 = 58; - - ob->x = flagpath[ob->temp3/2].x; - ob->y = flagpath[ob->temp3/2].y; - ob->needtoreact = true; - if (ob->temp1 == 0) - { - SD_PlaySound(SND_FLAGSPIN); - } -} - -/* -====================== -= -= FlagAlign -= -====================== -*/ - -void FlagAlign(objtype *ob) -{ - ob->x = ob->temp1; - ob->y = ob->temp2 + 8*PIXGLOBAL; - SD_PlaySound(SND_FLAGLAND); -#ifdef KEEN6 - { - Uint16 tile = *(mapsegs[1]+mapbwidthtable[flagy]/2 + flagx) + 1; - RF_MemToMap(&tile, 1, flagx, flagy, 1, 1); - } -#endif -} -#endif - -/* -============================================================================= - - NEURAL STUNNER - -============================================================================= -*/ -statetype s_stunray1 = {STUN1SPR, STUN1SPR, slide, false, false, 6, 64, 64, T_Shot, NULL, R_Shot, &s_stunray2}; -statetype s_stunray2 = {STUN2SPR, STUN2SPR, slide, false, false, 6, 64, 64, T_Shot, NULL, R_Shot, &s_stunray3}; -statetype s_stunray3 = {STUN3SPR, STUN3SPR, slide, false, false, 6, 64, 64, T_Shot, NULL, R_Shot, &s_stunray4}; -statetype s_stunray4 = {STUN4SPR, STUN4SPR, slide, false, false, 6, 64, 64, T_Shot, NULL, R_Shot, &s_stunray1}; - -statetype s_stunhit = {STUNHIT1SPR, STUNHIT1SPR, step, false, false, 12, 0, 0, NULL, NULL, R_Draw, &s_stunhit2}; -statetype s_stunhit2 = {STUNHIT2SPR, STUNHIT2SPR, step, false, false, 12, 0, 0, NULL, NULL, R_Draw, NULL}; - -/* -====================== -= -= SpawnShot -= -====================== -*/ - -void SpawnShot(Uint16 x, Uint16 y, Direction dir) -{ - if (!gamestate.ammo) - { - SD_PlaySound(SND_USESWITCH); - return; - } - - gamestate.ammo--; - GetNewObj(true); - new->x = x; - new->y = y; - new->priority = 0; - new->obclass = stunshotobj; - new->active = ac_allways; - SD_PlaySound(SND_KEENFIRE); - switch (dir) - { - case dir_North: - new->xdir = 0; - new->ydir = -1; - break; - case dir_East: - new->xdir = 1; - new->ydir = 0; - break; - case dir_South: - new->xdir = 0; - new->ydir = 1; - break; - case dir_West: - new->xdir = -1; - new->ydir = 0; - break; - default: - Quit("SpawnShot: Bad dir!"); - break; - } - NewState(new, &s_stunray1); - -#ifdef KEEN6 - { - objtype *ob; - - for (ob=player->next; ob; ob=ob->next) - { - if (ob->active - && new->right > ob->left && new->left < ob->right - && new->top < ob->bottom && new->bottom > ob->top - && ob->state->contact) - { - ob->state->contact(ob, new); - return; - } - } - } -#endif -} - -/* -====================== -= -= ExplodeShot -= -====================== -*/ - -void ExplodeShot(objtype *ob) -{ - ob->obclass = inertobj; - ChangeState(ob, &s_stunhit); - SD_PlaySound(SND_SHOTEXPLODE); -} - -/* -====================== -= -= T_Shot -= -====================== -*/ - -void T_Shot(objtype *ob) -{ - objtype *ob2; - - if (ob->tileright >= originxtile && ob->tilebottom >= originytile - && ob->tileleft <= originxtilemax && ob->tiletop <= originytilemax) - { - //object is visible, so do nothing - return; - } - - if (ob->tileright+10 < originxtile - || ob->tileleft-10 > originxtilemax - || ob->tilebottom+6 < originytile - || ob->tiletop-6 > originytilemax) - { - //shot is off-screen by more than half a screen, so remove it - RemoveObj(ob); - return; - } - - //check for collisions with INACTIVE objects - for (ob2 = player->next; ob2; ob2 = ob2->next) - { - if (!ob2->active && ob->right > ob2->left && ob->left < ob2->right - && ob->top < ob2->bottom && ob->bottom > ob2->top) - { - if (ob2->state->contact) - { - ob2->state->contact(ob2, ob); - ob2->needtoreact = true; - ob2->active = ac_yes; - } - - if (ob->obclass == nothing) //BUG: obclass is 'inertobj' for the exploded shot - break; - } - } -} - -/* -====================== -= -= R_Shot -= -====================== -*/ - -void R_Shot(objtype *ob) -{ - Uint16 tile; - - if (ob->hitnorth == 1 && ob->tileleft != ob->tileright) - { - tile = *(mapsegs[1]+mapbwidthtable[ob->tiletop-1]/2+ob->tileright); - if (tinf[NORTHWALL+tile] == 17) - { - ob->hitnorth = 17; - ob->x += 0x100 - (ob->x & 0xFF); - } - } - else if (ob->hitnorth == 17 && ob->tileleft != ob->tileright) - { - ob->x &= 0xFF00; - } - if (ob->hitsouth == 1 && ob->tileleft != ob->tileright) - { - tile = *(mapsegs[1]+mapbwidthtable[ob->tilebottom+1]/2+ob->tileright); - if (tinf[SOUTHWALL+tile] == 17) - { - ob->hitsouth = 17; - ob->x += 0x100 - (ob->x & 0xFF); - } - } - else if (ob->hitsouth == 17 && ob->tileleft != ob->tileright) - { - ob->x &= 0xFF00; - } - if (ob->hitnorth == 17 || ob->hitsouth == 17) - { - ytry = ob->state->ymove * tics * ob->ydir; - ob->y += ytry; - ob->top += ytry; - ob->bottom += ytry; - ob->tiletop = CONVERT_GLOBAL_TO_TILE(ob->top); - ob->tilebottom = CONVERT_GLOBAL_TO_TILE(ob->bottom); - } - else if (ob->hitnorth || ob->hitsouth || ob->hiteast || ob->hitwest) - { - ExplodeShot(ob); - } - RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority); -} - -/* -============================================================================= - - DOOR - -temp1 = height of the door's main section (identical tiles!), in tiles - DoorOpen changes two more tiles at the bottom end of the door - (total door height in tiles is temp1 + 2) - -============================================================================= -*/ - -statetype s_door1 = {0, 0, step, false, false, 10, 0, 0, DoorOpen, NULL, NULL, &s_door2}; -statetype s_door2 = {0, 0, step, false, false, 10, 0, 0, DoorOpen, NULL, NULL, &s_door3}; -statetype s_door3 = {0, 0, step, false, false, 10, 0, 0, DoorOpen, NULL, NULL, NULL}; - -/* -====================== -= -= DoorOpen -= -====================== -*/ - -void DoorOpen(objtype *ob) -{ - Sint16 i; - Uint16 far *map; - Uint16 tiles[50]; - - map = mapsegs[1] + mapbwidthtable[ob->y]/2 + ob->x; - for (i=0; i < ob->temp1+2; i++, map+=mapwidth) - { - tiles[i] = *map + 1; - } - RF_MemToMap(tiles, 1, ob->x, ob->y, 1, ob->temp1+2); -} - -#ifdef KEEN5 -/* -============================================================================= - - CARD DOOR - -temp1 = frame counter - -============================================================================= -*/ -statetype s_carddoor = {0, 0, step, false, false, 15, 0, 0, CardDoorOpen, NULL, NULL, &s_carddoor}; - -/* -====================== -= -= CardDoorOpen -= -====================== -*/ - -void CardDoorOpen(objtype *ob) -{ - Sint16 x, y; - Uint16 far *map; - Uint16 tiles[16], *tileptr; - - tileptr = tiles; - map = mapsegs[1] + mapbwidthtable[ob->y]/2 + ob->x; - for (y=0; y<4; y++, map+=mapwidth) - { - for (x=0; x<4; x++) - { - *tileptr++ = map[x]-4; - } - } - RF_MemToMap(tiles, 1, ob->x, ob->y, 4, 4); - - if (++ob->temp1 == 3) - ob->state = NULL; -} - -#endif \ No newline at end of file