Added more AI and other functions of CK 8.4

git-svn-id: https://clonekeenplus.svn.sourceforge.net/svnroot/clonekeenplus/cgenius/trunk@213 4df4b0f3-56ce-47cb-b001-ed939b7d65a6
This commit is contained in:
gerstrong
2009-08-06 19:36:58 +00:00
parent e143ccc5a3
commit 0f617cffe9
25 changed files with 1450 additions and 988 deletions

View File

@@ -1,5 +1,9 @@
Commander Genius Pre-Release v0.3 (CloneKeenPlus):
--------------------------------------------------
--------------------------------------------------
05-08-2009
- fixed crash when game in EP1 or 2 was ending
- fixed fonts problems in story section.
04-08-2009
- Fixed some minor issues with mods [Sprite Replacement] (Tulip)
- Added Ordering Info to Episode 1. Only works there!

View File

@@ -4,6 +4,6 @@
800x600x32
1024x768x32
1280x1024x32
1600x1050x32
1600x1200x32
1680x1050x32
1920x1200x32

340
src/ai/enemydata.h Normal file
View File

@@ -0,0 +1,340 @@
/*
* enemydata.h
*
* Created on: 05.08.2009
* Author: gerstrong
*/
#ifndef ENEMYDATA_H_
#define ENEMYDATA_H_
// Structs used for different enemy's variables. These are in a union.
typedef struct stYorpData
{
unsigned char state;
unsigned char looktimes,lookposition;
unsigned char timer, dietimer;
unsigned char walkframe;
unsigned int dist_traveled;
signed int yorpdie_inertia_y;
unsigned char movedir;
} stYorpData;
typedef struct stGargData
{
unsigned char state;
unsigned char looktimes,lookframe;
unsigned char timer, dietimer, keenonsameleveltimer;
unsigned char about_to_charge;
unsigned char walkframe;
unsigned int dist_traveled;
signed int gargdie_inertia_y;
unsigned char movedir;
unsigned char detectedPlayer, detectedPlayerIndex;
} stGargData;
typedef struct stVortData
{
unsigned char state;
unsigned char timer,timer2;
unsigned int animtimer;
unsigned char palflashtimer, palflashamt;
unsigned char frame;
unsigned int dist_traveled;
signed int inertiay;
char ep1style; // episode 1 style four-shots-to-kill
unsigned char movedir;
// these hold the animation frames indexes since they're
// different for each episode
int WalkLeftFrame;
int WalkRightFrame;
int LookFrame;
int JumpRightFrame;
int JumpLeftFrame;
int DyingFrame;
int DeadFrame;
} stVortData;
// Vorticon Elite = the purple guys that shoot you in ep2
typedef struct stVortEliteData
{
unsigned char state;
unsigned char timer,timer2;
unsigned int animtimer;
unsigned char frame;
signed int inertiay;
unsigned char movedir;
unsigned int timesincefire;
int dist_traveled;
} stVortEliteData;
// Butler = the little pushing robots in ep1
typedef struct stButlerData
{
unsigned char state;
unsigned char timer,animtimer;
unsigned char frame;
unsigned int dist_traveled;
unsigned char movedir;
} stButlerData;
// this same struct is used for both ep1 and ep2 "tanks", although
// they have seperate ai modules
typedef struct stTankData
{
char state;
uint timer,animtimer;
unsigned char frame;
uint dist_traveled;
unsigned char movedir;
uint ponsameleveltime;
unsigned char alreadyfiredcauseonsamelevel;
unsigned char fireafterlook;
unsigned char detectedPlayer; // 1 if player on same level
unsigned char detectedPlayerIndex; // index of player that was detected
// for tank2
uint timetillnextshot;
uint firetimes;
uint timetillcanfire;
uint timetillcanfirecauseonsamelevel;
uint turnaroundtimer;
int pausetime;
} stTankData;
// a shot from keen's raygun or an enemy that shoots rayguns
// also used for various other types of projectiles
typedef struct stRayData
{
char state;
char direction;
char zapzottimer;
unsigned char dontHitEnable;
unsigned int dontHit; // index of an object type ray will not harm
// for soundwave
int animframe, animtimer;
int offscreentime;
// for earth chunks
int baseframe;
} stRayData;
typedef struct stDoorData
{
char timer;
} stDoorData;
typedef struct stIceChunk
{
int vector_x, vector_y;
int veloc_x, veloc_y;
} stIceChunk;
typedef struct stTeleportData
{
char animtimer;
char animframe;
char numframechanges;
char direction;
int whichplayer;
unsigned int destx;
signed int desty;
int baseframe;
int idleframe;
char NoExitingTeleporter;
char snap;
char fadeamt;
char fadetimer;
} stTeleportData;
// the rope that you cut to kill the vorticon at the end of ep1
typedef struct stRopeData
{
char state;
int droptimer;
int stoneX, stoneY;
int bgtile;
} stRopeData;
typedef struct stWalkerData
{
unsigned char state;
unsigned char animtimer, dietimer;
unsigned char walkframe;
signed int walkerdie_inertia_y;
int fallinctimer,fallspeed;
unsigned char walkdir;
unsigned char kickedplayer[MAX_PLAYERS];
} stWalkerData;
// a moving platform
typedef struct stPlatformData
{
unsigned char state;
unsigned char animframe;
unsigned int animtimer;
unsigned int waittimer;
unsigned char movedir;
unsigned char kickedplayer[MAX_PLAYERS];
} stPlatformData;
// many different assorted things, many sector-effectors affect tiles
// in the level instead of being a sprite. named for the similiarity
// to the object in duke3d
typedef struct stSEData
{
unsigned int type;
unsigned char state;
unsigned int timer;
unsigned int platx, platy;
unsigned int bgtile;
unsigned int dir;
int counter,destroytiles;
unsigned int frame;
int mx,my;
int blowx,blowy;
} stSEData;
typedef struct stBabyData
{
char state;
char dir;
signed int inertia_x, inertia_y;
int jumpdectimer, xdectimer;
int jumpdecrate;
int dietimer;
char walkframe;
int walktimer;
} stBabyData;
typedef struct stFoobData
{
char state;
char dir;
int animframe, animtimer;
int OnSameLevelTime;
int OffOfSameLevelTime;
int spooktimer;
int SpookedByWho;
int blockedtime;
} stFoobData;
// Ninja = the kung-fu bears in ep3
typedef struct stNinjaData
{
char state;
char dir;
int animframe, animtimer;
unsigned int timetillkick;
signed int XInertia, YInertia;
unsigned int XFrictionTimer, YFrictionTimer;
unsigned int XFrictionRate, YFrictionRate;
int KickMoveTimer;
int isdying;
int dietimer;
} stNinjaData;
// vorticon mother
typedef struct stMotherData
{
char state;
char dir;
char hittimes;
int animframe, animtimer;
int timer;
} stMotherData;
typedef struct stMeepData
{
char state;
char dir;
int animframe, animtimer;
int timer;
} stMeepData;
typedef struct stBallJackData
{
char dir;
int animframe, animtimer;
int speed;
} stBallJackData;
#define NESSIETRAILLEN 5
typedef struct stNessieData
{
char state;
char leftrightdir, updowndir;
unsigned int baseframe;
unsigned int tiletrailX[NESSIETRAILLEN+1];
unsigned int tiletrailY[NESSIETRAILLEN+1];
int tiletrailhead;
char animframe, animtimer;
unsigned int destx, desty;
unsigned int pausetimer;
unsigned int pausex, pausey;
unsigned int mortimer_swim_amt;
unsigned int mounted[MAX_PLAYERS];
} stNessieData;
#endif /* ENEMYDATA_H_ */

View File

@@ -3,20 +3,24 @@
#include "../include/game.h"
// AI for the foobs (yellow "scaredy cat" creatures) (ep3)
#define FOOB_WALK 0
#define FOOB_SPOOK 1
#define FOOB_FLEE 2
#define FOOB_EXPLODE 3
#define FOOB_DEAD 4
enum FOOB_ACTIONS{
FOOB_WALK,
FOOB_SPOOK,
FOOB_FLEE,
FOOB_EXPLODE,
FOOB_DEAD
};
#define FOOB_WALK_SPEED 2
#define FOOB_WALK_ANIM_RATE 80
#define FOOB_FLEE_SPEED 20
#define FOOB_FLEE_SPEED 18
#define FOOB_FLEE_ANIM_RATE 16
#define FOOB_SPOOK_SHOW_TIME 50
#define FOOB_HARDMODE_BLOCK_TIME 150
#define FOOB_EXPLODE_ANIM_RATE 35
#define FOOB_SPOOK_TIME 150
@@ -28,7 +32,7 @@
#define FOOB_EXPLODE_FRAME 97
#define FOOB_DEAD_FRAME 101
void foob_ai(int o, stCloneKeenPlus *pCKP)
void foob_ai(int o, bool hardmode)
{
int onsamelevel;
unsigned int i;
@@ -41,9 +45,12 @@ unsigned int i;
objects[o].ai.foob.OnSameLevelTime = 0;
objects[o].blockedr = 0;
objects[o].canbezapped = 1;
objects[o].dead = 0;
objects[o].needinit = 0;
}
if (objects[o].ai.foob.state==FOOB_DEAD) return;
if (!objects[o].hasbeenonscreen) return;
if (objects[o].zapped || objects[o].touchPlayer)
{
@@ -54,7 +61,7 @@ unsigned int i;
objects[o].ai.foob.state = FOOB_EXPLODE;
objects[o].canbezapped = 0;
if (objects[o].onscreen) g_pSound->playStereofromCoord(SOUND_YORP_DIE, PLAY_NOW, objects[o].scrx);
if (pCKP->Control.levelcontrol.hardmode && objects[o].touchPlayer)
if (hardmode && objects[o].touchPlayer)
{
killplayer(objects[o].touchedBy);
}
@@ -142,6 +149,9 @@ unsigned int i;
{
objects[o].ai.foob.dir = LEFT;
}
// in hard mode run TOWARDS the player (he's deadly in hard mode)
if (hardmode) objects[o].ai.foob.dir ^= 1;
}
else objects[o].ai.foob.spooktimer++;
break;
@@ -153,8 +163,10 @@ unsigned int i;
{
if (objects[o].ai.foob.OffOfSameLevelTime > FOOB_RELAX_TIME)
{
relax: ;
objects[o].ai.foob.state = FOOB_WALK;
objects[o].ai.foob.OnSameLevelTime = 0;
break;
}
else objects[o].ai.foob.OffOfSameLevelTime++;
}
@@ -165,16 +177,34 @@ unsigned int i;
objects[o].sprite = FOOB_WALK_RIGHT_FRAME + objects[o].ai.foob.animframe;
if (!objects[o].blockedr)
{
objects[o].x += FOOB_FLEE_SPEED;
objects[o].x += FOOB_FLEE_SPEED;
objects[o].ai.foob.blockedtime = 0;
}
else if (hardmode)
{
if (++objects[o].ai.foob.blockedtime >= FOOB_HARDMODE_BLOCK_TIME)
{
objects[o].ai.foob.blockedtime = 0;
goto relax;
}
}
}
else
{ // walking left
objects[o].sprite = FOOB_WALK_LEFT_FRAME + objects[o].ai.foob.animframe;
if (!objects[o].blockedl)
{
objects[o].x -= FOOB_FLEE_SPEED;
objects[o].x -= FOOB_FLEE_SPEED;
objects[o].ai.foob.blockedtime = 0;
}
else if (hardmode)
{
if (++objects[o].ai.foob.blockedtime >= FOOB_HARDMODE_BLOCK_TIME)
{
objects[o].ai.foob.blockedtime = 0;
goto relax;
}
}
}
/* walk animation */
@@ -192,6 +222,7 @@ unsigned int i;
if (objects[o].sprite==FOOB_DEAD_FRAME)
{
objects[o].ai.foob.state = FOOB_DEAD;
objects[o].dead = 1;
}
else
{
@@ -205,3 +236,4 @@ unsigned int i;
break;
}
}

View File

@@ -1,39 +0,0 @@
#include "../keen.h"
#include "../include/enemyai.h"
// the little pieces that break off of an OBJ_ICECHUNK when it hits
// a wall or a player. (Ep1)
#define ICEBIT_SPEED 20
void icebit_ai(int o)
{
if (objects[o].needinit)
{ // first time initilization
objects[o].inhibitfall = 1;
objects[o].canbezapped = 0;
objects[o].needinit = 0;
}
switch(objects[o].ai.icechunk.movedir)
{
case DUPRIGHT:
objects[o].x += ICEBIT_SPEED;
objects[o].y -= ICEBIT_SPEED;
break;
case DUPLEFT:
objects[o].x -= ICEBIT_SPEED;
objects[o].y -= ICEBIT_SPEED;
break;
case DDOWNRIGHT:
objects[o].x += ICEBIT_SPEED;
objects[o].y += ICEBIT_SPEED;
break;
case DDOWNLEFT:
objects[o].x -= ICEBIT_SPEED;
objects[o].y += ICEBIT_SPEED;
break;
break;
}
}

169
src/ai/icecannon.cpp Normal file
View File

