Commit c88e5da7 authored by Gerhard Stein's avatar Gerhard Stein

AI changes to classes

parent 9c078bcd
......@@ -93,9 +93,6 @@ public:
union ai
{
// ep1
stButlerData butler;
stTankData tank;
stDoorData door;
stIceChunk icechunk;
stTeleportData teleport;
stRopeData rope;
......@@ -108,11 +105,9 @@ public:
stBabyData baby;
// ep3
stFoobData foob;
stNinjaData ninja;
stMeepData meep;
stMotherData mother;
stBallJackData bj;
stNessieData nessie;
} ai;
......
// ai for the ball and the jack in ep3
#include "CObjectAI.h"
#include "CBallJack.h"
#include "../../spritedefines.h"
#define BALL_SPEED 120
......@@ -12,147 +12,135 @@ char BJ_BlockedD(int o);
unsigned int rnd(void);
void CObjectAI::ballandjack_ai(CObject &object)
CBallJack::CBallJack()
{
if (object.needinit)
{
unsigned int px = m_Player[0].getXMidPos();
unsigned int py = m_Player[0].getYMidPos();
unsigned int px = m_Player[0].getXMidPos();
unsigned int py = m_Player[0].getYMidPos();
char tempxdir, tempydir;
if(px<object.getXMidPos()) tempxdir=LEFT;
else tempxdir = RIGHT;
char tempxdir, tempydir;
if(px<getXMidPos()) tempxdir=LEFT;
else tempxdir = RIGHT;
if(py<object.getYMidPos()) tempydir=UP;
else tempydir = DOWN;
if(py<getYMidPos()) tempydir=UP;
else tempydir = DOWN;
if (tempxdir == LEFT && tempydir == UP) object.ai.bj.dir = DUPLEFT;
else if (tempxdir == RIGHT && tempydir == UP) object.ai.bj.dir = DUPRIGHT;
else if (tempxdir == LEFT && tempydir == DOWN) object.ai.bj.dir = DDOWNLEFT;
else if (tempxdir == RIGHT && tempydir == DOWN) object.ai.bj.dir = DDOWNRIGHT;
if (tempxdir == LEFT && tempydir == UP) dir = DUPLEFT;
else if (tempxdir == RIGHT && tempydir == UP) dir = DUPRIGHT;
else if (tempxdir == LEFT && tempydir == DOWN) dir = DDOWNLEFT;
else if (tempxdir == RIGHT && tempydir == DOWN) dir = DDOWNRIGHT;
object.ai.bj.animframe = 0;
object.ai.bj.animtimer = 0;
object.inhibitfall = 1;
animframe = 0;
animtimer = 0;
inhibitfall = 1;
if (object.m_type==OBJ_BALL)
{
object.ai.bj.speed = BALL_SPEED;
object.canbezapped = 1;
}
else
{
object.ai.bj.speed = JACK_SPEED;
object.canbezapped = 0;
}
object.checkinitialCollisions();
object.needinit = 0;
if (m_type==OBJ_BALL)
{
speed = BALL_SPEED;
canbezapped = 1;
}
else
{
speed = JACK_SPEED;
canbezapped = 0;
}
checkinitialCollisions();
needinit = 0;
}
if (object.touchPlayer)
void CBallJack::process()
{
if (touchPlayer)
{
if (object.m_type==OBJ_BALL)
if (m_type==OBJ_BALL)
{
if (m_Player[object.touchedBy].getXPosition() < object.getXLeftPos())
if (m_Player[touchedBy].getXPosition() < getXLeftPos())
{
m_Player[object.touchedBy].bump(-BALLPUSHAMOUNT, true);
m_Player[touchedBy].bump(-BALLPUSHAMOUNT, true);
}
else
{
m_Player[object.touchedBy].bump(BALLPUSHAMOUNT, true);
m_Player[touchedBy].bump(BALLPUSHAMOUNT, true);
}
switch(object.ai.bj.dir)
switch(dir)
{
case DUPRIGHT: object.ai.bj.dir = DUPLEFT; break;
case DUPLEFT: object.ai.bj.dir = DUPRIGHT; break;
case DDOWNRIGHT: object.ai.bj.dir = DDOWNLEFT; break;
case DDOWNLEFT: object.ai.bj.dir = DDOWNRIGHT; break;
case DUPRIGHT: dir = DUPLEFT; break;
case DUPLEFT: dir = DUPRIGHT; break;
case DDOWNRIGHT: dir = DDOWNLEFT; break;
case DDOWNLEFT: dir = DDOWNRIGHT; break;
}
}
else killplayer(object.touchedBy);
else killplayer(touchedBy);
}
if (object.zapped)
if (zapped)
{
// have ball change direction when zapped
if (object.zapd==LEFT)
if (zapd==LEFT)
{
switch(object.ai.bj.dir)
switch(dir)
{
case DUPRIGHT: object.ai.bj.dir = DUPLEFT; break;
case DDOWNRIGHT: object.ai.bj.dir = DDOWNLEFT; break;
case DUPRIGHT: dir = DUPLEFT; break;
case DDOWNRIGHT: dir = DDOWNLEFT; break;
}
}
else
{
switch(object.ai.bj.dir)
switch(dir)
{
case DUPLEFT: object.ai.bj.dir = DUPRIGHT; break;
case DDOWNLEFT: object.ai.bj.dir = DDOWNRIGHT; break;
case DUPLEFT: dir = DUPRIGHT; break;
case DDOWNLEFT: dir = DDOWNRIGHT; break;
}
}
object.zapped = 0;
zapped = 0;
}
switch(object.ai.bj.dir)
switch(dir)
{
case DUPLEFT:
if (object.blockedu) { object.ai.bj.dir = DDOWNLEFT; }
else object.moveUp(object.ai.bj.speed);
if (blockedu) { dir = DDOWNLEFT; }
else moveUp(speed);
if (object.blockedl) { object.ai.bj.dir = DUPRIGHT; }
else object.moveLeft(object.ai.bj.speed);
if (blockedl) { dir = DUPRIGHT; }
else moveLeft(speed);
break;
case DUPRIGHT:
if (object.blockedu) { object.ai.bj.dir = DDOWNRIGHT; }
else object.moveUp(object.ai.bj.speed);
if (blockedu) { dir = DDOWNRIGHT; }
else moveUp(speed);
if (object.blockedr) { object.ai.bj.dir = DUPLEFT; }
else object.moveRight(object.ai.bj.speed);
if (blockedr) { dir = DUPLEFT; }
else moveRight(speed);
break;
case DDOWNLEFT:
if (BJ_BlockedD(object)) { object.ai.bj.dir = DUPLEFT; }
else object.moveDown(object.ai.bj.speed);
if (blockedd) { dir = DUPLEFT; }
else moveDown(speed);
if (object.blockedl) { object.ai.bj.dir = DDOWNRIGHT; }
else object.moveLeft(object.ai.bj.speed);
if (blockedl) { dir = DDOWNRIGHT; }
else moveLeft(speed);
break;
case DDOWNRIGHT:
if (BJ_BlockedD(object)) { object.ai.bj.dir = DUPRIGHT; }
else object.moveDown(object.ai.bj.speed);
if (blockedd) { dir = DUPRIGHT; }
else moveDown(speed);
if (object.blockedr) { object.ai.bj.dir = DDOWNLEFT; }
else object.moveRight(object.ai.bj.speed);
if (blockedr) { dir = DDOWNLEFT; }
else moveRight(speed);
break;
}
if (object.m_type==OBJ_BALL)
if (m_type==OBJ_BALL)
{
object.sprite = OBJ_BALL_DEFSPRITE;
sprite = OBJ_BALL_DEFSPRITE;
}
else
{
object.sprite = OBJ_JACK_DEFSPRITE + object.ai.bj.animframe;
if (object.ai.bj.animtimer > JACK_ANIM_RATE)
sprite = OBJ_JACK_DEFSPRITE + animframe;
if (animtimer > JACK_ANIM_RATE)
{
object.ai.bj.animframe++;
if (object.ai.bj.animframe>3) object.ai.bj.animframe=0;
object.ai.bj.animtimer = 0;
animframe++;
if (animframe>3) animframe=0;
animtimer = 0;
}
else object.ai.bj.animtimer++;
else animtimer++;
}
}
bool CObjectAI::BJ_BlockedD(CObject &object)
{
// we do our own blockedd, because we don't want the ball/jack to
// bounce off the top of platforms that have only solidfall set--
// so we test blockedd against solidl/r instead
if (object.blockedd)
{ // ensure that the tile common_enemy_ai said we hit also has
// solid l/r set
return true;
}
return false;
}
/*
* CBallJack.h
*
* Created on: 05.07.2010
* Author: gerstrong
*/
#ifndef CBALLJACK_H_
#define CBALLJACK_H_
#include "../../../common/CObject.h"
class CBallJack : public CObject
{
public:
CBallJack();
void process();
private:
enum {
DUPRIGHT,
DUPLEFT,
DUP,
DDOWN,
DDOWNRIGHT,
DDOWNLEFT,
DLEFT,
DRIGHT
}m_Direction;
int animframe, animtimer;
int speed;
};
#endif /* CBALLJACK_H_ */
#include "CObjectAI.h"
#include "CButler.h"
#include "../../../keen.h"
#include "../../../sdl/sound/CSound.h"
#include "../../../graphics/CGfxEngine.h"
#include "../../../common/CBehaviorEngine.h"
// AI for "butler" robot (ep1)
enum Butleractionn{
BUTLER_TURN, BUTLER_WALK
};
#define BUTLER_WALK_SPEED 32
#define BUTLER_WALK_SPEED_FAST 38
#define BUTLER_WALK_ANIM_TIME 6
#define BUTLER_WALK_ANIM_TIME_FAST 1
#define BUTLER_TURN_TIME 10
#define BUTLERPUSHAMOUNT 44
#define BUTLERPUSHAMOUNTFAST 30
// distance in pixels butler should look ahead to avoid falling
// off an edge
#define BUTLER_LOOK_AHEAD_DIST 1
// frames
#define BUTLER_WALK_LEFT_FRAME 92
#define BUTLER_WALK_RIGHT_FRAME 88
#define BUTLER_TURNLEFT_FRAME 96
#define BUTLER_TURNRIGHT_FRAME 97
CButler::CButler()
{
state = BUTLER_WALK;
movedir = RIGHT;
animtimer = 0;
canbezapped = false; // will stop bullets but are not harmed
}
void CObjectAI::butler_ai(CObject &object, char difficulty)
void CButler::process()
{
bool not_about_to_fall;
if (object.needinit)
{
object.ai.butler.state = BUTLER_WALK;
object.ai.butler.movedir = RIGHT;
object.ai.butler.animtimer = 0;
object.canbezapped = 1; // will stop bullets but are not harmed
object.needinit = 0;
//object.moveDown(8);
}
// push keen
CPlayer &touched_player = m_Player[object.touchedBy];
if (object.touchPlayer && !touched_player.pdie)
{
if(!((touched_player.pdir == object.ai.butler.movedir) && (touched_player.pwalking)))
{
g_pSound->playStereofromCoord(SOUND_YORP_BUMP, PLAY_NORESTART, object.scrx);
CPlayer &touched_player = m_Player[touchedBy];
if (touchPlayer && !touched_player.pdie)
{
if(!((touched_player.pdir == movedir) && (touched_player.pwalking)))
{
g_pSound->playStereofromCoord(SOUND_YORP_BUMP, PLAY_NORESTART, scrx);
short butlerpushamount;
butlerpushamount = BUTLERPUSHAMOUNT;
short butlerpushamount;
butlerpushamount = BUTLERPUSHAMOUNT;
if(touched_player.pwalking) butlerpushamount = 3*BUTLERPUSHAMOUNT/2;
if(touched_player.pwalking) butlerpushamount = 3*BUTLERPUSHAMOUNT/2;
if (touched_player.getXPosition() < object.getXPosition())
{
touched_player.playpushed_x = -butlerpushamount;
if (difficulty>1) touched_player.playpushed_x -= BUTLERPUSHAMOUNTFAST;
touched_player.playpushed_decreasetimer = 0;
touched_player.pdir = touched_player.pshowdir = LEFT;
}
else
{
touched_player.playpushed_x = butlerpushamount;
if (difficulty>1) touched_player.playpushed_x += BUTLERPUSHAMOUNTFAST;
touched_player.playpushed_decreasetimer = 0;
touched_player.pdir = touched_player.pshowdir = RIGHT;
}
}
}
if (touched_player.getXPosition() < getXPosition())
{
touched_player.playpushed_x = -butlerpushamount;
if (difficulty>1) touched_player.playpushed_x -= BUTLERPUSHAMOUNTFAST;
touched_player.playpushed_decreasetimer = 0;
touched_player.pdir = touched_player.pshowdir = LEFT;
}
else
{
touched_player.playpushed_x = butlerpushamount;
if (difficulty>1) touched_player.playpushed_x += BUTLERPUSHAMOUNTFAST;
touched_player.playpushed_decreasetimer = 0;
touched_player.pdir = touched_player.pshowdir = RIGHT;
}
}
}
switch(object.ai.butler.state)
switch(state)
{
case BUTLER_TURN:
if (object.ai.butler.timer > BUTLER_TURN_TIME)
if (timer > BUTLER_TURN_TIME)
{
object.ai.butler.movedir ^= 1;
object.ai.butler.animtimer = 0;
object.ai.butler.state = BUTLER_WALK;
} else object.ai.butler.timer++;
movedir ^= 1;
animtimer = 0;
state = BUTLER_WALK;
} else timer++;
break;
case BUTLER_WALK:
if (object.ai.butler.movedir==LEFT)
if (movedir==LEFT)
{ // move left
size_t tile = mp_Map->at((object.getXLeftPos()-(BUTLER_LOOK_AHEAD_DIST<<STC))>>CSF, (object.getYDownPos()+1)>>CSF);
size_t tile = mp_Map->at((getXLeftPos()-(BUTLER_LOOK_AHEAD_DIST<<STC))>>CSF, (getYDownPos()+1)>>CSF);
not_about_to_fall = g_pBehaviorEngine->getTileProperties().at(tile).bup;
object.sprite = BUTLER_WALK_LEFT_FRAME + object.ai.butler.frame;
if (!object.blockedl && not_about_to_fall)
sprite = BUTLER_WALK_LEFT_FRAME + frame;
if (!blockedl && not_about_to_fall)
{
if (difficulty>1)
object.moveLeft(BUTLER_WALK_SPEED_FAST);
moveLeft(BUTLER_WALK_SPEED_FAST);
else
object.moveLeft(BUTLER_WALK_SPEED);
moveLeft(BUTLER_WALK_SPEED);
}
else
{
object.sprite = BUTLER_TURNRIGHT_FRAME;
object.ai.butler.frame = 0;
object.ai.butler.timer = 0;
object.ai.butler.animtimer = 0;
object.ai.butler.state = BUTLER_TURN;
sprite = BUTLER_TURNRIGHT_FRAME;
frame = 0;
timer = 0;
animtimer = 0;
state = BUTLER_TURN;
}
}
else
{ // move right
size_t tile = mp_Map->at((object.getXRightPos()+(BUTLER_LOOK_AHEAD_DIST<<STC))>>CSF, (object.getYDownPos()+1)>>CSF);
size_t tile = mp_Map->at((getXRightPos()+(BUTLER_LOOK_AHEAD_DIST<<STC))>>CSF, (getYDownPos()+1)>>CSF);
not_about_to_fall = g_pBehaviorEngine->getTileProperties().at(tile).bup;
object.sprite = BUTLER_WALK_RIGHT_FRAME + object.ai.butler.frame;
if (!object.blockedr && not_about_to_fall)
sprite = BUTLER_WALK_RIGHT_FRAME + frame;
if (!blockedr && not_about_to_fall)
{
if (difficulty>1)
object.moveRight(BUTLER_WALK_SPEED_FAST);
moveRight(BUTLER_WALK_SPEED_FAST);
else
object.moveRight(BUTLER_WALK_SPEED);
moveRight(BUTLER_WALK_SPEED);
}
else
{
object.sprite = BUTLER_TURNLEFT_FRAME;
object.ai.butler.frame = 0;
object.ai.butler.timer = 0;
object.ai.butler.animtimer = 0;
object.ai.butler.state = BUTLER_TURN;
sprite = BUTLER_TURNLEFT_FRAME;
frame = 0;
timer = 0;
animtimer = 0;
state = BUTLER_TURN;
}
}
// walk animation
if (object.ai.butler.animtimer > BUTLER_WALK_ANIM_TIME ||
(object.ai.butler.animtimer > BUTLER_WALK_ANIM_TIME_FAST && difficulty>1))
if (animtimer > BUTLER_WALK_ANIM_TIME ||
(animtimer > BUTLER_WALK_ANIM_TIME_FAST && difficulty>1))
{
if (object.ai.butler.frame>=3) object.ai.butler.frame=0;
else object.ai.butler.frame++;
object.ai.butler.animtimer = 0;
if (frame>=3) frame=0;
else frame++;
animtimer = 0;
}
else object.ai.butler.animtimer++;
else animtimer++;
break;
default: break;
}
}
/*
* CButler.h
*
* Created on: 05.07.2010
* Author: gerstrong
*/
#ifndef CBUTLER_H_
#define CBUTLER_H_
#include "../../../common/CObject.h"
#define BUTLER_WALK_SPEED 32
#define BUTLER_WALK_SPEED_FAST 38
#define BUTLER_WALK_ANIM_TIME 6
#define BUTLER_WALK_ANIM_TIME_FAST 1
#define BUTLER_TURN_TIME 10
#define BUTLERPUSHAMOUNT 44
#define BUTLERPUSHAMOUNTFAST 30
// distance in pixels butler should look ahead to avoid falling
// off an edge
#define BUTLER_LOOK_AHEAD_DIST 1
// frames
#define BUTLER_WALK_LEFT_FRAME 92
#define BUTLER_WALK_RIGHT_FRAME 88
#define BUTLER_TURNLEFT_FRAME 96
#define BUTLER_TURNRIGHT_FRAME 97
class CButler
{
public:
CButler();
void process();
private:
// AI for "butler" robot (ep1)
enum {
BUTLER_TURN, BUTLER_WALK
} state;
unsigned char timer,animtimer;
unsigned char frame;
unsigned int dist_traveled;
direction_t movedir;
};
#endif /* CBUTLER_H_ */
#include "CObjectAI.h"
#include "CDoor.h"
#include "../../../keen.h"
#include "../../../graphics/CGfxEngine.h"
// "AI" for the door object (to do the animation when a door
// opens, the door tiles are removed and replaced with a sprite
// that looks exactly the old tiles, which then moves down into
// the floor)
#define DOOR_OPEN_SPEED 1
CDoor::CDoor()
{
int x, y;
timer = 0;
doorsprite.setHeight(32);
inhibitfall = true;
needinit = false;
x = getXPosition()>>CSF;
y = getYPosition()>>CSF;
mp_Map->redrawAt(x, y);
mp_Map->redrawAt(x, y+1);
}
void CObjectAI::door_ai( CObject &object, char DoorOpenDir )
void CDoor::process()
{
CSprite &doorsprite = g_pGfxEngine->getSprite(object.sprite);
if (object.needinit)
{
int x, y;
object.ai.door.timer = 0;
doorsprite.setHeight(32);
object.inhibitfall = true;
object.needinit = false;
x = object.getXPosition()>>CSF;
y = object.getYPosition()>>CSF;
mp_Map->redrawAt(x, y);
mp_Map->redrawAt(x, y+1);
}
if (object.ai.door.timer > DOOR_OPEN_SPEED)
CSprite &doorsprite = g_pGfxEngine->getSprite(sprite);
if (timer > DOOR_OPEN_SPEED)
{
// TODO: Create a flag for mods in which the door can be opened in another direction
if (DoorOpenDir==DOWN) object.moveDown(1<<STC);
if (DoorOpenDir==DOWN) moveDown(1<<STC);
doorsprite.setHeight(doorsprite.getHeight()-1);
object.ai.door.timer = 0;
timer = 0;
if (doorsprite.getHeight() == 0)
{
return;
}
}
else object.ai.door.timer++;
else timer++;
}
/*
* CDoor.h
*
* Created on: 05.07.2010
* Author: gerstrong
*/
#ifndef CDOOR_H_
#define CDOOR_H_
// "AI" for the door object (to do the animation when a door
// opens, the door tiles are removed and replaced with a sprite
// that looks exactly the old tiles, which then moves down into
// the floor)
#define DOOR_OPEN_SPEED 1
class CDoor : CObject
{
public:
CDoor();
void process();
private:
char timer;
};
#endif /* CDOOR_H_ */
#include "CFoob.h"
#include "../../../sdl/sound/CSound.h"
#include "../../../graphics/CGfxEngine.h"
#include "CObjectAI.h"
// AI for the foobs (yellow "scaredy cat" creatures) (ep3)
enum FOOB_ACTIONS{
FOOB_WALK,
FOOB_SPOOK,
FOOB_FLEE,
FOOB_EXPLODE,
FOOB_DEAD
};
#define FOOB_WALK_SPEED 32
#define FOOB_WALK_ANIM_RATE 4
#define FOOB_FLEE_SPEED 77
#define FOOB_FLEE_ANIM_RATE 1
#define FOOB_SPOOK_SHOW_TIME 12
#define FOOB_HARDMODE_BLOCK_TIME 35
#define FOOB_EXPLODE_ANIM_RATE 8
CFoob::CFoob()
{
#define FOOB_SPOOK_TIME 80
#define FOOB_RELAX_TIME 400
}
#define FOOB_WALK_LEFT_FRAME 93
#define FOOB_WALK_RIGHT_FRAME 95
#define FOOB_SPOOK_FRAME 97
#define FOOB_EXPLODE_FRAME 97
#define FOOB_DEAD_FRAME 101
void CFoob::process()
{
state = FOOB_WALK;
dir = RIGHT;
animframe = 0;
animtimer = 0;
OnSameLevelTime = 0;