Start of entity management.

This commit is contained in:
Steve 2018-02-03 08:44:02 +00:00
parent 383c8c19a3
commit b3c8ca90d5
6 changed files with 518 additions and 10 deletions

View File

@ -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,

View File

@ -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;

View File

@ -20,27 +20,116 @@ 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)
{
removeFromQuadtree(self, &world.quadtree);
self->isOnScreen = 0;
if (self->flags & EF_TELEPORTING)
{
handleTeleport();
continue;
}
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->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();
}
}
}
void drawEntities(int plane)
{
@ -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;
}
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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);