@@ -0,0 +1,169 @@
#include "../keen.h"
#include "../include/game.h"
#include "../include/enemyai.h"
#include "icecannon.h"
#include "../sdl/sound/CSound.h"
// the chunks of ice shot out by an ice cannon (ep1)
#define ICECHUNK_SPEED 15
#define ICECHUNK_STRAIGHT_SPEED 20
#define ICECHUNK_WAIT_TIME 150
void icechunk_ai(int o)
{
if (objects[o].needinit)
{ // first time initialization
int speed;
if (objects[o].ai.icechunk.vector_x && objects[o].ai.icechunk.vector_y)
speed = ICECHUNK_SPEED;
else
speed = ICECHUNK_STRAIGHT_SPEED;
objects[o].ai.icechunk.veloc_x = speed * objects[o].ai.icechunk.vector_x;
objects[o].ai.icechunk.veloc_y = speed * objects[o].ai.icechunk.vector_y;
objects[o].inhibitfall = 1;
objects[o].canbezapped = 0;
objects[o].needinit = 0;
}
// freeze the player if it touches him
if (objects[o].touchPlayer)
{
if (!player[objects[o].touchPlayer].pfrozentime)
{
// make him start sliding in the direction of the impact
if (objects[o].ai.icechunk.vector_x > 0)
{
player[objects[o].touchedBy].pdir = player[objects[o].touchedBy].pshowdir = RIGHT;
player[objects[o].touchedBy].pinertia_x = PMAXSPEED;
}
else if (objects[o].ai.icechunk.vector_x < 0)
{
player[objects[o].touchedBy].pdir = player[objects[o].touchedBy].pshowdir = LEFT;
player[objects[o].touchedBy].pinertia_x = -PMAXSPEED;
}
else // perfectly vertical ice cannons
{
#define UPDNCANNON_PUSHAMT 4
if (player[objects[o].touchedBy].pinertia_x < UPDNCANNON_PUSHAMT)
{
if (rnd()&1)
player[objects[o].touchedBy].pinertia_x = UPDNCANNON_PUSHAMT;
else
player[objects[o].touchedBy].pinertia_x = -UPDNCANNON_PUSHAMT;
}
}
}
freezeplayer(objects[o].touchedBy);
smash(o);
return;
}
// smash the chunk if it hits something
if (objects[o].ai.icechunk.vector_x > 0)
{
if (objects[o].blockedr) { smash(o); return; }
}
else if (objects[o].ai.icechunk.vector_x < 0)
{
if (objects[o].blockedl) { smash(o); return; }
}
if (objects[o].ai.icechunk.vector_y > 0)
{
if (objects[o].blockedd) { smash(o); return; }
}
else if (objects[o].ai.icechunk.vector_y < 0)
{
if (objects[o].blockedu) { smash(o); return; }
}
// fly through the air
objects[o].x += objects[o].ai.icechunk.veloc_x;
objects[o].y += objects[o].ai.icechunk.veloc_y;
}
static void smash(int o)
{
int newobject;
if (objects[o].onscreen)
{
g_pSound->playStereofromCoord(SOUND_CHUNKSMASH, PLAY_NOW, objects[o].x);
// upleft
newobject = spawn_object(objects[o].x, objects[o].y, OBJ_ICEBIT);
objects[newobject].ai.icechunk.vector_x = -1;
objects[newobject].ai.icechunk.vector_y = -1;
// upright
newobject = spawn_object(objects[o].x, objects[o].y, OBJ_ICEBIT);
objects[newobject].ai.icechunk.vector_x = 1;
objects[newobject].ai.icechunk.vector_y = -1;
// downleft
newobject = spawn_object(objects[o].x, objects[o].y, OBJ_ICEBIT);
objects[newobject].ai.icechunk.vector_x = -1;
objects[newobject].ai.icechunk.vector_y = 1;
// downright
newobject = spawn_object(objects[o].x, objects[o].y, OBJ_ICEBIT);
objects[newobject].ai.icechunk.vector_x = 1;
objects[newobject].ai.icechunk.vector_y = 1;
}
delete_object(o);
}
// the little pieces that break off of an OBJ_ICECHUNK when it hits
// a wall or a player. (Ep1)
#define ICEBIT_SPEED 20
void icebit_ai(int o)
{
if (objects[o].needinit)
{ // first time initilization
objects[o].ai.icechunk.veloc_x = ICEBIT_SPEED * objects[o].ai.icechunk.vector_x;
objects[o].ai.icechunk.veloc_y = ICEBIT_SPEED * objects[o].ai.icechunk.vector_y;
objects[o].inhibitfall = 1;
objects[o].canbezapped = 0;
objects[o].needinit = 0;
}
objects[o].x += objects[o].ai.icechunk.veloc_x;
objects[o].y += objects[o].ai.icechunk.veloc_y;
if (!objects[o].onscreen)
{
delete_object(o);
}
}
// the ice cannon itself
void icecannon_ai(int o)
{
int newobject;
// keep spawner object invisible and properly positioned
objects[o].sprite = BLANKSPRITE;
objects[o].inhibitfall = 1;
if (!gunfiretimer)
{
newobject = spawn_object(objects[o].x, objects[o].y, OBJ_ICECHUNK);
objects[newobject].ai.icechunk.vector_x = objects[o].ai.icechunk.vector_x;
objects[newobject].ai.icechunk.vector_y = objects[o].ai.icechunk.vector_y;
}
}

18
src/ai/icecannon.h Normal file
View File

@@ -0,0 +1,18 @@
/*
* icecannon.h
*
* Created on: 06.08.2009
* Author: gerstrong
*/
#ifndef ICECANNON_H_
#define ICECANNON_H_
void delete_object(int o);
unsigned int rnd(void);
static void smash(int o);
#endif /* ICECANNON_H_ */

View File

@@ -1,102 +0,0 @@
#include "../sdl/sound/CSound.h"
#include "../keen.h"
#include "../include/game.h"
#include "../include/enemyai.h"
// the chunks of ice shot out by an ice cannon (ep1)
#define ICECHUNK_FLY 0
#define ICECHUNK_SPEED 15
#define ICECHUNK_WAIT_TIME 150
void icechunk_ai(int o)
{
int newobject,blockedlr;
if (objects[o].needinit)
{ // first time initilization
objects[o].ai.icechunk.state = ICECHUNK_FLY;
objects[o].ai.icechunk.timer = 0;
objects[o].inhibitfall = 1;
objects[o].needinit = 0;
objects[o].canbezapped = 0;
}
if (objects[o].touchPlayer && objects[o].ai.icechunk.state==ICECHUNK_FLY &&\
!player[objects[o].touchedBy].pfrozentime)
{
switch(objects[o].ai.icechunk.movedir)
{
case DUPRIGHT:
case DDOWNRIGHT:
player[objects[o].touchedBy].pdir = player[objects[o].touchedBy].pshowdir = RIGHT;
player[objects[o].touchedBy].pinertia_x = PMAXSPEED;
break;
case DUPLEFT:
case DDOWNLEFT:
player[objects[o].touchedBy].pdir = player[objects[o].touchedBy].pshowdir = LEFT;
player[objects[o].touchedBy].pinertia_x = -PMAXSPEED;
break;
}
freezeplayer(objects[o].touchedBy);
goto smash;
}
switch(objects[o].ai.icechunk.state)
{
case ICECHUNK_FLY:
blockedlr = 0;
if (objects[o].ai.icechunk.movedir==DUPRIGHT || objects[o].ai.icechunk.movedir==DDOWNRIGHT)
{
if (objects[o].blockedr) blockedlr = 1;
}
if (objects[o].ai.icechunk.movedir==DUPLEFT || objects[o].ai.icechunk.movedir==DDOWNLEFT)
{
if (objects[o].blockedl) blockedlr = 1;
}
if (blockedlr)
{
smash: ;
if (objects[o].onscreen)
{
g_pSound->playStereofromCoord(SOUND_CHUNKSMASH, PLAY_NOW, objects[o].scrx);
newobject = spawn_object(objects[o].x, objects[o].y, OBJ_ICEBIT);
objects[newobject].ai.icechunk.movedir = DUPLEFT;
newobject = spawn_object(objects[o].x, objects[o].y, OBJ_ICEBIT);
objects[newobject].ai.icechunk.movedir = DUPRIGHT;
newobject = spawn_object(objects[o].x, objects[o].y, OBJ_ICEBIT);
objects[newobject].ai.icechunk.movedir = DDOWNLEFT;
newobject = spawn_object(objects[o].x, objects[o].y, OBJ_ICEBIT);
objects[newobject].ai.icechunk.movedir = DDOWNRIGHT;
}
objects[o].exists = 0;
return;
}
switch(objects[o].ai.icechunk.movedir)
{
case DUPRIGHT:
objects[o].x += ICECHUNK_SPEED;
objects[o].y -= ICECHUNK_SPEED;
break;
case DUPLEFT:
objects[o].x -= ICECHUNK_SPEED;
objects[o].y -= ICECHUNK_SPEED;
break;
case DDOWNLEFT:
objects[o].x -= ICECHUNK_SPEED;
objects[o].y += ICECHUNK_SPEED;
break;
case DDOWNRIGHT:
objects[o].x += ICECHUNK_SPEED;
objects[o].y += ICECHUNK_SPEED;
break;
break;
}
break;
}
}

View File

