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:
@@ -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!
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
800x600x32
|
||||
1024x768x32
|
||||
1280x1024x32
|
||||
1600x1050x32
|
||||
1600x1200x32
|
||||
1680x1050x32
|
||||
1920x1200x32
|
||||
|
||||
340
src/ai/enemydata.h
Normal file
340
src/ai/enemydata.h
Normal 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_ */
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
169
src/ai/icecannon.cpp
Normal 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
18
src/ai/icecannon.h
Normal 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_ */
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
168
src/ai/rope.cpp
168
src/ai/rope.cpp
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
570
src/ai/se.cpp
570
src/ai/se.cpp
@@ -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
60
src/ai/se.h
Normal 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_ */
|
||||
@@ -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);
|
||||
|
||||
|
||||
283
src/cinematics/blowupworld.cpp
Normal file
283
src/cinematics/blowupworld.cpp
Normal 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--;
|
||||
}*/
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
39
src/game.cpp
39
src/game.cpp
@@ -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;
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)); }
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
452
src/keen.h
452
src/keen.h
@@ -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
|
||||
|
||||
@@ -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++)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user