Start of entity management.
This commit is contained in:
parent
383c8c19a3
commit
b3c8ca90d5
|
@ -85,6 +85,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#define MAX_WIDGET_OPTIONS 8
|
||||
|
||||
#define MAX_ENTS_TO_OBSERVE 12
|
||||
|
||||
enum
|
||||
{
|
||||
ET_NONE,
|
||||
|
|
|
@ -134,6 +134,8 @@ struct Entity {
|
|||
int isMissionTarget;
|
||||
int observationTime;
|
||||
SDL_Rect bounds;
|
||||
Entity *riding;
|
||||
Entity *owner;
|
||||
unsigned long flags;
|
||||
void (*init)(void);
|
||||
void (*action)(void);
|
||||
|
@ -160,7 +162,6 @@ struct EntityExt {
|
|||
struct Entity;
|
||||
char spriteName[MAX_NAME_LENGTH];
|
||||
Item *carriedItem;
|
||||
Entity *riding;
|
||||
};
|
||||
|
||||
struct Unit {
|
||||
|
@ -425,7 +426,6 @@ struct Bullet {
|
|||
struct Entity;
|
||||
int damage;
|
||||
int weaponType;
|
||||
Entity *owner;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@ -461,6 +461,7 @@ typedef struct {
|
|||
Bob *bob;
|
||||
Boss *boss;
|
||||
Entity *entityToTrack;
|
||||
Entity *entitiesToObserve[MAX_ENTS_TO_OBSERVE];
|
||||
Map map;
|
||||
Quadtree quadtree;
|
||||
Entity entityHead, *entityTail;
|
||||
|
|
|
@ -20,25 +20,114 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#include "entities.h"
|
||||
|
||||
static void doMarker(Marker *m, int delta);
|
||||
static void handleTeleport(void);
|
||||
static int isObserving(void);
|
||||
static void addRider(void);
|
||||
static void checkPlatformContact(void);
|
||||
static void moveEntity(void);
|
||||
static void haltAtEdge(void);
|
||||
static int canWalkOnEntity(float x, float y);
|
||||
static void moveToOthers(float dx, float dy, PointF *position);
|
||||
static void addTouched(Entity *e);
|
||||
|
||||
static SDL_Rect srcRect;
|
||||
static Entity *riders[MAX_RIDERS];
|
||||
static Entity *touched[MAX_TOUCHED];
|
||||
static Texture *atlasTexture;
|
||||
static Marker targetMarker[3];
|
||||
|
||||
void initEntities(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
atlasTexture = getTexture("gfx/atlas/atlas.png");
|
||||
|
||||
for (i = 0 ; i < 3 ; i++)
|
||||
{
|
||||
memset(&targetMarker[i], 0, sizeof(Marker));
|
||||
targetMarker[i].sprite = getSprite("Marker");
|
||||
}
|
||||
}
|
||||
|
||||
void doEntities(void)
|
||||
{
|
||||
int camMidX, camMidY, flicker;
|
||||
|
||||
memset(riders, 0, sizeof(Entity*) * MAX_RIDERS);
|
||||
|
||||
camMidX = camera.x + (SCREEN_WIDTH / 2);
|
||||
camMidY = camera.y + (SCREEN_HEIGHT / 2);
|
||||
|
||||
doMarker(&targetMarker[0], 1);
|
||||
doMarker(&targetMarker[1], -1);
|
||||
doMarker(&targetMarker[2], 1);
|
||||
|
||||
flicker = world.frameCounter % 3 > 0;
|
||||
|
||||
for (self = world.entityHead.next ; self != NULL ; self = self->next)
|
||||
{
|
||||
if (--self->thinkTime <= 0)
|
||||
removeFromQuadtree(self, &world.quadtree);
|
||||
|
||||
self->isOnScreen = 0;
|
||||
|
||||
if (self->flags & EF_TELEPORTING)
|
||||
{
|
||||
self->action();
|
||||
handleTeleport();
|
||||
continue;
|
||||
}
|
||||
|
||||
self->tick();
|
||||
if ((self->flags & EF_ALWAYS_PROCESS) > 0 || getDistance(camMidX, camMidY, self->x, self->y) < SCREEN_WIDTH || isObserving())
|
||||
{
|
||||
self->isOnScreen = 1;
|
||||
}
|
||||
else if (self->flags & EF_KILL_OFFSCREEN)
|
||||
{
|
||||
self->alive = ALIVE_DEAD;
|
||||
}
|
||||
|
||||
self->animate();
|
||||
self->setSize();
|
||||
|
||||
self->riding = NULL;
|
||||
|
||||
if (self->w != 0 && self->h != 0 && (!(self->flags & (EF_TELEPORTING | EF_GONE))))
|
||||
{
|
||||
addToQuadtree(self, &world.quadtree);
|
||||
}
|
||||
|
||||
if (self->isOnScreen)
|
||||
{
|
||||
memset(touched, 0, sizeof(Entity*) * MAX_TOUCHED);
|
||||
|
||||
if (--self->thinkTime <= 0)
|
||||
{
|
||||
self->thinkTime = 0;
|
||||
|
||||
self->action();
|
||||
}
|
||||
|
||||
if (self->flags & EF_GONE)
|
||||
{
|
||||
self->isOnScreen = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
self->tick();
|
||||
|
||||
self->isOnGround = 0;
|
||||
|
||||
if (self->dy >= 0 && (!(self->flags & EF_WEIGHTLESS)))
|
||||
{
|
||||
checkPlatformContact();
|
||||
}
|
||||
|
||||
if (!self->isStatic)
|
||||
{
|
||||
moveEntity();
|
||||
}
|
||||
|
||||
self->animate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,6 +151,325 @@ void drawEntities(int plane)
|
|||
}
|
||||
}
|
||||
|
||||
static void checkPlatformContact(void)
|
||||
{
|
||||
Entity *e;
|
||||
|
||||
srcRect.x = self->x;
|
||||
srcRect.y = self->y + 4;
|
||||
srcRect.w = self->w;
|
||||
srcRect.h = self->h;
|
||||
|
||||
for (e = world.entityHead.next ; e != NULL ; e = e->next)
|
||||
{
|
||||
if (e == self || e->type != ET_LIFT)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (e->y > self->y + self->h - (8 + self->dy) && collision(srcRect.x, srcRect.y, srcRect.w, srcRect.h, e->x, e->y, e->w, e->h))
|
||||
{
|
||||
self->riding = e;
|
||||
self->isOnGround = 1;
|
||||
self->dy = 0;
|
||||
addRider();
|
||||
|
||||
/* required for bullets */
|
||||
self->touch(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void moveEntity(void)
|
||||
{
|
||||
PointF position;
|
||||
|
||||
switch (self->environment)
|
||||
{
|
||||
case ENV_AIR:
|
||||
if (!(self->flags & EF_WEIGHTLESS))
|
||||
{
|
||||
self->dy += GRAVITY_POWER;
|
||||
self->dy =limit(self->dy, -25, 25);
|
||||
|
||||
if (self->dy > 0 && self->dy < 1)
|
||||
{
|
||||
self->dy = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ENV_WATER:
|
||||
self->flags &= ~EF_BOUNCES;
|
||||
if ((self->flags & EF_SWIMS) == 0)
|
||||
{
|
||||
self->dy += GRAVITY_POWER;
|
||||
self->dy = limit(self->dy, -2, 2);
|
||||
}
|
||||
break;
|
||||
|
||||
case ENV_SLIME:
|
||||
case ENV_LAVA:
|
||||
self->dy += GRAVITY_POWER;
|
||||
self->dx = limit(self->dx, -2, 2);
|
||||
self->dy = limit(self->dy, -2, 2);
|
||||
break;
|
||||
}
|
||||
|
||||
if (self->flags & EF_HALT_AT_EDGE)
|
||||
{
|
||||
haltAtEdge();
|
||||
}
|
||||
|
||||
// Deal with x movement
|
||||
position.x = self->x;
|
||||
position.y = self->x;
|
||||
position.x += self->dx;
|
||||
moveToOthers(self->dx, 0, &position);
|
||||
moveToMap(self->dx, 0, position);
|
||||
|
||||
// Deal with Y movement
|
||||
position.y += self->dy;
|
||||
moveToOthers(0, self->dy, &position);
|
||||
moveToMap(0, self->dy, position);
|
||||
|
||||
if (self->dy > 0 && self->riding != NULL)
|
||||
{
|
||||
position.y = self->riding->y;
|
||||
position.y -= self->h;
|
||||
}
|
||||
|
||||
self->x = position.x;
|
||||
self->y = position.y;
|
||||
|
||||
if (!(self->flags & (EF_KILL_OFFSCREEN | EF_NO_CLIP)))
|
||||
{
|
||||
self->x = limit(self->x, world.map.bounds.x, world.map.bounds.w + SCREEN_WIDTH - self->w);
|
||||
self->y = limit(self->y, world.map.bounds.y - 64, world.map.bounds.h + SCREEN_HEIGHT - self->h);
|
||||
}
|
||||
}
|
||||
|
||||
static void haltAtEdge(void)
|
||||
{
|
||||
float x, y;
|
||||
int mx, my, i;
|
||||
|
||||
if (!(self->flags & (EF_WEIGHTLESS | EF_SWIMS)))
|
||||
{
|
||||
if (self->environment == ENV_WATER)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
x = self->x + self->dx + (self->w / 2);
|
||||
y = self->y + self->h + 1;
|
||||
|
||||
if (canWalkOnEntity(x, y))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mx = x / MAP_TILE_SIZE;
|
||||
my = y / MAP_TILE_SIZE;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (isLiquid(mx, my + i))
|
||||
{
|
||||
self->walk();
|
||||
self->dx = 0;
|
||||
self->thinkTime = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isWalkable(mx, my + i))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self->walk();
|
||||
self->dx = 0;
|
||||
self->thinkTime = 0;
|
||||
return;
|
||||
}
|
||||
else if ((self->flags & EF_SWIMS) && self->dy < 0)
|
||||
{
|
||||
x = self->x + self->dx + (self->w / 2);
|
||||
y = self->y + self->dy + (self->h / 2);
|
||||
|
||||
mx = x / MAP_TILE_SIZE;
|
||||
my = y / MAP_TILE_SIZE;
|
||||
|
||||
my--;
|
||||
|
||||
if (world.map.data[mx][my] == MAP_TILE_AIR)
|
||||
{
|
||||
self->walk();
|
||||
self->dx = 0;
|
||||
self->dy = 0;
|
||||
self->thinkTime = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ((self->flags & EF_WEIGHTLESS) && self->dy > 0)
|
||||
{
|
||||
x = self->x + self->dx + self->w;
|
||||
y = self->y + self->dy + self->h;
|
||||
|
||||
mx = x / MAP_TILE_SIZE;
|
||||
my = y / MAP_TILE_SIZE;
|
||||
|
||||
my++;
|
||||
|
||||
if (isLiquid(mx, my))
|
||||
{
|
||||
self->walk();
|
||||
self->dx = 0;
|
||||
self->dy = 0;
|
||||
self->thinkTime = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int canWalkOnEntity(float x, float y)
|
||||
{
|
||||
Entity *e;
|
||||
|
||||
srcRect.x = x;
|
||||
srcRect.x = y;
|
||||
srcRect.w = 8;
|
||||
srcRect.h = MAP_TILE_SIZE * 4;
|
||||
|
||||
for (e = world.entityHead.next ; e != NULL ; e = e->next)
|
||||
{
|
||||
if (self != e && e->isSolid && collision(x, y, 1, MAP_TILE_SIZE * 2, e->x, e->y, e->w, e->y))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void moveToOthers(float dx, float dy, PointF *position)
|
||||
{
|
||||
Entity *e;
|
||||
int clearTouched, hit, dirX, dirY, solidLoopHits;
|
||||
|
||||
srcRect.x = (int) position->x;
|
||||
srcRect.y = (int) position->y;
|
||||
srcRect.w = self->w;
|
||||
srcRect.h = self->h;
|
||||
|
||||
clearTouched = 0;
|
||||
hit = 0;
|
||||
dirX = (dx > 0) ? 1 : -1;
|
||||
dirY = (dy > 0) ? 1 : -1;
|
||||
solidLoopHits = 0;
|
||||
|
||||
do
|
||||
{
|
||||
hit = 0;
|
||||
|
||||
for (e = world.entityHead.next ; e != NULL ; e = e->next)
|
||||
{
|
||||
if (e == self || e->owner == self || self->owner == e)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (collision(srcRect.x, srcRect.y, srcRect.w, srcRect.h, e->x, e->y, e->w, e->h))
|
||||
{
|
||||
if (clearTouched)
|
||||
{
|
||||
memset(touched, 0, sizeof(Entity*) * MAX_TOUCHED);
|
||||
clearTouched = 0;
|
||||
}
|
||||
|
||||
if (self->type == ET_BOB && e->type == ET_PUSHBLOCK && dx != 0)
|
||||
{
|
||||
if (!pushEntity(e, dx * 0.35, 0))
|
||||
{
|
||||
position->x = e->x;
|
||||
position->x -= (dirX == 1) ? self->w : -e->w;
|
||||
self->dx = self->bounce(self->dx);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->animate();
|
||||
}
|
||||
}
|
||||
|
||||
if (e->isSolid && self->type != ET_LIFT)
|
||||
{
|
||||
if (dx != 0)
|
||||
{
|
||||
position->x = e->x;
|
||||
position->x -= (dirX == 1) ? self->w : -e->w;
|
||||
self->dx = self->bounce(self->dx);
|
||||
}
|
||||
|
||||
if (dy != 0)
|
||||
{
|
||||
if (e->y > self->y)
|
||||
{
|
||||
self->isOnGround = 1;
|
||||
self->riding = e;
|
||||
}
|
||||
|
||||
position->y = e->y;
|
||||
position->y -= (dirY == 1) ? self->h : -e->h;
|
||||
self->dy = self->bounce(self->dy);
|
||||
self->dy = limit(self->dy, JUMP_POWER, -JUMP_POWER);
|
||||
}
|
||||
}
|
||||
|
||||
if (self->isSolid && e->isSolid)
|
||||
{
|
||||
hit = 1;
|
||||
|
||||
/*
|
||||
* Infinite loop! Kill it!
|
||||
*/
|
||||
if (dx == 0 && dy == 0 && solidLoopHits++ > 1)
|
||||
{
|
||||
self->alive = ALIVE_DEAD;
|
||||
printf("Warning: Killed stuck entity '%s', stuck in '%s'\n", self->name, e->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
addTouched(e);
|
||||
}
|
||||
}
|
||||
|
||||
clearTouched = 1;
|
||||
|
||||
srcRect.x = self->x;
|
||||
srcRect.y = self->y;
|
||||
srcRect.w = self->w;
|
||||
srcRect.h = self->h;
|
||||
}
|
||||
while (hit);
|
||||
}
|
||||
|
||||
static int isObserving(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < MAX_ENTS_TO_OBSERVE ; i++)
|
||||
{
|
||||
if (world.entitiesToObserve[i] == self)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void activateEntities(char *names, int activate)
|
||||
{
|
||||
}
|
||||
|
@ -70,6 +478,50 @@ void teleportEntity(Entity *e, float tx, float ty)
|
|||
{
|
||||
}
|
||||
|
||||
static void handleTeleport(void)
|
||||
{
|
||||
float diffX, diffY;
|
||||
|
||||
diffX = abs(self->x - self->tx) / 20;
|
||||
diffY = abs(self->y - self->ty) / 20;
|
||||
|
||||
addTeleportStar(self->x + rand() % self->w, self->y + rand() % self->h);
|
||||
|
||||
diffX = MAX(3, MIN(30, diffX));
|
||||
diffY = MAX(3, MIN(30, diffY));
|
||||
|
||||
if (self->x > self->tx)
|
||||
{
|
||||
self->x -= diffX;
|
||||
}
|
||||
|
||||
if (self->x < self->tx)
|
||||
{
|
||||
self->x += diffX;
|
||||
}
|
||||
|
||||
if (self->y > self->ty)
|
||||
{
|
||||
self->y -= diffY;
|
||||
}
|
||||
|
||||
if (self->y < self->ty)
|
||||
{
|
||||
self->y += diffY;
|
||||
}
|
||||
|
||||
if (collision(self->x, self->y, self->w, self->h, self->tx, self->ty, self->w, self->h))
|
||||
{
|
||||
self->flags &= ~EF_TELEPORTING;
|
||||
self->x = self->tx;
|
||||
self->y = self->ty;
|
||||
addTeleportStars(self);
|
||||
self->dx = self->dy = 0;
|
||||
self->environment = ENV_AIR;
|
||||
playSound(SND_TELEPORT, CH_EFFECTS);
|
||||
}
|
||||
}
|
||||
|
||||
void dropCarriedItem(void)
|
||||
{
|
||||
EntityExt *e;
|
||||
|
@ -138,3 +590,42 @@ Entity *getRandomObjectiveEntity(void)
|
|||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
static void doMarker(Marker *m, int delta)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < 3 ; i++)
|
||||
{
|
||||
m->value -= (0.1 * delta);
|
||||
m->y = 15 + (float) sin(m->value) * 5;
|
||||
}
|
||||
}
|
||||
|
||||
static void addRider(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < MAX_RIDERS ; i++)
|
||||
{
|
||||
if (!riders[i])
|
||||
{
|
||||
riders[i] = self;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void addTouched(Entity *e)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < MAX_TOUCHED ; i++)
|
||||
{
|
||||
if (!touched[i])
|
||||
{
|
||||
touched[i] = e;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#include "../common.h"
|
||||
|
||||
#define MAX_RIDERS 12
|
||||
#define MAX_TOUCHED 12
|
||||
|
||||
extern Texture *getTexture(const char *filename);
|
||||
extern void blitRect(SDL_Texture *texture, int x, int y, SDL_Rect *srcRect, int center);
|
||||
extern void addTeleportStars(Entity *e);
|
||||
extern void removeFromQuadtree(Entity *e, Quadtree *root);
|
||||
extern Sprite *getSprite(char *name);
|
||||
extern void playSound(int snd, int ch);
|
||||
extern void addTeleportStars(Entity *e);
|
||||
extern void addTeleportStar(float x, float y);
|
||||
extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2);
|
||||
extern int getDistance(int x1, int y1, int x2, int y2);
|
||||
extern void addToQuadtree(Entity *e, Quadtree *root);
|
||||
extern float limit(float i, float a, float b);
|
||||
extern int isWalkable(int x, int y);
|
||||
extern int isLiquid(int x, int y);
|
||||
|
||||
extern Entity *self;
|
||||
extern Camera camera;
|
||||
|
|
|
@ -36,7 +36,6 @@ static int canAdd(Unit *u, int mx, int my);
|
|||
void startMission(void);
|
||||
|
||||
static Texture *background;
|
||||
static Entity* entitiesToObserve[MAX_ENTS_TO_OBSERVE];
|
||||
|
||||
void initWorld(void)
|
||||
{
|
||||
|
@ -212,7 +211,10 @@ static void doWorldObserving(void)
|
|||
{
|
||||
for (i = 0 ; i < MAX_ENTS_TO_OBSERVE ; i++)
|
||||
{
|
||||
entitiesToObserve[i]->observationTime = SDL_GetTicks() + 5000;
|
||||
if (world.entitiesToObserve[i])
|
||||
{
|
||||
world.entitiesToObserve[i]->observationTime = SDL_GetTicks() + 5000;
|
||||
}
|
||||
}
|
||||
|
||||
memset(entitiesToObserve, 0, sizeof(Entity*) * MAX_ENTS_TO_OBSERVE);
|
||||
|
|
|
@ -20,8 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#include "../common.h"
|
||||
|
||||
#define MAX_ENTS_TO_OBSERVE 12
|
||||
|
||||
extern Texture *getTexture(const char *filename);
|
||||
extern void initObjectives(void);
|
||||
extern Entity *getRandomObjectiveEntity(void);
|
||||
|
|
Loading…
Reference in New Issue