@@ -283,7 +283,7 @@ int oneoflasttiles;
oneoflasttiles = 0;
for(i=0;i<NESSIETRAILLEN;i++)
{
if (objects[o].ai.nessie.tiletrailX[i]==destx &&\
if (objects[o].ai.nessie.tiletrailX[i]==destx &&
objects[o].ai.nessie.tiletrailY[i]==desty)
{
oneoflasttiles = 1;

View File

@@ -10,124 +10,96 @@
// ;)
void rope_movestone(int o);
void killboss(int o);
#define ROPE_IDLE 0
#define ROPE_DROP 1
#define ROPE_DROPSTONE 1
#define STONE_WIDTH 9
#define STONE_HEIGHT 2
#define STONE_DROP_RATE 100
#define STONE_DROP_TIMES 4
#define ROPE_SPRITE 114
void delete_object(int o);
void static rope_movestone(int o);
void kill_all_intersecting_tile(int mpx, int mpy);
void rope_ai(int o)
{
int i;
if (objects[o].needinit)
{ // first time initilization
objects[o].ai.rope.state = ROPE_IDLE;
objects[o].canbezapped = 1;
objects[o].inhibitfall = 1;
objects[o].sprite = ROPE_SPRITE;
// find the vorticon commander
for(i=0;i<MAX_OBJECTS;i++)
{
if (objects[i].type == OBJ_VORT)
{
objects[o].ai.rope.vortboss = i;
break;
}
}
objects[o].needinit = 0;
}
int x;
if (objects[o].needinit)
{ // first time initialization
objects[o].ai.rope.state = ROPE_IDLE;
objects[o].canbezapped = 1;
objects[o].inhibitfall = 1;
objects[o].sprite = OBJ_ROPE_DEFSPRITE;
switch(objects[o].ai.rope.state)
{
case ROPE_IDLE:
if (objects[o].zapped)
{ // time to drop the stone
objects[o].ai.rope.state = ROPE_DROP;
objects[o].ai.rope.droptimer = STONE_DROP_RATE;
objects[o].ai.rope.droptimes = 0;
// get upper left corner of the stone
objects[o].ai.rope.stoneX = (objects[o].x >> CSF >> 4) - 4;
objects[o].ai.rope.stoneY = (objects[o].y >> CSF >> 4) + 1;
// hide the rope
objects[o].sprite = BlankSprite;
}
break;
case ROPE_DROP:
if (objects[o].ai.rope.droptimer > STONE_DROP_RATE)
{
rope_movestone(o);
objects[o].ai.rope.droptimer = 0;
objects[o].needinit = 0;
}
objects[o].ai.rope.droptimes++;
if (objects[o].ai.rope.droptimes >= STONE_DROP_TIMES)
{
// just to make sure the boss is dead
// killboss(o);
objects[o].exists = 0;
}
}
else objects[o].ai.rope.droptimer++;
switch(objects[o].ai.rope.state)
{
case ROPE_IDLE:
if (objects[o].zapped)
{
// rope got broke! time to drop the stone
objects[o].ai.rope.state = ROPE_DROPSTONE;
objects[o].ai.rope.droptimer = 0;
// hide the rope
objects[o].sprite = BLANKSPRITE;
// get upper left corner of the stone
objects[o].ai.rope.stoneX = (objects[o].x >> CSF >> 4) - 4;
objects[o].ai.rope.stoneY = (objects[o].y >> CSF >> 4) + 1;
// get color of background
objects[o].ai.rope.bgtile = getmaptileat(objects[o].x>>CSF, objects[o].y>>CSF);
}
break;
case ROPE_DROPSTONE:
if (!objects[o].ai.rope.droptimer)
{
objects[o].ai.rope.droptimer = STONE_DROP_RATE;
rope_movestone(o);
// check if we've hit the ground yet
for(x=0;x<STONE_WIDTH;x++)
{
if (TileProperty[map.mapdata[objects[o].ai.rope.stoneX+x][objects[o].ai.rope.stoneY+2]][BUP])
{
delete_object(o);
return;
}
}
}
else objects[o].ai.rope.droptimer--;
break;
}
}
void rope_movestone(int o)
void static rope_movestone(int o)
{
int xa,ya;
int x,y;
unsigned int xpix,ypix,vb;
xa = objects[o].ai.rope.stoneX;
ya = objects[o].ai.rope.stoneY;
// move the stone down one space
for(y=STONE_HEIGHT;y>0;y--)
{
for(x=0;x<STONE_WIDTH;x++)
{
map_chgtile(x+xa,y+ya,map.mapdata[x+xa][y+ya-1]);
// if the stone has hit the vorticon commander, kill him
xpix = (x+xa)<<4<<CSF; ypix = (y+ya)<<4<<CSF;
vb = objects[o].ai.rope.vortboss;
if (xpix <= objects[vb].x && xpix+(16<<CSF) >= objects[vb].x)
{
if (ypix <= objects[vb].y && ypix+(16<<CSF) >= objects[vb].y)
{
killboss(o);
}
}
}
}
// clear the space at the top with black
for(x=0;x<STONE_WIDTH;x++)
{
map_chgtile(x+xa,ya,BG_BLACK);
}
xa = objects[o].ai.rope.stoneX;
ya = objects[o].ai.rope.stoneY;
objects[o].ai.rope.stoneY++;
// move the stone down one space and kill anything in it's path!
for(y=STONE_HEIGHT;y>0;y--)
{
for(x=0;x<STONE_WIDTH;x++)
{
map_chgtile(x+xa,y+ya,map.mapdata[x+xa][y+ya-1]);
// if the stone hits any enemies, kill them
kill_all_intersecting_tile(x+xa, y+ya);
}
}
// clear the space at the top
for(x=0;x<STONE_WIDTH;x++)
map_chgtile(x+xa,ya,objects[o].ai.rope.bgtile);
objects[o].ai.rope.stoneY++;
}
void killboss(int o)
{
int vb;
vb = objects[o].ai.rope.vortboss;
if (objects[vb].ai.vort.state != VORT_DYING &&\
objects[vb].ai.vort.state != VORT_DEAD)
{
objects[vb].inhibitfall = 0;
objects[vb].canbezapped = 0;
objects[vb].ai.vort.animtimer = 0;
objects[vb].ai.vort.frame = 0;
objects[vb].ai.vort.palflashtimer = VORT_PALETTE_FLASH_TIME+1;
objects[vb].ai.vort.palflashamt = 255;
objects[vb].ai.vort.state = VORT_DYING;
//pal_set(0, 255, objects[vb].ai.vort.palflashamt, objects[vb].ai.vort.palflashamt);
g_pSound->playStereofromCoord(SOUND_VORT_DIE, PLAY_NOW, objects[o].scrx);
}
}

View File

@@ -1,10 +1,13 @@
#include "../sdl/sound/CSound.h"
#include "../keen.h"
#include "ray.h"
#include "se.h"
#include "../include/game.h"
#include "../include/enemyai.h"
#include "../CLogFile.h"
char PlatExtending=0;
// "Sector Effector" object (The name comes from D3D)...it's basically
@@ -13,111 +16,98 @@ char PlatExtending=0;
// around it. Used where it wasn't worth it to create a whole new object
// (or where I was too lazy to do it).
void se_extend_plat(int o); // extends a platform (ep2)
void se_spark(int o, stLevelControl *p_levelcontrol); // spark in Tantalus Ray (ep2)
void se_gun(int o); // periodically-firing guns (ep3)
void se_ankhshield(int o); // Ankh Shield (ep3)
void se_icecannon(int o); // ice cannon (ep1)
void se_mortimer_arm(int o); // Mortimer's arms (ep3)
void se_mortimer_leg_left(int o); // Mortimer's left leg (ep3)
void se_mortimer_leg_right(int o, stCloneKeenPlus *pCKP); // Mortimer's right leg (ep3)
void se_mortimer_spark(int o, stCloneKeenPlus *pCKP); // spark in Mortimer's machine (ep3)
void se_mortimer_heart(int o); // Mortimer's "heart" (ep3)
void se_mortimer_zapsup(int o, stCloneKeenPlus *pCKP); // causes zaps to roll up Mortimer's machine (ep3)
void se_mortimer_randomzaps(int o); // spawns random zaps on Mortimer's machine (ep3)
void se_retract_plat(int o);
// this also contains the AI for the Spark object
void set_mortimer_surprised(int yes);
int mortimer_surprisedcount=0;
int mortimer_surprisedcount = 0;
void se_ai(int o, stCloneKeenPlus *pCKP)
{
switch(objects[o].ai.se.type)
{
case SE_EXTEND_PLATFORM: se_extend_plat(o); break;
case SE_RETRACT_PLATFORM: se_retract_plat(o); break;
case SE_SPARK: se_spark(o, (&pCKP->Control.levelcontrol)); break;
case SE_GUN_VERT: se_gun(o); break;
case SE_GUN_RIGHT: se_gun(o); break;
case SE_ANKHSHIELD: se_ankhshield(o); break;
case SE_ICECANNON: se_icecannon(o); break;
case SE_MORTIMER_ARM: se_mortimer_arm(o); break;
case SE_MORTIMER_LEG_LEFT: se_mortimer_leg_left(o); break;
case SE_MORTIMER_LEG_RIGHT: se_mortimer_leg_right(o, pCKP); break;
case SE_MORTIMER_SPARK: se_mortimer_spark(o, pCKP); break;
case SE_MORTIMER_HEART: se_mortimer_heart(o); break;
case SE_MORTIMER_ZAPSUP: se_mortimer_zapsup(o, pCKP); break;
case SE_MORTIMER_RANDOMZAPS: se_mortimer_randomzaps(o); break;
switch(objects[o].ai.se.type)
{
case SE_EXTEND_PLATFORM: se_extend_plat(o, &(pCKP->Control.levelcontrol.PlatExtending) ); break;
case SE_RETRACT_PLATFORM: se_retract_plat(o, &(pCKP->Control.levelcontrol.PlatExtending) ); break;
case SE_ANKHSHIELD: se_ankhshield(o, pCKP->Control.levelcontrol.episode); break;
case SE_MORTIMER_ARM: se_mortimer_arm(o); break;
case SE_MORTIMER_LEG_LEFT: se_mortimer_leg_left(o); break;
case SE_MORTIMER_LEG_RIGHT: se_mortimer_leg_right(o); break;
case SE_MORTIMER_SPARK: se_mortimer_spark(o, &(pCKP->Control.levelcontrol) ); break;
case SE_MORTIMER_HEART: se_mortimer_heart(o, &(pCKP->Control.levelcontrol) ); break;
case SE_MORTIMER_ZAPSUP: se_mortimer_zapsup(o, &(pCKP->Control.levelcontrol) ); break;
case SE_MORTIMER_RANDOMZAPS: se_mortimer_randomzaps(o); break;
default: crashflag = 1;
crashflag2 = objects[o].ai.se.type;
why_term_ptr = "Invalid sector effector type (shown in flag2)";
break;
}
default:
g_pLogFile->ftextOut("Invalid sector effector type %d", objects[o].ai.se.type);
break;
}
}
void se_extend_plat(int o)
void se_extend_plat(int o, bool *p_PlatExtending)
{
//char buf[80];
#define PLAT_EXTEND_RATE 30
if (objects[o].needinit)
{
objects[o].ai.se.timer = 0;
objects[o].inhibitfall = 1;
objects[o].canbezapped = 0;
objects[o].sprite = BlankSprite;
objects[o].needinit = 0;
if (objects[o].needinit)
{
objects[o].ai.se.timer = 0;
objects[o].inhibitfall = 1;
objects[o].canbezapped = 0;
objects[o].sprite = BLANKSPRITE;
// figure out which direction the bridge is supposed to go
if (!TileProperty[map.mapdata[objects[o].ai.se.platx+1][objects[o].ai.se.platy]][BLEFT])
//if (!tiles[map.mapdata[objects[o].ai.se.platx+1][objects[o].ai.se.platy]].solidl)
objects[o].ai.se.dir = RIGHT;
else
objects[o].ai.se.dir = LEFT;
}
// if the platform is already extended, turn ourselves
// into an se_retract_plat()
//lprintf(">se_extend:check=%d expect=%d",getmaptileat(objects[o].x>>CSF,objects[o].y>>CSF),TILE_EXTENDING_PLATFORM);
if (map.mapdata[objects[o].ai.se.platx][objects[o].ai.se.platy]==\
TILE_EXTENDING_PLATFORM)
{
objects[o].ai.se.type = SE_RETRACT_PLATFORM;
se_retract_plat(o, p_PlatExtending);
return;
}
if (!objects[o].ai.se.timer)
{
if (!TileProperty[map.mapdata[objects[o].ai.se.platx][objects[o].ai.se.platy]][BUP])
//if (!tiles[map.mapdata[objects[o].ai.se.platx][objects[o].ai.se.platy]].solidfall)
{
map_chgtile(objects[o].ai.se.platx, objects[o].ai.se.platy, TILE_EXTENDING_PLATFORM);
// figure out which direction the bridge is supposed to go
if (!TileProperty[map.mapdata[objects[o].ai.se.platx+1][objects[o].ai.se.platy]][BLEFT])
objects[o].ai.se.dir = RIGHT;
else
objects[o].ai.se.dir = LEFT;
if (objects[o].ai.se.dir==RIGHT)
objects[o].ai.se.platx++;
else
objects[o].ai.se.platx--;
objects[o].needinit = 0;
}
objects[o].ai.se.timer = PLAT_EXTEND_RATE;
if (!objects[o].ai.se.timer)
{
if (!TileProperty[map.mapdata[objects[o].ai.se.platx][objects[o].ai.se.platy]][BUP])
{
map_chgtile(objects[o].ai.se.platx, objects[o].ai.se.platy, TILE_EXTENDING_PLATFORM);
kill_all_intersecting_tile(objects[o].ai.se.platx, objects[o].ai.se.platy);
if (objects[o].ai.se.dir==RIGHT)
objects[o].ai.se.platx++;
else
objects[o].ai.se.platx--;
objects[o].ai.se.timer = PLAT_EXTEND_RATE;
}
else
{
delete_object(o);
*p_PlatExtending = false;
return;
}
else
{
objects[o].exists = 0;
PlatExtending = 0;
}
}
else objects[o].ai.se.timer--;
}
else objects[o].ai.se.timer--;
}
void se_retract_plat(int o)
void se_retract_plat(int o, bool *p_PlatExtending)
{
if (objects[o].needinit)
{
objects[o].ai.se.timer = PLAT_EXTEND_RATE;
objects[o].inhibitfall = 1;
objects[o].canbezapped = 0;
objects[o].sprite = BlankSprite;
objects[o].needinit = 0;
// get the background tile from the tile above the starting point
objects[o].ai.se.bgtile = map.mapdata[objects[o].ai.se.platx][objects[o].ai.se.platy-1];
// figure out which direction the bridge is supposed to go
if (map.mapdata[objects[o].ai.se.platx-1][objects[o].ai.se.platy] != TILE_EXTENDING_PLATFORM)
if (objects[o].needinit)
{
// get the background tile from the tile above the starting point
objects[o].ai.se.bgtile = map.mapdata[objects[o].ai.se.platx][objects[o].ai.se.platy-1];
// figure out which direction the bridge is supposed to go
if (map.mapdata[objects[o].ai.se.platx-1][objects[o].ai.se.platy] != TILE_EXTENDING_PLATFORM)
objects[o].ai.se.dir = LEFT;
else
objects[o].ai.se.dir = RIGHT;
@@ -127,67 +117,67 @@ void se_retract_plat(int o)
// it was extended)
do
{
if (map.mapdata[objects[o].ai.se.platx][objects[o].ai.se.platy] != TILE_EXTENDING_PLATFORM)
{ // we've found the end of the platform
break;
}
if (objects[o].ai.se.dir==LEFT)
{
if (objects[o].ai.se.platx==map.xsize)
{
crashflag = 1;
why_term_ptr = "SE_RETRACT_PLATFORM: Failed to find end of platform when scanning right.";
return;
}
objects[o].ai.se.platx++;
}
else
{ // platform will be removed in a right-going direction
if (objects[o].ai.se.platx==0)
{
crashflag = 1;
why_term_ptr = "SE_RETRACT_PLATFORM: Failed to find end of platform when scanning left.";
return;
}
if (map.mapdata[objects[o].ai.se.platx][objects[o].ai.se.platy] != TILE_EXTENDING_PLATFORM)
{ // we've found the end of the platform
break;
}
if (objects[o].ai.se.dir==LEFT)
{
if (objects[o].ai.se.platx==map.xsize)
{
g_pLogFile->ftextOut("SE_RETRACT_PLATFORM: Failed to find end of platform when scanning right.");
return;
}
objects[o].ai.se.platx++;
}
else
{ // platform will be removed in a right-going direction
if (objects[o].ai.se.platx==0)
{
g_pLogFile->ftextOut("SE_RETRACT_PLATFORM: Failed to find end of platform when scanning left.");
return;
}
objects[o].ai.se.platx--;
}
} while(1);
} while(1);
// when we were scanning we went one tile too far, go back one
if (objects[o].ai.se.dir==LEFT) objects[o].ai.se.platx--;
else objects[o].ai.se.platx++;
}
if (objects[o].ai.se.timer >= PLAT_EXTEND_RATE)
{
if (map.mapdata[objects[o].ai.se.platx][objects[o].ai.se.platy]==TILE_EXTENDING_PLATFORM)
{
map_chgtile(objects[o].ai.se.platx, objects[o].ai.se.platy, objects[o].ai.se.bgtile);
objects[o].needinit = 0;
}
if (objects[o].ai.se.dir==RIGHT)
objects[o].ai.se.platx++;
else
objects[o].ai.se.platx--;
if (!objects[o].ai.se.timer)
{
if (map.mapdata[objects[o].ai.se.platx][objects[o].ai.se.platy]==TILE_EXTENDING_PLATFORM)
{
map_chgtile(objects[o].ai.se.platx, objects[o].ai.se.platy, objects[o].ai.se.bgtile);
objects[o].ai.se.timer = 0;
}
else
{
objects[o].exists = 0;
PlatExtending = 0;
}
}
else objects[o].ai.se.timer++;
if (objects[o].ai.se.dir==RIGHT)
objects[o].ai.se.platx++;
else
objects[o].ai.se.platx--;
objects[o].ai.se.timer = PLAT_EXTEND_RATE;
}
else
{
delete_object(o);
*p_PlatExtending = false;
}
}
else objects[o].ai.se.timer--;
}
void se_spark(int o, stLevelControl *p_levelcontrol)
// AI for the Spark object in the Tantalus Ray Machine's of ep2
void spark_ai(int o, int *p_sparks_left)
{
int newobject;
int mx,my,x,y;
#define SPARK_BASEFRAME 128
#define SPARK_BASEFRAME OBJ_SPARK_DEFSPRITE_EP2
#define SPARK_ANIMRATE 20
#define SPARK_ANIMATE 0
@@ -197,6 +187,8 @@ int mx,my,x,y;
#define SPARK_BLOW_DELAY 100
#define BG_GREY 143
if (objects[o].needinit)
{
objects[o].ai.se.state = SPARK_ANIMATE;
@@ -215,9 +207,14 @@ int mx,my,x,y;
}
else
{
objects[o].sprite = BlankSprite;
objects[o].sprite = BLANKSPRITE;
}
if (objects[o].touchPlayer)
{
killplayer(objects[o].touchedBy);
}
switch(objects[o].ai.se.state)
{
case SPARK_ANIMATE:
@@ -230,19 +227,18 @@ int mx,my,x,y;
if (objects[o].zapped)
{
g_pSound->playStereofromCoord(SOUND_SHOT_HIT, PLAY_NOW, objects[o].scrx);
g_pSound->playStereofromCoord(SOUND_SHOT_HIT,PLAY_NOW, objects[o].x);
// break the glass and blow out the electric arcs
map_chgtile(objects[o].ai.se.mx - 2, objects[o].ai.se.my, 492);
map_chgtile(objects[o].ai.se.mx - 1, objects[o].ai.se.my, 546);
map_chgtile(objects[o].ai.se.mx, objects[o].ai.se.my, 547);
map_chgtile(objects[o].ai.se.mx + 1, objects[o].ai.se.my, 548);
map_chgtile(objects[o].ai.se.mx + 2, objects[o].ai.se.my, 492);
map_deanimate(objects[o].ai.se.mx - 2, objects[o].ai.se.my);
map_deanimate(objects[o].ai.se.mx + 2, objects[o].ai.se.my);
// remove the unneeded dome tiles
map_chgtile(objects[o].ai.se.mx - 1, objects[o].ai.se.my-1, BG_GRAY);
map_chgtile(objects[o].ai.se.mx, objects[o].ai.se.my-1, BG_GRAY);
map_chgtile(objects[o].ai.se.mx + 1, objects[o].ai.se.my-1, BG_GRAY);
map_chgtile(objects[o].ai.se.mx - 1, objects[o].ai.se.my-1, BG_GREY);
map_chgtile(objects[o].ai.se.mx, objects[o].ai.se.my-1, BG_GREY);
map_chgtile(objects[o].ai.se.mx + 1, objects[o].ai.se.my-1, BG_GREY);
// break the switch
map_chgtile(objects[o].ai.se.mx - 3, objects[o].ai.se.my + 4, 506);
@@ -251,12 +247,8 @@ int mx,my,x,y;
objects[o].ai.se.timer = 0;
objects[o].ai.se.blowy = 0;
fade.mode = FADE_GO;
fade.dir = FADE_IN;
fade.curamt = PAL_FADE_WHITEOUT;
fade.fadetimer = 0;
fade.rate = FADE_NORM;
}
//fade(FADE_FLASH, FADE_NORM);
}
break;
case SPARK_BLOWUP1:
// one by one blow out the purple thingies below the device
@@ -266,14 +258,14 @@ int mx,my,x,y;
mx = objects[o].ai.se.mx;
my = objects[o].ai.se.my+3+objects[o].ai.se.blowy;
map_chgtile(mx, my, 505);
map_deanimate(mx, my);
// spawn a ZAP! or a ZOT!
newobject = spawn_object(mx<<4<<CSF, my<<4<<CSF, OBJ_RAY);
objects[newobject].ai.ray.state = RAY_STATE_SETZAPZOT;
objects[newobject].inhibitfall = 1;
objects[newobject].needinit = 0;
objects[newobject].ai.ray.dontHitEnable = 0;
g_pSound->playStereofromCoord(SOUND_SHOT_HIT, PLAY_NOW, objects[o].scrx);
g_pSound->playStereofromCoord(SOUND_SHOT_HIT,PLAY_NOW, objects[newobject].x);
objects[o].ai.se.blowy++;
if (objects[o].ai.se.blowy >= 3)
@@ -299,11 +291,10 @@ int mx,my,x,y;
for(x=0;x<3;x++)
{
map_chgtile(mx+x,my+y,533);
map_animate(mx+x,my+y);
}
}
objects[o].exists = 0;
p_levelcontrol->canexit = 1; // ok, you can exit now
delete_object(o);
*p_sparks_left--;
return;
}
@@ -313,7 +304,6 @@ int mx,my,x,y;
{
my = objects[o].ai.se.my+3+y;
map_chgtile(mx, my, 549);
map_deanimate(mx, my);
// spawn a ZAP! or a ZOT!
newobject = spawn_object(mx<<4<<CSF, my<<4<<CSF, OBJ_RAY);
objects[newobject].ai.ray.state = RAY_STATE_SETZAPZOT;
@@ -321,7 +311,7 @@ int mx,my,x,y;
objects[newobject].needinit = 0;
}
g_pSound->playStereofromCoord(SOUND_SHOT_HIT, PLAY_NOW, objects[o].scrx);
g_pSound->playStereofromCoord(SOUND_SHOT_HIT, PLAY_NOW, objects[newobject].x);
objects[o].ai.se.blowx++;
}
else objects[o].ai.se.timer++;
@@ -330,37 +320,7 @@ int mx,my,x,y;
}
void se_gun(int o)
{
int newobject;
if (objects[o].needinit)
{
objects[o].ai.se.timer = 0;
objects[o].sprite = BlankSprite;
objects[o].inhibitfall = 1;
objects[o].needinit = 0;
}
if (!gunfiretimer)
{
if (objects[o].ai.se.type==SE_GUN_VERT)
{
newobject = spawn_object(objects[o].x+(4<<CSF), objects[o].y+(1<<CSF), OBJ_RAY);
objects[newobject].sprite = RAY_VERT_EP3;
objects[newobject].ai.ray.direction = DOWN;
}
else if (objects[o].ai.se.type==SE_GUN_RIGHT)
{
newobject = spawn_object(objects[o].x+(1<<CSF), objects[o].y+(2<<CSF), OBJ_RAY);
objects[newobject].sprite = ENEMYRAYEP3;
objects[newobject].ai.ray.direction = RIGHT;
}
if((objects[o].scrx > 0) && (objects[o].scrx < 255))
g_pSound->playStereofromCoord(SOUND_TANK_FIRE, PLAY_NOW, objects[o].scrx);
}
}
void se_ankhshield(int o)
void se_ankhshield(int o, int episode)
{
#define ANKH_FLICKER_FREQ 12
@@ -382,7 +342,7 @@ void se_ankhshield(int o)
break;
case ANKH_STATE_FLICKERFAST:
if (objects[o].ai.se.frame&1)
objects[o].sprite = BlankSprite;
objects[o].sprite = BLANKSPRITE;
else
{
if (objects[o].ai.se.frame&2)
@@ -393,9 +353,9 @@ void se_ankhshield(int o)
break;
case ANKH_STATE_FLICKERSLOW:
if (objects[o].ai.se.frame>4)
objects[o].sprite = BlankSprite;
objects[o].sprite = BLANKSPRITE;
else
objects[o].sprite = ANKH_SHIELD_FRAME;
objects[o].sprite = (episode==3)?ANKH_SHIELD_FRAME:YORPSHIELD_SPRITE;
break;
}
@@ -406,20 +366,6 @@ void se_ankhshield(int o)
objects[o].ai.se.timer = 0;
}
else objects[o].ai.se.timer++;
}
void se_icecannon(int o)
{
int newobject;
if (!gunfiretimer)
{
newobject = spawn_object(objects[o].x, objects[o].y, OBJ_ICECHUNK);
objects[newobject].ai.icechunk.movedir = objects[o].ai.se.dir;
}
}
#define ARM_GO 0
@@ -541,7 +487,7 @@ int mx,my;
#define MSPARK_IDLE 0
#define MSPARK_DESTROYARMS 1
void se_mortimer_spark(int o, stCloneKeenPlus *pCKP)
void se_mortimer_spark(int o, stLevelControl *p_levelcontrol)
{
int x,mx,i;
int newobject;
@@ -576,56 +522,54 @@ int newobject;
if (objects[o].zapped)
{
set_mortimer_surprised(1);
set_mortimer_surprised(1);
SetVibrateTime(200, 0, p_levelcontrol);
// if there are any sparks left, destroy the spark,
// else destroy mortimer's arms
for(i=0;i<MAX_OBJECTS;i++)
{
if (objects[i].type==OBJ_SECTOREFFECTOR &&\
objects[i].ai.se.type==SE_MORTIMER_SPARK &&\
objects[i].exists)
{
if (i!=o)
{
objects[o].ai.se.type = SE_MORTIMER_RANDOMZAPS;
objects[o].needinit = 1;
return;
}
}
}
// if there are any sparks left, destroy the spark,
// else destroy mortimer's arms
for(i=0;i<highest_objslot;i++)
{
if (objects[i].type==OBJ_SECTOREFFECTOR &&\
objects[i].ai.se.type==SE_MORTIMER_SPARK &&\
objects[i].exists)
{
if (i!=o)
{ // other sparks still exist
objects[o].ai.se.type = SE_MORTIMER_RANDOMZAPS;
objects[o].needinit = 1;
return;
}
}
}
// keen just destroyed the last spark
/* destroy mortimer's arms */
objects[o].sprite = BlankSprite;
/* destroy mortimer's arms */
objects[o].sprite = BLANKSPRITE;
// destroy the sector effectors controlling his arms
for(i=0;i<MAX_OBJECTS;i++)
{
if (objects[i].type==OBJ_SECTOREFFECTOR && \
objects[i].ai.se.type==SE_MORTIMER_ARM)
{
objects[i].exists = 0;
}
}
// go into a state to destroy mortimer's arms
objects[o].ai.se.state = MSPARK_DESTROYARMS;
objects[o].ai.se.my = MORTIMER_ARMS_YSTART;
objects[o].ai.se.timer = 0;
// destroy the sector effectors controlling his arms
for(i=0;i<highest_objslot;i++)
{
if (objects[i].type==OBJ_SECTOREFFECTOR && \
objects[i].ai.se.type==SE_MORTIMER_ARM)
{
delete_object(i);
}
}
// go into a state where we'll destroy mortimer's arms
objects[o].ai.se.state = MSPARK_DESTROYARMS;
objects[o].ai.se.my = MORTIMER_ARMS_YSTART;
objects[o].ai.se.timer = 0;
}
break;
case MSPARK_DESTROYARMS:
if (!objects[o].ai.se.timer)
{
g_pSound->playStereofromCoord(SOUND_SHOT_HIT, PLAY_NOW, objects[o].x);
for(x=0;x<3;x++)
{
mx = MORTIMER_LEFT_ARM_X+x;
if (map.mapdata[mx][objects[o].ai.se.my]!=169)
if (map.mapdata[mx][objects[o].ai.se.my] != 169)
{
//if (tiles[map.mapdata[mx][objects[o].ai.se.my]].isAnimated)
if (TileProperty[map.mapdata[mx][objects[o].ai.se.my]][ANIMATION] > 1)
{
map_deanimate(mx, objects[o].ai.se.my);
}
map_chgtile(mx, objects[o].ai.se.my, 169);
// spawn a ZAP! or a ZOT!
newobject = spawn_object(((mx<<4)+4)<<CSF, objects[o].ai.se.my<<4<<CSF, OBJ_RAY);
@@ -636,12 +580,8 @@ int newobject;
}
mx = MORTIMER_RIGHT_ARM_X+x;
if (map.mapdata[mx][objects[o].ai.se.my]!=169)
if (map.mapdata[mx][objects[o].ai.se.my] != 169)
{
if (TileProperty[map.mapdata[mx][objects[o].ai.se.my]][ANIMATION] > 1)
{
map_deanimate(mx, objects[o].ai.se.my);
}
map_chgtile(mx, objects[o].ai.se.my, 169);
// spawn a ZAP! or a ZOT!
newobject = spawn_object(((mx<<4)+4)<<CSF, objects[o].ai.se.my<<4<<CSF, OBJ_RAY);
@@ -656,7 +596,7 @@ int newobject;
objects[o].ai.se.my++;
if (objects[o].ai.se.my > MORTIMER_ARMS_YEND)
{
objects[o].exists = 0;
delete_object(o);
set_mortimer_surprised(0);
}
}
@@ -685,57 +625,59 @@ int newobject;
#define ZAPSUP_NORMAL 0
#define ZAPSUP_ABOUTTOFADEOUT 1
void se_mortimer_heart(int o)
void se_mortimer_heart(int o, stLevelControl *p_levelcontrol)
{
int i,x;
int x,i;
int newobject;
if (objects[o].needinit)
{
objects[o].ai.se.timer = 0;
objects[o].ai.se.frame = 0;
objects[o].ai.se.state = HEART_IDLE;
objects[o].inhibitfall = 1;
objects[o].canbezapped = 1;
objects[o].needinit = 0;
mortimer_surprisedcount = 0;
objects[o].ai.se.timer = 0;
objects[o].ai.se.frame = 0;
objects[o].ai.se.state = HEART_IDLE;
objects[o].inhibitfall = 1;
objects[o].canbezapped = 1;
objects[o].needinit = 0;
mortimer_surprisedcount = 0;
}
switch(objects[o].ai.se.state)
{
case HEART_IDLE:
objects[o].sprite = MORTIMER_HEART_BASEFRAME + objects[o].ai.se.frame;
case HEART_IDLE:
objects[o].sprite = MORTIMER_HEART_BASEFRAME + objects[o].ai.se.frame;
if (objects[o].ai.se.timer > HEART_ANIMRATE)
{
objects[o].ai.se.frame ^= 1;
objects[o].ai.se.timer = 0;
}
else objects[o].ai.se.timer++;
if (objects[o].ai.se.timer > HEART_ANIMRATE)
{
objects[o].ai.se.frame ^= 1;
objects[o].ai.se.timer = 0;
}
else objects[o].ai.se.timer++;
if (objects[o].zapped)
{
objects[o].sprite = BlankSprite;
set_mortimer_surprised(1);
if (objects[o].zapped)
{
objects[o].sprite = BLANKSPRITE;
set_mortimer_surprised(1);
/* destroy Mortimer's machine */
/* destroy Mortimer's machine */
SetVibrateTime(1500, 0, p_levelcontrol);
// kill all enemies
for(i=0;i<MAX_OBJECTS;i++)
{
if (objects[i].type!=OBJ_PLAYER && i!=o)
{
objects[i].exists = 0;
}
}
// kill all enemies
for(i=0;i<highest_objslot;i++)
{
if (objects[i].type!=OBJ_PLAYER && i!=o)
{
delete_object(i);
}
}
set_mortimer_surprised(1);
// have waves of zaps run up mortimer's machine
objects[o].ai.se.timer = 0;
objects[o].ai.se.state = HEART_ZAPSRUNUP;
objects[o].ai.se.counter = 0;
}
break;
set_mortimer_surprised(1);
// have waves of zaps run up mortimer's machine
objects[o].ai.se.timer = 0;
objects[o].ai.se.state = HEART_ZAPSRUNUP;
objects[o].ai.se.counter = 0;
}
break;
case HEART_ZAPSRUNUP:
if (!objects[o].ai.se.timer)
{
@@ -752,7 +694,7 @@ int newobject;
if (objects[o].ai.se.counter > MORTIMER_NUMZAPWAVES)
{
objects[newobject].ai.se.destroytiles = 1;
objects[o].exists = 0;
delete_object(o);
}
else objects[o].ai.se.counter++;
}
@@ -764,11 +706,6 @@ int newobject;
for(x=MORTIMER_MACHINE_XSTART;x<MORTIMER_MACHINE_XEND;x++)
{
// delete the tile
//if (tiles[map.mapdata[x][objects[o].ai.se.my]].isAnimated)
if (TileProperty[map.mapdata[x][objects[o].ai.se.my]][ANIMATION])
{
map_deanimate(x,objects[o].ai.se.my);
}
map_chgtile(x,objects[o].ai.se.my,169);
// spawn a ZAP! or a ZOT!
newobject = spawn_object(((x<<4)+4)<<CSF, objects[o].ai.se.my<<4<<CSF, OBJ_RAY);
@@ -781,7 +718,7 @@ int newobject;
objects[o].ai.se.timer = MACHINE_DESTROY_RATE;
if (objects[o].ai.se.my > MORTIMER_MACHINE_YEND)
{
objects[o].exists = 0;
delete_object(o);
}
else objects[o].ai.se.my++;
}
@@ -790,8 +727,8 @@ int newobject;
}
}
#define TIME_AFTER_DESTROY_BEFORE_FADEOUT 500
void se_mortimer_zapsup(int o, stCloneKeenPlus *pCKP)
#define TIME_AFTER_DESTROY_BEFORE_FADEOUT 2300
void se_mortimer_zapsup(int o, stLevelControl *levelcontrol)
{
int x, newobject;
@@ -799,12 +736,13 @@ int x, newobject;
{
if (objects[o].ai.se.state==ZAPSUP_ABOUTTOFADEOUT)
{
pCKP->Control.levelcontrol.level_done = LEVEL_DONE_FADEOUT;
endlevel(1,pCKP);
objects[o].exists = 0;
levelcontrol->level_done = LEVEL_DONE_FADEOUT;
endlevel(WON_LEVEL, levelcontrol);
delete_object(o);
return;
}
g_pSound->playStereofromCoord(SOUND_SHOT_HIT, PLAY_NOW, objects[o].x);
for(x=MORTIMER_MACHINE_XSTART;x<MORTIMER_MACHINE_XEND;x++)
{
// spawn a ZAP! or a ZOT!
@@ -817,11 +755,6 @@ int x, newobject;
if (objects[o].ai.se.destroytiles)
{
// delete the tile
//if (tiles[map.mapdata[x][objects[o].ai.se.my]].isAnimated)
if (TileProperty[map.mapdata[x][objects[o].ai.se.my]][ANIMATION])
{
map_deanimate(x,objects[o].ai.se.my);
}
map_chgtile(x,objects[o].ai.se.my,169);
}
}
@@ -838,7 +771,7 @@ int x, newobject;
}
else
{
objects[o].exists = 0;
delete_object(o);
objects[o].ai.se.timer = 0;
}
}
@@ -887,7 +820,7 @@ int mx,my;
{
objects[o].ai.se.timer = 0;
objects[o].ai.se.state = LEG_WAIT;
g_pSound->playStereofromCoord(SOUND_FOOTSLAM, PLAY_NOW, objects[o].scrx);
g_pSound->playStereofromCoord(SOUND_FOOTSLAM, PLAY_NOW, objects[o].x);
}
else
{
@@ -954,13 +887,9 @@ int mx,my;
}
}
void se_mortimer_leg_right(int o, stCloneKeenPlus *pCKP)
void se_mortimer_leg_right(int o)
{
int mx,my;
if (objects[o].touchPlayer)
{
killplayer(objects[o].touchedBy);
}
if (objects[o].needinit)
{
objects[o].ai.se.dir = UP;
@@ -970,6 +899,11 @@ int mx,my;
objects[o].needinit = 0;
}
if (objects[o].touchPlayer)
{
killplayer(objects[o].touchedBy);
}
switch(objects[o].ai.se.state)
{
case LEG_GO:
@@ -990,7 +924,7 @@ int mx,my;
{
objects[o].ai.se.timer = 0;
objects[o].ai.se.state = LEG_WAIT;
g_pSound->playStereofromCoord(SOUND_FOOTSLAM, PLAY_NOW, objects[o].scrx);
g_pSound->playStereofromCoord(SOUND_FOOTSLAM, PLAY_NOW, objects[o].x);
}
else
{
@@ -1065,7 +999,7 @@ int x,y;
int newobject;
if (objects[o].needinit)
{
objects[o].sprite = BlankSprite;
objects[o].sprite = BLANKSPRITE;
objects[o].ai.se.counter = 0;
objects[o].ai.se.timer = 0;
objects[o].needinit = 0;
@@ -1073,8 +1007,8 @@ int newobject;
if (!objects[o].ai.se.timer)
{
x = rand()%((MORTIMER_MACHINE_XEND*16)-(MORTIMER_MACHINE_XSTART*16))+(MORTIMER_MACHINE_XSTART*16);
y = rand()%((MORTIMER_MACHINE_YENDNOLEGS*16)-(MORTIMER_MACHINE_YSTART*16))+(MORTIMER_MACHINE_YSTART*16);
x = rnd()%((MORTIMER_MACHINE_XEND*16)-(MORTIMER_MACHINE_XSTART*16))+(MORTIMER_MACHINE_XSTART*16);
y = rnd()%((MORTIMER_MACHINE_YENDNOLEGS*16)-(MORTIMER_MACHINE_YSTART*16))+(MORTIMER_MACHINE_YSTART*16);
// spawn a ZAP! or a ZOT!
newobject = spawn_object(x<<CSF, y<<CSF, OBJ_RAY);
@@ -1086,7 +1020,7 @@ int newobject;
if (objects[o].ai.se.counter > NUM_RANDOM_ZAPS)
{
set_mortimer_surprised(0);
objects[o].exists = 0;
delete_object(o);
}
else objects[o].ai.se.counter++;
}
@@ -1106,23 +1040,17 @@ void set_mortimer_surprised(int yes)
if (mortimer_surprisedcount)
{
//12,6 -> 610 -- give mortimer his "surprised" face
map_chgtile(12,6,610);
map_deanimate(12,6);
// deanimate mortimer's hands
map_chgtile(11,6,613);
map_deanimate(11,6);
map_chgtile(13,6,615);
map_deanimate(13,6);
//12,6 -> 610 -- give mortimer his "surprised" face
map_chgtile(12,6,610);
// deanimate mortimer's hands
map_chgtile(11,6,613); map_deanimate(11,6);
map_chgtile(13,6,615); map_deanimate(13,6);
}
else
{
// give mortimer his normal face
map_chgtile(12,6,607);
map_animate(12,6);
// reanimate things
map_animate(11,6);
map_chgtile(13,6,616);
map_animate(13,6);
// give mortimer his normal face again
map_chgtile(12,6,607);
map_chgtile(11,6,613);
map_chgtile(13,6,616);
}
}

60
src/ai/se.h Normal file
View File

@@ -0,0 +1,60 @@
/*
* se.h
*
* Created on: 06.08.2009
* Author: gerstrong
*/
#ifndef SE_H_
#define SE_H_
/* located in game.c */
//----------------------[referenced from ai/se.c]--------------------//
void kill_all_intersecting_tile(int mpx, int mpy);
void delete_object(int o);
void killplayer(int theplayer);
unsigned char spawn_object(int x, int y, int otype);
/* located in map.c */
//----------------------[referenced from ai/se.c]--------------------//
unsigned int getmaptileat(unsigned int x, unsigned int y);
void map_chgtile(unsigned int x,unsigned int y, int newtile);
void map_deanimate(int x, int y);
//----------------------[referenced from ai/se.c]--------------------//
//void fade(uchar type, uchar rate);
/* located in misc.c */
//----------------------[referenced from ai/se.c]--------------------//
uint rnd(void);
/* located in cinematics/blowupworld.c */
//----------------------[referenced from ai/se.c]--------------------//
void SetVibrateTime(int vibetime, char pausegame, stLevelControl *levelcontrol);
/* located in ai/se.c */
//----------------------[referenced from ai/se.c]--------------------//
void se_ai(int o);
void se_extend_plat(int o, bool *p_PlatExtending);
void se_retract_plat(int o, bool *p_PlatExtending);
void spark_ai(int o, int *p_sparks_left);
void se_ankhshield(int o, int episode);
void se_mortimer_arm(int o);
void se_mortimer_spark(int o, stLevelControl *p_levelcontrol);
void se_mortimer_heart(int o, stLevelControl *p_levelcontrol);
void se_mortimer_zapsup(int o, stLevelControl *levelcontrol);
void se_mortimer_leg_left(int o);
void se_mortimer_leg_right(int o);
void se_mortimer_randomzaps(int o);
void set_mortimer_surprised(int yes);
#endif /* SE_H_ */

View File

@@ -1,5 +1,5 @@
void killplayer(int theplayer);
char spawn_object(int x, int y, int otype);
unsigned char spawn_object(int x, int y, int otype);
unsigned int getmaptileat(unsigned int x, unsigned int y);

View File

@@ -0,0 +1,283 @@
/*
* blowupworld.cpp
*
* Created on: 06.08.2009
* Author: Caitlin Shaw
* Ported by: Gerstrong
*/
// cinematic of what happens when you hit the on switch on a tantalus ray
// (episode 2)
#include "../keen.h"
#define VIBRATE_MINSTRENGTH 1
#define VIBRATE_MORTIMERSTRENGTH 4
#define VIBRATE_MAXSTRENGTH 16
#define VIBRATE_GETWORSETIME 150
int vibe_xamt, vibe_yamt, vibe_xdir, vibe_ydir;
int vibe_strength, vibe_getworsetimer;
void SetVibrateTime(int vibetime, char pausegame, stLevelControl *levelcontrol)
{
vibe_xamt = vibe_yamt = 0;
if (levelcontrol->episode==3)
vibe_strength = VIBRATE_MORTIMERSTRENGTH;
else
vibe_strength = VIBRATE_MINSTRENGTH;
vibe_getworsetimer = 0;
levelcontrol->vibratetime = vibetime;
levelcontrol->vibratepause = pausegame;
}
/*void static vibescroller(void)
{
int i;
// scroll the map to make it look like it's vibrating
if (vibe_xdir)
for(i=0;i<vibe_xamt;i++) map_scroll_right();
else
for(i=0;i<vibe_xamt;i++) map_scroll_left();
if (vibe_ydir)
for(i=0;i<vibe_yamt;i++) map_scroll_down();
else
for(i=0;i<vibe_yamt;i++) map_scroll_up();
}
// makes the map vibrate like an earthquake
void do_vibration(void)
{
if (Menu_IsVisible()) return;
// undo the scroll from last time
vibe_xdir ^= 1; vibe_ydir ^= 1;
vibescroller();
levelcontrol.vibratetime--;
if (levelcontrol.vibratetime)
{
// randomize a new amount to offset this frame
vibe_xamt = (rnd() % vibe_strength);
vibe_yamt = (rnd() % vibe_strength);
vibe_xdir = rnd() & 1;
vibe_ydir = rnd() & 1;
vibescroller();
if (++vibe_getworsetimer > VIBRATE_GETWORSETIME)
{
vibe_getworsetimer = 0;
if (vibe_strength < VIBRATE_MAXSTRENGTH) vibe_strength++;
}
}
else // vibration is over, blow up the world
{
if (levelcontrol.episode==2) // vibration also used in ep3 end level
{
dispmsgstring("EP2_UhOhString", 1);
message_SetDismissalCallback(blow_up_world);
}
}
}
void blow_up_world(void) { endlevel(HIT_TANTALUS_SWITCH); }
// start x,y map scroll position
#define TANTALUS_X 0
#define TANTALUS_Y 0
#define TANTALUS_SPRITE 58
#define SHOT_SPD_X (21*1.5)
#define SHOT_SPD_Y (9*1.5)
int shot_x, shot_y, shot_obj, shot_frame, shot_frametimer;
int fire_timer;
char tant_hitearth;
void seq_tantalus_start(void)
{
int i;
int x,y;
lprintf(">seq_tantalus_start()\n");
overlay.tantalus = 1;
sound_stop_all();
initgame();
showmapatpos(81, TANTALUS_X, TANTALUS_Y);
AllPlayersInvisible();
// there are no objects in this scene
for(i=0;i<MAX_OBJECTS;i++) delete_object(i);
// place keen next to his ship
numplayers = 1;
objects[player[0].useObject].exists = 1;
highest_objslot = player[0].useObject+1;
// place the player (which is actually the tantalus ray) at the mouth
// of the vorticon mothership
if (map_findtile(593, &x, &y))
{ // found the tile
shot_x = ((x<<4)-1)<<CSF;
shot_y = ((y<<4)-0)<<CSF;
shot_frame = 0;
shot_frametimer = 0;
}
else
{
crash("seq_tantalus_start(): unable to find tile 593.");
return;
}
player[0].x = shot_x;
player[0].y = shot_y;
fire_timer = 300;
tant_hitearth = 0;
levelcontrol.dontscroll = 1;
fade(FADE_IN, FADE_NORM);
}
void seq_tantalus_run(void)
{
player[0].hideplayer = 1;
if (!levelcontrol.gameover)
{
if (!tant_hitearth)
{
tant_moveshot();
}
else
{
tant_earthexplode();
}
}
}
int timer, spawnedcount;
void static tant_moveshot(void)
{
int tl;
levelcontrol.dontscroll = 0;
player[0].x = shot_x;
player[0].y = shot_y;
if (fire_timer > 0)
{
fire_timer--;
if (!fire_timer)
{
shot_obj = spawn_object(shot_x, shot_y, OBJ_RAY);
objects[shot_obj].onscreen = 1;
sound_play(SOUND_KEEN_FIRE, PLAY_FORCE);
}
else return;
}
objects[shot_obj].sprite = TANTALUS_SPRITE + shot_frame;
if (++shot_frametimer > 45)
{
shot_frametimer = 0;
shot_frame ^= 1;
}
objects[shot_obj].x = shot_x;
objects[shot_obj].y = shot_y;
tl = getmaptileat((shot_x>>CSF)+(sprites[TANTALUS_SPRITE].xsize/2), \
(shot_y>>CSF)+(sprites[TANTALUS_SPRITE].ysize/2));
if (tl==586)
{ // it hit center of earth
tant_hitearth = 1;
delete_object(shot_obj);
srnd(300);
spawn_object(shot_x, shot_y, OBJ_EXPLOSION);
sound_play(SOUND_EARTHPOW, PLAY_NOW);
timer = spawnedcount = 0;
}
else
{
shot_x += SHOT_SPD_X;
shot_y += SHOT_SPD_Y;
}
}
#define EARTHCHUNK_BIG_UP 64
#define EARTHCHUNK_BIG_DN 66
#define EARTHCHUNK_SMALL_UP 68
#define EARTHCHUNK_SMALL_DN 70
void tant_earthexplode(void)
{
int i,o;
gamedo_enemyai();
if (!timer)
{
if (spawnedcount<16)
o = spawn_object(shot_x+((rnd()%32)<<CSF), shot_y+((rnd()%32)<<CSF)-(8<<CSF), OBJ_EXPLOSION);
switch(spawnedcount)
{
case 0: o = spawn_object(shot_x-(8<<CSF), shot_y-(8<<CSF), OBJ_EXPLOSION); break;
case 1: o = spawn_object(shot_x+(24<<CSF), shot_y+(4<<CSF), OBJ_EXPLOSION); break;
case 2: o = spawn_object(shot_x+(16<<CSF), shot_y-(8<<CSF), OBJ_EXPLOSION); break;
case 3: o = spawn_object(shot_x+(24<<CSF), shot_y+(16<<CSF), OBJ_EXPLOSION); break;
case 4: o = spawn_object(shot_x-(8<<CSF), shot_y+(4<<CSF), OBJ_EXPLOSION); break;
case 5:
o = spawn_object(shot_x-(8<<CSF), shot_y+(16<<CSF), OBJ_EXPLOSION);
// spawn a bunch of small fragments of the earth to go flying off
// spawn small earth chunks in all possible directions
// (upleft/upright/dnleft/dnright)
// up/left/down/right
for(i=0;i<=9;i++)
{
o = spawn_object(shot_x+(14<<CSF), shot_y, OBJ_EARTHCHUNK);
objects[o].ai.ray.direction = i;
if (i > 4)
{
objects[o].sprite = EARTHCHUNK_SMALL_DN;
}
else
{
objects[o].sprite = EARTHCHUNK_SMALL_UP;
}
}
break;
case 6:
o = spawn_object(shot_x+(16<<CSF), shot_y+(16<<CSF), OBJ_EXPLOSION);
break;
case 7: o = spawn_object(shot_x+(24<<CSF), shot_y-(8<<CSF), OBJ_EXPLOSION); break;
case 8: o = spawn_object(shot_x+(16<<CSF), shot_y+(4<<CSF), OBJ_EXPLOSION); break;
case 10:
// spawn four big fragments of the earth to go flying off
o = spawn_object(shot_x+(8<<CSF), shot_y, OBJ_EARTHCHUNK);
objects[o].sprite = EARTHCHUNK_BIG_UP;
objects[o].ai.ray.direction = EC_UPLEFT;
o = spawn_object(shot_x+(8<<CSF), shot_y, OBJ_EARTHCHUNK);
objects[o].sprite = EARTHCHUNK_BIG_UP;
objects[o].ai.ray.direction = EC_UPRIGHT;
o = spawn_object(shot_x+(8<<CSF), shot_y, OBJ_EARTHCHUNK);
objects[o].sprite = EARTHCHUNK_BIG_DN;
objects[o].ai.ray.direction = EC_DOWNRIGHT;
o = spawn_object(shot_x+(8<<CSF), shot_y, OBJ_EARTHCHUNK);
objects[o].sprite = EARTHCHUNK_BIG_DN;
objects[o].ai.ray.direction = EC_DOWNLEFT;
break;
case 32:
sound_play(SOUND_GAME_OVER, PLAY_NOW);
SetGameOver();
break;
}
spawnedcount++;
timer = 60;
}
else timer--;
}*/

View File

@@ -325,11 +325,9 @@ int o,x;
// foob (ep3)
if (pCKP->Control.levelcontrol.episode==1)
{
o = spawn_object((((curmapx+1)<<4)+4)<<CSF, ((curmapy<<4)-4)<<CSF, OBJ_SECTOREFFECTOR);
objects[o].ai.se.type = SE_ICECANNON;
objects[o].ai.se.dir = DUPRIGHT;
objects[o].inhibitfall = 1;
objects[o].hasbeenonscreen = 1;
o = spawn_object((((curmapx+1)<<4)+4)<<CSF, ((curmapy<<4)-4)<<CSF, OBJ_ICECANNON);
objects[o].ai.icechunk.vector_x = 1;
objects[o].ai.icechunk.vector_y = -1;
}
else if (pCKP->Control.levelcontrol.episode==2)
{
@@ -343,11 +341,10 @@ int o,x;
case 7: // spark (ep2) ball (ep3)
if (pCKP->Control.levelcontrol.episode==2)
{
o = spawn_object(curmapx<<4<<CSF,curmapy<<4<<CSF,OBJ_SECTOREFFECTOR);
objects[o].ai.se.type = SE_SPARK;
o = spawn_object(curmapx<<4<<CSF,curmapy<<4<<CSF,OBJ_SPARK);
pCKP->Control.levelcontrol.canexit = 0; // can't exit till spark is shot
}
else
else if (pCKP->Control.levelcontrol.episode==3)
{
o = spawn_object(curmapx<<4<<CSF,curmapy<<4<<CSF,OBJ_BALL);
objects[o].hasbeenonscreen = 1;
@@ -363,12 +360,9 @@ int o,x;
case 9: // up-left-flying ice chunk (ep1) horiz platform (ep3)
if (pCKP->Control.levelcontrol.episode==1)
{
o = spawn_object(((curmapx<<4)-4)<<CSF, ((curmapy<<4)-4)<<CSF, OBJ_SECTOREFFECTOR);
// objects[o].ai.icechunk.movedir = DUPLEFT;
objects[o].ai.se.type = SE_ICECANNON;
objects[o].ai.se.dir = DUPLEFT;
objects[o].inhibitfall = 1;
objects[o].hasbeenonscreen = 1;
o = spawn_object(((curmapx<<4)-4)<<CSF, ((curmapy<<4)-4)<<CSF, OBJ_ICECANNON);
objects[o].ai.icechunk.vector_x = -1;
objects[o].ai.icechunk.vector_y = -1;
}
else if (pCKP->Control.levelcontrol.episode==3)
{
@@ -406,7 +400,7 @@ int o,x;
if (pCKP->Control.levelcontrol.episode==3)
{
o = spawn_object(curmapx<<4<<CSF, curmapy<<4<<CSF, OBJ_SECTOREFFECTOR);
objects[o].ai.se.type = SE_GUN_RIGHT;
//objects[o].ai.se.type = SE_GUN_RIGHT;
objects[o].hasbeenonscreen = 1;
}
break;
@@ -414,7 +408,7 @@ int o,x;
if (pCKP->Control.levelcontrol.episode==3)
{
o = spawn_object(curmapx<<4<<CSF, curmapy<<4<<CSF, OBJ_SECTOREFFECTOR);
objects[o].ai.se.type = SE_GUN_VERT;
//objects[o].ai.se.type = SE_GUN_VERT;
objects[o].hasbeenonscreen = 1;
}
break;

View File

@@ -22,7 +22,7 @@ void scrolltest(void);
void give_keycard(int doortile, int p);
void take_keycard(int doortile, int p);
void extralifeat(int p);
char spawn_object(int x, int y, int otype);
unsigned char spawn_object(int x, int y, int otype);
void common_enemy_ai(int o);
char hitdetect(int object1, int object2);
void freezeplayer(int theplayer);

View File

@@ -612,7 +612,7 @@ int initgamefirsttime(stCloneKeenPlus *pCKP, int s)
return 0;
}
char spawn_object(int x, int y, int otype)
unsigned char spawn_object(int x, int y, int otype)
{
int i;
// find an unused object slot
@@ -643,7 +643,6 @@ int i;
}
}
// object could not be created
//crash("Object of type %d could not be created at %d,%d (out of object slots)",otype,x,y);
g_pLogFile->ftextOut("Object of type %d could not be created at %d,%d (out of object slots)<br>",otype,x,y);
return 0;
}
@@ -681,10 +680,26 @@ int i;
}
}
// anything (players/enemies) occupying the map tile at [mpx,mpy] is killed
/*void kill_all_intersecting_tile(int mpx, int mpy)
void killobject(int o)
{
int xpix,ypix;
if (objects[o].exists)
{
if (objects[o].type==OBJ_PLAYER)
{
killplayer(o);
}
else
{
if (objects[o].zapped < 500 && objects[o].canbezapped)
objects[o].zapped += 500;
}
}
}
// anything (players/enemies) occupying the map tile at [mpx,mpy] is killed
void kill_all_intersecting_tile(int mpx, int mpy)
{
unsigned int xpix,ypix;
int i;
xpix = mpx<<TILE_S<<CSF;
ypix = mpy<<TILE_S<<CSF;
@@ -701,7 +716,7 @@ int i;
}
}
}
}*/
}
// returns whether pix position x,y is a stop point for object o.
// stop points are invisible blockers that act solid only to certain
@@ -845,7 +860,7 @@ void PlayerTouchedExit(int theplayer, stCloneKeenPlus *pCKP)
}
}
void endlevel(int success, stCloneKeenPlus *pCKP)
void endlevel(int reason_for_leaving, stLevelControl *levelcontrol)
{
if (fade.mode == NO_FADE)
{
@@ -854,8 +869,8 @@ void endlevel(int success, stCloneKeenPlus *pCKP)
fade.fadetimer = 0;
fade.rate = FADE_NORM;
fade.mode = FADE_GO;
pCKP->Control.levelcontrol.success = success;
pCKP->Control.levelcontrol.tobonuslevel = 0;
levelcontrol->success = reason_for_leaving;
levelcontrol->tobonuslevel = 0;
}
}
@@ -1211,27 +1226,31 @@ void procgoodie(int t, int mpx, int mpy, int theplayer, stCloneKeenPlus *pCKP)
case 11:
player[theplayer].inventory.HasJoystick = 1;
pCKP->Control.levelcontrol.canexit = 1;
g_pSound->playSound(SOUND_GET_PART, PLAY_NOW);
break;
case 12:
player[theplayer].inventory.HasBattery = 1;
pCKP->Control.levelcontrol.canexit = 1;
g_pSound->playSound(SOUND_GET_PART, PLAY_NOW);
break;
case 13:
player[theplayer].inventory.HasVacuum = 1;
pCKP->Control.levelcontrol.canexit = 1;
g_pSound->playSound(SOUND_GET_PART, PLAY_NOW);
break;
case 14:
player[theplayer].inventory.HasFuel = 1;
pCKP->Control.levelcontrol.canexit = 1;
g_pSound->playSound(SOUND_GET_PART, PLAY_NOW);
break;
// in-level teleporter
// (in level13.ck1 that takes you to the bonus level)
case 24:
endlevel(0, pCKP);
endlevel(0, &(pCKP->Control.levelcontrol) );
pCKP->Control.levelcontrol.tobonuslevel = 1;
break;

View File

@@ -14,6 +14,7 @@
#include "sdl/CTimer.h"
#include "sdl/CInput.h"
#include "sdl/sound/CSound.h"
#include "CLogFile.h"
#include "CGraphics.h"
#include "externals.h"
#include "StringUtils.h"
@@ -69,7 +70,7 @@ unsigned int msb, lsb;
if (byt & 32)player[0].playcontrol[PA_STATUS] = 1;
if (byt & 64)
{ // demo STOP command
if (fade.mode!=FADE_GO) endlevel(1, pCKP);
if (fade.mode!=FADE_GO) endlevel(1, &(pCKP->Control.levelcontrol) );
}
}
else
@@ -83,12 +84,12 @@ unsigned int msb, lsb;
{
if (g_pInput->getPressedKey(i))
{
if (fade.mode!=FADE_GO) endlevel(0, pCKP);
if (fade.mode!=FADE_GO) endlevel(0, &(pCKP->Control.levelcontrol) );
}
}
if (g_pInput->getPressedCommand(IC_STATUS))
{
if (fade.mode!=FADE_GO) endlevel(0, pCKP);
if (fade.mode!=FADE_GO) endlevel(0, &(pCKP->Control.levelcontrol) );
}
return;
@@ -262,7 +263,7 @@ int i, topobj;
case OBJ_TANK: tank_ai(i, pCKP->Control.levelcontrol.hardmode); break;
case OBJ_RAY: ray_ai(i, pCKP, pCKP->Control.levelcontrol); break;
case OBJ_DOOR: door_ai(i, pCKP->Control.levelcontrol.cepvars.DoorOpenDir); break;
//case OBJ_ICECANNON: icecannon_ai(i); break; TODO: Add this AI
case OBJ_ICECANNON: icecannon_ai(i); break;
case OBJ_ICECHUNK: icechunk_ai(i); break;
case OBJ_ICEBIT: icebit_ai(i); break;
case OBJ_TELEPORTER: teleporter_ai(i, pCKP->Control.levelcontrol); break;
@@ -277,7 +278,7 @@ int i, topobj;
pCKP->Control.levelcontrol.hardmode); break;
case OBJ_EXPLOSION: explosion_ai(i); break;
case OBJ_EARTHCHUNK: earthchunk_ai(i); break;
//case OBJ_SPARK: spark_ai(i); break; TODO: Add this AI
case OBJ_SPARK: spark_ai(i, &(pCKP->Control.levelcontrol.sparks_left) ); break;
//KEEN3
case OBJ_FOOB: foob_ai(i, pCKP); break;
case OBJ_NINJA: ninja_ai(i, pCKP); break;
@@ -296,6 +297,7 @@ int i, topobj;
case OBJ_DEMOMSG: break;
default:
//crash("gamedo_enemy_ai: Object %d is of invalid type %d\n", i, objects[i].type);
g_pLogFile->ftextOut("gamedo_enemy_ai: Object %d is of invalid type %d\n", i, objects[i].type);
break;
}
@@ -819,7 +821,7 @@ int i;
// F9 - exit level immediately
if(g_pInput->getPressedKey(KF9))
{
endlevel(1, pCKP);
endlevel(1, &(pCKP->Control.levelcontrol) );
}
// F6 - onscreen debug--toggle through debug/radar/off
if(g_pInput->getPressedKey(KF6))

View File

@@ -165,7 +165,7 @@ void gamepdo_dieanim(int cp, stCloneKeenPlus *pCKP)
}
else
{
endlevel(0,pCKP);
endlevel(0,&(pCKP->Control.levelcontrol));
}
}
}
@@ -243,7 +243,7 @@ void gamepdo_ProcessInput(unsigned int cp, stCloneKeenPlus *pCKP)
if (p_levelcontrol->level_done != LEVEL_DONE_FADEOUT)
{
p_levelcontrol->level_done = LEVEL_DONE_FADEOUT;
endlevel(1, pCKP);
endlevel(1, &(pCKP->Control.levelcontrol));
}
}
else if (p_levelcontrol->level_done_timer > LEVEL_DONE_STOPWALKING_TIME)

View File

@@ -315,7 +315,7 @@ p_levelcontrol = &(pCKP->Control.levelcontrol);
default: // a regular level
p_levelcontrol->chglevelto = (lvl & 0x7fff);
endlevel(1, pCKP);
endlevel(1, &(pCKP->Control.levelcontrol));
g_pMusicPlayer->stop();
g_pSound->playStereofromCoord(SOUND_ENTER_LEVEL, PLAY_NOW, objects[player[cp].useObject].scrx);

View File

@@ -63,7 +63,21 @@ struct stLevelControl
unsigned int level_done, level_done_timer;
unsigned int level_finished_by; // index of player that finished level
unsigned int exitXpos;
// for ep2: how many sparks (tantalus ray machines) are left
// you must destroy the tantalus ray generator before exiting
int sparks_left;
// if 1, a moving platform is currently extending/retracting (ep2)
bool PlatExtending;
// if > 0, the screen will shake and it will decrement each frame.
// used when you push a switch on a tantalus ray (ep2), and Mortimer's machine
int vibratetime;
// if 1, then while vibrating the game will be paused
char vibratepause;
// as long as we only have POD
stLevelControl() { memset(this, 0, sizeof(stLevelControl)); }

View File

@@ -15,6 +15,7 @@ void tank_ai(int o, bool hardmode);
void ray_ai(int o, stCloneKeenPlus *pCKP, stLevelControl levelcontrol);
void icechunk_ai(int o);
void icebit_ai(int o);
void icecannon_ai(int o);
void door_ai(int o, char DoorOpenDir);
void teleporter_ai(int o, stLevelControl levelcontrol);
void rope_ai(int o);
@@ -26,8 +27,9 @@ void vortelite_ai(int o, bool darkness);
void se_ai(int o, stCloneKeenPlus *pCKP);
void explosion_ai(int o);
void earthchunk_ai(int o);
void spark_ai(int o, int *p_sparks_left);
// ep3
void foob_ai(int o, stCloneKeenPlus *pCKP);
void foob_ai(int o, bool hardmode);
void ninja_ai(int o, stCloneKeenPlus *pCKP);
void meep_ai(int o, stLevelControl levelcontrol);
void sndwave_ai(int o, stCloneKeenPlus *pCKP);

View File

@@ -1,10 +1,13 @@
// various states we go through when a level is completed
// to do the walking out the exit door animation
#define LEVEL_NOT_DONE 0 // not completed
#define LEVEL_DONE_WALK 1 // walking through exit door
#define LEVEL_DONE_WAIT 2 // finished walk through door, wait a bit
#define LEVEL_DONE_FADEOUT 3 // fading out
#define LEVEL_COMPLETE 4 // on to the next level!
enum levelstate
{
LEVEL_NOT_DONE, // not completed
LEVEL_DONE_WALK, // walking through exit door
LEVEL_DONE_WAIT, // finished walk through door, wait a bit
LEVEL_DONE_FADEOUT, // fading out
LEVEL_COMPLETE // on to the next level!
};
// width of the player sprite, used for walking "behind" the exit door frame
#define PLAYERSPRITE_WIDTH 16
@@ -34,10 +37,12 @@
#define ICECANNON_FIRE_FREQ 400
// direction defines used for various things
#define RIGHT 0
#define LEFT 1
#define UP 2
#define DOWN 3
enum directions{
RIGHT,
LEFT,
UP,
DOWN
};
#define ANKH_SHIELD_FRAME 61
@@ -191,10 +196,43 @@
#define DOOR_GREEN 4
#define DOOR_BLUE 5
#define DOOR_RED_SPRITE (MAX_SPRITES-5)
#define DOOR_GREEN_SPRITE (MAX_SPRITES-4)
#define DOOR_BLUE_SPRITE (MAX_SPRITES-3)
#define DOOR_YELLOW_SPRITE (MAX_SPRITES-2)
// special sprites (they either weren't in the game originally,
// or are used for internal engine stuff).
#define BLANKSPRITE (MAX_SPRITES-1)
#define DOOR_YELLOW_SPRITE (MAX_SPRITES-2) // opening door (yellow)
#define DOOR_BLUE_SPRITE (MAX_SPRITES-3)
#define DOOR_GREEN_SPRITE (MAX_SPRITES-4)
#define DOOR_RED_SPRITE (MAX_SPRITES-5)
#define PT5000_SPRITE (MAX_SPRITES-6) // rising bonus pts (+5000)
#define PT1000_SPRITE (MAX_SPRITES-7)
#define PT500_SPRITE (MAX_SPRITES-8)
#define PT200_SPRITE (MAX_SPRITES-9)
#define PT100_SPRITE (MAX_SPRITES-10)
#define PT1UP_SPRITE (MAX_SPRITES-11) // rising 1up bonus
#define PTCARDY_SPRITE (MAX_SPRITES-12) // rising access card
#define PTCARDR_SPRITE (MAX_SPRITES-13)
#define PTCARDG_SPRITE (MAX_SPRITES-14)
#define PTCARDB_SPRITE (MAX_SPRITES-15)
#define SHOTUP_SPRITE (MAX_SPRITES-16) // rising single shot (ep3)
#define GUNUP_SPRITE (MAX_SPRITES-17) // rising ray gun
#define YORPSHIELD_SPRITE (MAX_SPRITES-18) // invincibility force field, used in editor and in "yorps have forcefields" mode
#define VERSION_SPRITE (MAX_SPRITES-19) // version text shown in lower-right corner at startup
#define DEMOBOX_SPRITE (MAX_SPRITES-20) // says "Demo"
#define OSD_LIVES_SPRITE (MAX_SPRITES-21)
#define OSD_AMMO_SPRITE (MAX_SPRITES-22)
#define OSD_YORPS_SPRITE (MAX_SPRITES-23)
#define TITLE_LOGO1_SPRITE (MAX_SPRITES-24) // left half of the logo
#define TITLE_LOGO2_SPRITE (MAX_SPRITES-25) // right half of the logo
#define TITLE_FLOOR_SPRITE (MAX_SPRITES-26) // more stuff for the logo
#define TITLE_VORT_SPRITE (MAX_SPRITES-27)
#define ARROWLR_SPRITE (MAX_SPRITES-28) // these are directional arrows used in the editor
#define ARROWUD_SPRITE (MAX_SPRITES-29)
#define ARROWUR_SPRITE (MAX_SPRITES-30)
#define ARROWUL_SPRITE (MAX_SPRITES-31)
#define ARROWU_SPRITE (MAX_SPRITES-32)
#define ARROWD_SPRITE (MAX_SPRITES-33)
#define LAST_SPECIAL_SPRITE (MAX_SPRITES-34)
#define YORPSTATUEHEAD 22
#define YORPSTATUEHEADUSED 485
#define YORPSTATUEBOTTOM 22
@@ -224,7 +262,7 @@ void open_door(int doortile, int doorsprite, int mpx, int mpy, int cp, stCloneKe
void killplayer(int theplayer);
void PlayerTouchedExit(int theplayer, stCloneKeenPlus *pCKP);
void endlevel(int success, stCloneKeenPlus *pCKP);
void endlevel(int reason_for_leaving, stLevelControl *levelcontrol);
void SetGameOver(stCloneKeenPlus *pCKP);
char checkissolidl(int x, int y, int cp, stCloneKeenPlus *pCKP);

View File

@@ -30,7 +30,7 @@
#define WM_MAP_NUM 80
#define MAX_SPRITES 300
#define MAX_SPRITES 500
#define MAX_FONT 256
#define MAX_BITMAPS 20
@@ -89,6 +89,8 @@ typedef struct stFade
#define WORLD_MAP 80
#define FINAL_MAP 16
// values returned by gameloop()
#define LVLC_NOCOMMAND 0
#define LVLC_CHANGE_LEVEL 1
#define LVLC_END_SEQUENCE 2
@@ -96,6 +98,8 @@ typedef struct stFade
#define LVLC_TANTALUS_RAY 4 // switch on tantalus ray pressed
#define LVLC_START_LEVEL 5
#define WON_LEVEL LVLC_CHANGE_LEVEL
typedef struct stMap
{
@@ -157,297 +161,8 @@ struct stString
unsigned int attrvalues[MAX_ATTRIBUTES+1];
};
/* Structs used for different enemies data, these are in a union */
struct stYorpData
{
unsigned char state;
unsigned char looktimes,lookposition;
unsigned char timer, dietimer;
unsigned char walkframe;
unsigned int dist_traveled;
signed int yorpdie_inertia_y;
unsigned char movedir;
};
struct stGargData
{
unsigned char state;
unsigned char looktimes,lookframe;
unsigned char timer, dietimer, keenonsameleveltimer;
unsigned char about_to_charge;
unsigned char walkframe;
unsigned int dist_traveled;
signed int gargdie_inertia_y;
unsigned char movedir;
unsigned char detectedPlayer, detectedPlayerIndex;
};
struct stVortData
{
unsigned char state;
unsigned char timer,timer2;
unsigned int animtimer;
unsigned char palflashtimer, palflashamt;
unsigned char frame;
unsigned int dist_traveled;
signed int inertiay;
char ep1style; // episode 1 style four-shots-to-kill
unsigned char movedir;
// these hold the animation frames indexes since they're
// different for each episode
int WalkLeftFrame;
int WalkRightFrame;
int LookFrame;
int JumpRightFrame;
int JumpLeftFrame;
int DyingFrame;
int DeadFrame;
};
struct stVortEliteData
{
unsigned char state;
unsigned char timer,timer2;
unsigned int animtimer;
unsigned char frame;
signed int inertiay;
unsigned char movedir;
unsigned int timesincefire;
unsigned int running;
int dist_traveled;
};
struct stButlerData
{
unsigned char state;
unsigned char timer,animtimer;
unsigned char frame;
unsigned int dist_traveled;
unsigned char movedir;
};
struct stTankData
{
unsigned char state;
unsigned char timer,animtimer;
unsigned char frame;
unsigned int dist_traveled;
unsigned char movedir;
int ponsameleveltime;
unsigned char alreadyfiredcauseonsamelevel;
unsigned char fireafterlook;
unsigned char detectedPlayer; // 1 if player on same level
unsigned char detectedPlayerIndex; // index of player that was detected
// for tank2
unsigned int timetillnextshot;
unsigned int firetimes;
unsigned int timetillcanfire;
unsigned int timetillcanfirecauseonsamelevel;
};
struct stRayData
{
char state;
char direction;
char zapzottimer;
char dontHitEnable;
unsigned int dontHit; // index of an object type ray will not harm
// for soundwave
int animframe, animtimer;
int offscreentime;
// for earth chunks
int baseframe;
};
struct stDoorData
{
char timer;
char distance_traveled;
};
struct stIceChunk
{
char movedir;
char state;
unsigned int originalX, originalY;
int timer;
};
struct stTeleportData
{
char animtimer;
char animframe;
char numframechanges;
char direction;
int whichplayer;
unsigned int destx;
signed int desty;
int baseframe;
int idleframe;
char NoExitingTeleporter;
char snap;
char fadeamt;
char fadetimer;
};
struct stRopeData
{
char state;
int droptimer;
int droptimes;
int stoneX, stoneY;
int vortboss;
};
struct stWalkerData
{
unsigned char state;
unsigned char animtimer, dietimer;
unsigned char walkframe;
signed int walkerdie_inertia_y;
int fallinctimer,fallspeed;
unsigned char walkdir;
unsigned char kickedplayer[MAX_PLAYERS];
};
struct stPlatformData
{
unsigned char state;
unsigned char animframe;
unsigned int animtimer;
unsigned int waittimer;
unsigned char movedir;
unsigned char kickedplayer[MAX_PLAYERS];
};
struct stSEData
{
unsigned int type;
unsigned char state;
unsigned int timer;
unsigned int platx, platy;
unsigned int bgtile;
unsigned int dir;
int counter,destroytiles;
unsigned int frame;
int mx,my;
int blowx,blowy;
};
struct stBabyData
{
char state;
char dir;
signed int inertia_x, inertia_y;
int jumpdectimer, xdectimer;
int jumpdecrate;
int dietimer;
char walkframe;
int walktimer;
};
struct stFoobData
{
char state;
char dir;
int animframe, animtimer;
int OnSameLevelTime;
int OffOfSameLevelTime;
int spooktimer;
int SpookedByWho;
};
struct stNinjaData
{
char state;
char dir;
int animframe, animtimer;
unsigned int timetillkick;
signed int XInertia, YInertia;
unsigned int XFrictionTimer, YFrictionTimer;
unsigned int XFrictionRate, YFrictionRate;
int KickMoveTimer;
int isdying;
int dietimer;
};
typedef struct stMotherData
{
char state;
char dir;
char hittimes;
int animframe, animtimer;
int timer;
} stMotherData;
typedef struct stMeepData
{
char state;
char dir;
int animframe, animtimer;
int timer;
} stMeepData;
typedef struct stBallJackData
{
char dir;
int animframe, animtimer;
int speed;
} stBallJackData;
#define NESSIETRAILLEN 5
typedef struct stNessieData
{
char state;
char leftrightdir, updowndir;
unsigned int baseframe;
unsigned int tiletrailX[NESSIETRAILLEN+1];
unsigned int tiletrailY[NESSIETRAILLEN+1];
int tiletrailhead;
char animframe, animtimer;
unsigned int destx, desty;
unsigned int pausetimer;
unsigned int pausex, pausey;
unsigned int mortimer_swim_amt;
unsigned int mounted[MAX_PLAYERS];
} stNessieData;
// structures for each AI module's data
#include "ai/enemydata.h"
// and the object structure containing the union of the above structs
typedef struct stObject
@@ -496,30 +211,30 @@ typedef struct stObject
// what kind of object it is
union ai
{
// ep1
stYorpData yorp;
stGargData garg;
stVortData vort;
stButlerData butler;
stTankData tank;
stRayData ray;
stDoorData door;
stIceChunk icechunk;
stTeleportData teleport;
stRopeData rope;
// ep2
stWalkerData walker;
stPlatformData platform;
stVortEliteData vortelite;
stSEData se;
stBabyData baby;
// ep3
stFoobData foob;
stNinjaData ninja;
stMeepData meep;
stMotherData mother;
stBallJackData bj;
stNessieData nessie;
// ep1
stYorpData yorp;
stGargData garg;
stVortData vort;
stButlerData butler;
stTankData tank;
stRayData ray;
stDoorData door;
stIceChunk icechunk;
stTeleportData teleport;
stRopeData rope;
// ep2
stWalkerData walker;
stPlatformData platform;
stVortEliteData vortelite;
stSEData se;
stBabyData baby;
// ep3
stFoobData foob;
stNinjaData ninja;
stMeepData meep;
stMotherData mother;
stBallJackData bj;
stNessieData nessie;
} ai;
unsigned char erasedata[64][64]; // backbuffer to erase this object
} stObject;
@@ -537,43 +252,56 @@ typedef struct stAnimTile
} stAnimTile;
#define NUM_OBJ_TYPES 40
enum enumerated_Objects{
// ** objects from KEEN1
#define OBJ_YORP 1
#define OBJ_GARG 2
#define OBJ_VORT 3
#define OBJ_BUTLER 4
#define OBJ_TANK 5
#define OBJ_RAY 6 // keen's raygun blast
#define OBJ_DOOR 7 // an opening door
#define OBJ_ICECHUNK 8 // ice chunk from ice cannon
#define OBJ_ICEBIT 9 // piece of shattered ice chunk
#define OBJ_PLAYER 10
#define OBJ_TELEPORTER 11 // world map teleporter
#define OBJ_ROPE 12
OBJ_YORP,
OBJ_GARG,
OBJ_VORT,
OBJ_BUTLER,
OBJ_TANK,
OBJ_RAY, // keen's raygun blast
OBJ_DOOR, // an opening door
OBJ_ICECHUNK, // ice chunk from ice cannon
OBJ_ICEBIT, // piece of shattered ice chunk
OBJ_PLAYER,
OBJ_TELEPORTER, // world map teleporter
OBJ_ROPE,
// ** objects from KEEN2 (some of these are in ep3 as well)
#define OBJ_WALKER 13
#define OBJ_TANKEP2 14
#define OBJ_PLATFORM 15
#define OBJ_VORTELITE 16
#define OBJ_SECTOREFFECTOR 17
#define OBJ_BABY 18
#define OBJ_EXPLOSION 19
#define OBJ_EARTHCHUNK 20
OBJ_WALKER,
OBJ_TANKEP2,
OBJ_PLATFORM,
OBJ_VORTELITE,
OBJ_SECTOREFFECTOR,
OBJ_BABY,
OBJ_EXPLOSION,
OBJ_EARTHCHUNK,
OBJ_SPARK,
// ** objects from KEEN3
#define OBJ_FOOB 21
#define OBJ_NINJA 22
#define OBJ_MEEP 23
#define OBJ_SNDWAVE 24
#define OBJ_MOTHER 25
#define OBJ_FIREBALL 26
#define OBJ_BALL 27
#define OBJ_JACK 28
#define OBJ_PLATVERT 29
#define OBJ_NESSIE 30
OBJ_FOOB,
OBJ_NINJA,
OBJ_MEEP,
OBJ_SNDWAVE,
OBJ_MOTHER,
OBJ_FIREBALL,
OBJ_BALL,
OBJ_JACK,
OBJ_PLATVERT,
OBJ_NESSIE,
#define OBJ_DEMOMSG 31
OBJ_DEMOMSG,
// the guns that shoot periodically
OBJ_AUTORAY,
OBJ_AUTORAY_V,
OBJ_ICECANNON,
OBJ_GOTPOINTS, //this thing is the rising point numbers
OBJ_GHOST, //ghosted object from map editor
LAST_OBJ_TYPE
};
// default sprites...when an object is spawned it's sprite is set to this
// sprite. the object AI will immediately reset the sprite frame, so it
@@ -594,8 +322,9 @@ typedef struct stAnimTile
#define OBJ_RAY_DEFSPRITE_EP3 102
#define OBJ_ICECHUNK_DEFSPRITE 112
#define OBJ_ICEBIT_DEFSPRITE 113
#define OBJ_ROPE_DEFSPRITE 114
#define OBJ_TELEPORTER_DEFSPRITE 180
#define OBJ_ROPE_DEFSPRITE 184
#define OBJ_PLATFORM_DEFSPRITE_EP2 126
#define OBJ_PLATFORM_DEFSPRITE_EP3 107
@@ -615,6 +344,7 @@ typedef struct stAnimTile
#define OBJ_BABY_DEFSPRITE_EP2 52
#define OBJ_BABY_DEFSPRITE_EP3 51
#define OBJ_SPARK_DEFSPRITE_EP2 128
// some directions (mostly for OBJ_ICECHUNK and OBJ_ICEBIT)
#define DUPRIGHT 0
@@ -789,20 +519,18 @@ typedef struct stShipQueue
#define TILE_EXTENDING_PLATFORM 270
// "Sector Effector" types
#define SE_EXTEND_PLATFORM 1
#define SE_RETRACT_PLATFORM 2
#define SE_SPARK 3
#define SE_GUN_VERT 4
#define SE_GUN_RIGHT 5
#define SE_ANKHSHIELD 6
#define SE_ICECANNON 7
#define SE_MORTIMER_ARM 8
#define SE_MORTIMER_LEG_LEFT 9
#define SE_MORTIMER_LEG_RIGHT 10
#define SE_MORTIMER_SPARK 11
#define SE_MORTIMER_HEART 12
#define SE_MORTIMER_ZAPSUP 13
#define SE_MORTIMER_RANDOMZAPS 14
enum sector_effector_type{
SE_EXTEND_PLATFORM,
SE_RETRACT_PLATFORM,
SE_ANKHSHIELD,
SE_MORTIMER_ARM,
SE_MORTIMER_LEG_LEFT,
SE_MORTIMER_LEG_RIGHT,
SE_MORTIMER_SPARK,
SE_MORTIMER_HEART,
SE_MORTIMER_ZAPSUP,
SE_MORTIMER_RANDOMZAPS
};
// animation rate of animated tiles
#define ANIM_TILE_TIME 40

View File

@@ -117,7 +117,7 @@ bool CEGASprit::loadData(const std::string& filename, bool compresseddata)
// TODO: Create surfaces which can be blitted directly to the blit surface or maybe screen.
// load the image data
sprites = new stSprite[301];
sprites = new stSprite[MAX_SPRITES+1];
char c;
for(int p=0 ; p<4 ; p++)
{