Start of replacing grid with quadtree.

This commit is contained in:
Steve 2016-02-21 07:48:22 +00:00
parent 7337460853
commit 6b1e62dd38
15 changed files with 374 additions and 192 deletions

View File

@ -13,13 +13,14 @@ OBJS += capitalShips.o challenges.o cJSON.o
OBJS += debris.o dev.o draw.o OBJS += debris.o dev.o draw.o
OBJS += effects.o entities.o extractionPoint.o OBJS += effects.o entities.o extractionPoint.o
OBJS += fighters.o OBJS += fighters.o
OBJS += galacticMap.o game.o grid.o OBJS += galacticMap.o game.o
OBJS += hud.o OBJS += hud.o
OBJS += init.o input.o io.o items.o OBJS += init.o input.o io.o items.o
OBJS += load.o locations.o lookup.o OBJS += load.o locations.o lookup.o
OBJS += main.o messageBox.o mission.o missionInfo.o OBJS += main.o messageBox.o mission.o missionInfo.o
OBJS += objectives.o options.o OBJS += objectives.o options.o
OBJS += player.o OBJS += player.o
OBJS += quadtree.o
OBJS += radar.o rope.o OBJS += radar.o rope.o
OBJS += save.o script.o sound.o starfield.o starSystems.o stats.o OBJS += save.o script.o sound.o starfield.o starSystems.o stats.o
OBJS += testMission.o textures.o text.o title.o transition.o OBJS += testMission.o textures.o text.o title.o transition.o

View File

@ -638,7 +638,7 @@ static int nearItems(void)
closest = MAX_TARGET_RANGE; closest = MAX_TARGET_RANGE;
candidates = getAllEntsWithin(self->x - (self->w / 2) - (GRID_CELL_WIDTH / 2), self->y - (self->h / 2) - (GRID_CELL_HEIGHT / 2), GRID_CELL_WIDTH, GRID_CELL_HEIGHT, self); candidates = getAllEntsWithin(self->x - (self->w / 2) - (SCREEN_WIDTH / 4), self->y - (self->h / 2) - (SCREEN_HEIGHT / 4), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, self);
self->target = NULL; self->target = NULL;
@ -684,7 +684,7 @@ static int nearTowableCraft(void)
long closest, distance; long closest, distance;
Entity *e, **candidates; Entity *e, **candidates;
candidates = getAllEntsWithin(self->x - (self->w / 2) - (GRID_CELL_WIDTH / 2), self->y - (self->h / 2) - (GRID_CELL_HEIGHT / 2), GRID_CELL_WIDTH, GRID_CELL_HEIGHT, self); candidates = getAllEntsWithin(self->x - (self->w / 2) - (SCREEN_WIDTH / 4), self->y - (self->h / 2) - (SCREEN_HEIGHT / 4), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, self);
closest = MAX_TARGET_RANGE; closest = MAX_TARGET_RANGE;
@ -787,11 +787,8 @@ static void moveToLeader(void)
static void doWander(void) static void doWander(void)
{ {
self->targetLocation.x = 5 + (rand() % (GRID_SIZE - 10)); self->targetLocation.x = 500 + (rand() % (BATTLE_AREA_WIDTH - 1000));
self->targetLocation.x *= GRID_CELL_WIDTH; self->targetLocation.y = 500 + (rand() % (BATTLE_AREA_HEIGHT - 1000));
self->targetLocation.y = 5 + (rand() % (GRID_SIZE - 10));
self->targetLocation.y *= GRID_CELL_HEIGHT;
self->aiActionTime = FPS * 15; self->aiActionTime = FPS * 15;

View File

@ -52,6 +52,10 @@ void initBattle(void)
app.delegate.draw = &draw; app.delegate.draw = &draw;
memset(&app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS); memset(&app.keyboard, 0, sizeof(int) * MAX_KEYBOARD_KEYS);
battle.quadtree.w = BATTLE_AREA_WIDTH;
battle.quadtree.h = BATTLE_AREA_HEIGHT;
initQuadtree(&battle.quadtree);
initBullets(); initBullets();
initEntities(); initEntities();
@ -436,5 +440,5 @@ void destroyBattle(void)
destroyScript(); destroyScript();
destroyGrid(); destroyQuadtree();
} }

View File

@ -64,7 +64,8 @@ extern void drawOptions(void);
extern void playSound(int id); extern void playSound(int id);
extern void resetWaypoints(void); extern void resetWaypoints(void);
extern void doPlayerSelect(void); extern void doPlayerSelect(void);
extern void destroyGrid(void); extern void destroyQuadtree(void);
extern void initQuadtree(Quadtree *root);
extern void completeMission(void); extern void completeMission(void);
extern void initEffects(void); extern void initEffects(void);
extern void doScript(void); extern void doScript(void);

View File

@ -164,11 +164,8 @@ static void findAITarget(void)
} }
else else
{ {
self->targetLocation.x = 5 + (rand() % (GRID_SIZE - 10)); self->targetLocation.x = 500 + (rand() % (BATTLE_AREA_WIDTH - 1000));
self->targetLocation.x *= GRID_CELL_WIDTH; self->targetLocation.y = 500 + (rand() % (BATTLE_AREA_HEIGHT - 1000));
self->targetLocation.y = 5 + (rand() % (GRID_SIZE - 10));
self->targetLocation.y *= GRID_CELL_HEIGHT;
self->aiActionTime = FPS * (30 + (rand() % 120)); self->aiActionTime = FPS * (30 + (rand() % 120));
} }

View File

@ -69,14 +69,9 @@ void doEntities(void)
numAllies = numEnemies = numActiveAllies = numActiveEnemies = 0; numAllies = numEnemies = numActiveAllies = numActiveEnemies = 0;
destroyGrid();
for (e = battle.entityHead.next ; e != NULL ; e = e->next) for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{ {
if (e->active && e->alive != ALIVE_DEAD) removeFromQuadtree(e, &battle.quadtree);
{
addToGrid(e);
}
} }
if (dev.playerImmortal) if (dev.playerImmortal)
@ -169,6 +164,8 @@ void doEntities(void)
e->x += e->dx; e->x += e->dx;
e->y += e->dy; e->y += e->dy;
addToQuadtree(e, &battle.quadtree);
} }
else else
{ {
@ -261,30 +258,30 @@ static void restrictToGrid(Entity *e)
{ {
float force; float force;
if (e->x <= GRID_RESTRICTION_SIZE) if (e->x <= BATTLE_AREA_EDGE)
{ {
force = GRID_RESTRICTION_SIZE - e->x; force = BATTLE_AREA_EDGE - e->x;
e->dx += force * 0.001; e->dx += force * 0.001;
e->dx *= 0.95; e->dx *= 0.95;
} }
if (e->y <= GRID_RESTRICTION_SIZE) if (e->y <= BATTLE_AREA_EDGE)
{ {
force = GRID_RESTRICTION_SIZE - e->y; force = BATTLE_AREA_EDGE - e->y;
e->dy += force * 0.001; e->dy += force * 0.001;
e->dy *= 0.95; e->dy *= 0.95;
} }
if (e->x >= (GRID_SIZE * GRID_CELL_WIDTH) - GRID_RESTRICTION_SIZE) if (e->x >= BATTLE_AREA_WIDTH - BATTLE_AREA_EDGE)
{ {
force = e->x - ((GRID_SIZE * GRID_CELL_WIDTH) - GRID_RESTRICTION_SIZE); force = e->x - (BATTLE_AREA_WIDTH - BATTLE_AREA_EDGE);
e->dx -= force * 0.001; e->dx -= force * 0.001;
e->dx *= 0.95; e->dx *= 0.95;
} }
if (e->y >= (GRID_SIZE * GRID_CELL_HEIGHT) - GRID_RESTRICTION_SIZE) if (e->y >= BATTLE_AREA_HEIGHT - BATTLE_AREA_EDGE)
{ {
force = e->y - ((GRID_SIZE * GRID_CELL_HEIGHT) - GRID_RESTRICTION_SIZE); force = e->y - (BATTLE_AREA_HEIGHT - BATTLE_AREA_EDGE);
e->dy -= force * 0.001; e->dy -= force * 0.001;
e->dy *= 0.95; e->dy *= 0.95;
} }
@ -353,7 +350,7 @@ void drawEntities(void)
{ {
Entity *e, **candidates; Entity *e, **candidates;
int i; int i;
candidates = getAllEntsWithin(battle.camera.x, battle.camera.y, SCREEN_WIDTH, SCREEN_HEIGHT, NULL); candidates = getAllEntsWithin(battle.camera.x, battle.camera.y, SCREEN_WIDTH, SCREEN_HEIGHT, NULL);
/* count number of candidates for use with qsort */ /* count number of candidates for use with qsort */

View File

@ -27,14 +27,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern void blitRotated(SDL_Texture *texture, int x, int y, float angle); extern void blitRotated(SDL_Texture *texture, int x, int y, float angle);
extern void doFighter(void); extern void doFighter(void);
extern void doCapitalShip(void); extern void doCapitalShip(void);
extern void addToGrid(Entity *e);
extern void removeFromGrid(Entity *e);
extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore); extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore);
extern void doRope(Entity *e); extern void doRope(Entity *e);
extern void drawRope(Entity *e); extern void drawRope(Entity *e);
extern void cutRope(Entity *e); extern void cutRope(Entity *e);
extern void drawShieldHitEffect(Entity *e); extern void drawShieldHitEffect(Entity *e);
extern void destroyGrid(void); extern void removeFromQuadtree(Entity *e, Quadtree *root);
extern void addToQuadtree(Entity *e, Quadtree *root);
extern void updateCapitalShipComponentProperties(Entity *parent); extern void updateCapitalShipComponentProperties(Entity *parent);
extern App app; extern App app;

View File

@ -1,128 +0,0 @@
/*
Copyright (C) 2015 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "grid.h"
static Entity *candidates[MAX_GRID_CANDIDATES];
static void addCandidate(Entity *e);
void addToGrid(Entity *e)
{
GridCell *cell, *prev;
int x, y, x1, y1, x2, y2;
x1 = (e->x - e->w / 2) / GRID_CELL_WIDTH;
y1 = (e->y - e->h / 2) / GRID_CELL_HEIGHT;
x2 = (e->x + e->w / 2) / GRID_CELL_WIDTH;
y2 = (e->y + e->h / 2) / GRID_CELL_HEIGHT;
for (x = x1 ; x <= x2 ; x++)
{
for (y = y1 ; y <= y2 ; y++)
{
if (x >= 0 && y >= 0 && x < GRID_SIZE && y < GRID_SIZE)
{
prev = &battle.grid[x][y];
for (cell = battle.grid[x][y].next ; cell != NULL ; cell = cell->next)
{
prev = cell;
}
cell = malloc(sizeof(GridCell));
memset(cell, 0, sizeof(GridCell));
prev->next = cell;
cell->entity = e;
}
}
}
}
Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore)
{
GridCell *cell;
int x1, y1, x2, y2;
memset(candidates, 0, sizeof(Entity*) * MAX_GRID_CANDIDATES);
x1 = x / GRID_CELL_WIDTH;
y1 = y / GRID_CELL_HEIGHT;
x2 = (x + w) / GRID_CELL_WIDTH;
y2 = (y + h) / GRID_CELL_HEIGHT;
for (x = x1 ; x <= x2 ; x++)
{
for (y = y1 ; y <= y2 ; y++)
{
if (x >= 0 && y >= 0 && x < GRID_SIZE && y < GRID_SIZE)
{
for (cell = battle.grid[x][y].next ; cell != NULL ; cell = cell->next)
{
if (cell->entity != ignore)
{
addCandidate(cell->entity);
}
}
}
}
}
/* NULL terminate, to allow us to loop through them more easily */
candidates[MAX_GRID_CANDIDATES - 1] = NULL;
return candidates;
}
static void addCandidate(Entity *e)
{
int i = 0;
for (i = 0 ; i < MAX_GRID_CANDIDATES ; i++)
{
if (candidates[i] == NULL || candidates[i] == e)
{
candidates[i] = e;
return;
}
}
printf("Out of grid candidate space!");
exit(1);
}
void destroyGrid(void)
{
int x, y;
GridCell *cell;
for (x = 0 ; x < GRID_SIZE ; x++)
{
for (y = 0 ; y < GRID_SIZE ; y++)
{
while (battle.grid[x][y].next)
{
cell = battle.grid[x][y].next;
battle.grid[x][y].next = cell->next;
free(cell);
}
}
}
}

View File

@ -247,14 +247,14 @@ static void handleMouse(void)
if (app.mouse.button[SDL_BUTTON_X1]) if (app.mouse.button[SDL_BUTTON_X1])
{ {
cycleRadarZoom(); switchGuns();
app.mouse.button[SDL_BUTTON_X1] = 0; app.mouse.button[SDL_BUTTON_X1] = 0;
} }
if (app.mouse.button[SDL_BUTTON_X2]) if (app.mouse.button[SDL_BUTTON_X2])
{ {
switchGuns(); cycleRadarZoom();
app.mouse.button[SDL_BUTTON_X2] = 0; app.mouse.button[SDL_BUTTON_X2] = 0;
} }

306
src/battle/quadtree.c Normal file
View File

@ -0,0 +1,306 @@
/*
Copyright (C) 2015 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "quadtree.h"
static Entity *candidates[QT_MAX_CANDIDATES];
static int cIndex;
static int memory;
static int getIndex(Quadtree *root, int x, int y, int w, int h);
static void removeEntity(Entity *e, Quadtree *root);
static void addCandidate(Entity *e);
static int candidatesComparator(const void *a, const void *b);
static void getAllEntsWithinNode(int x, int y, int w, int h, Entity *ignore, Quadtree *root);
static void destroyQuadtreeNode(Quadtree *root);
void initQuadtree(Quadtree *root)
{
Quadtree *node;
int i, w, h;
if (root->depth == 0)
{
memory = 0;
}
memory += sizeof(Quadtree);
w = root->w / 2;
h = root->h / 2;
if (root->depth + 1 < QT_MAX_DEPTH)
{
for (i = 0 ; i < 4 ; i++)
{
node = malloc(sizeof(Quadtree));
memset(node, 0, sizeof(Quadtree));
root->node[i] = node;
node->depth = root->depth + 1;
if (i == 0)
{
node->x = root->x;
node->y = root->y;
node->w = w;
node->h = h;
}
else if (i == 1)
{
node->x = root->x + w;
node->y = root->y;
node->w = w;
node->h = h;
}
else if (i == 2)
{
node->x = root->x;
node->y = root->y + h;
node->w = w;
node->h = h;
}
else
{
node->x = root->x + w;
node->y = root->y + h;
node->w = w;
node->h = h;
}
initQuadtree(node);
}
}
if (root->depth == 0)
{
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Quadtree memory footprint: %d bytes", memory);
}
}
void addToQuadtree(Entity *e, Quadtree *root)
{
int index;
if (root->node[0])
{
index = getIndex(root, e->x - (e->w / 2), e->y - (e->h / 2), e->w, e->h);
if (index != -1)
{
addToQuadtree(e, root->node[index]);
return;
}
}
if (root->numEnts < QT_MAX_ENTS)
{
root->ents[root->numEnts++] = e;
return;
}
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Couldn't add %s to quadtree - out of node ent space", e->name);
}
static int getIndex(Quadtree *root, int x, int y, int w, int h)
{
int index = -1;
int verticalMidpoint = root->x + (root->w / 2);
int horizontalMidpoint = root->y + (root->h / 2);
int topQuadrant = (y < horizontalMidpoint && y + h < horizontalMidpoint);
int bottomQuadrant = (y > horizontalMidpoint);
if (x < verticalMidpoint && x + w < verticalMidpoint)
{
if (topQuadrant)
{
index = 1;
}
else if (bottomQuadrant)
{
index = 2;
}
}
else if (x > verticalMidpoint)
{
if (topQuadrant)
{
index = 0;
}
else if (bottomQuadrant)
{
index = 3;
}
}
return index;
}
void removeFromQuadtree(Entity *e, Quadtree *root)
{
int index, i;
index = getIndex(root, e->x - (e->w / 2), e->y - (e->h / 2), e->w, e->h);
removeEntity(e, root);
if (root->node[0])
{
if (index != -1)
{
removeFromQuadtree(e, root->node[index]);
}
else
{
for (i = 0; i < 4; i++)
{
removeFromQuadtree(e, root->node[i]);
}
}
}
}
static void removeEntity(Entity *e, Quadtree *root)
{
int i, n;
n = root->numEnts;
for (i = 0 ; i < QT_MAX_ENTS ; i++)
{
if (root->ents[i] == e)
{
root->ents[i] = NULL;
root->numEnts--;
}
}
qsort(root->ents, n, sizeof(Entity*), candidatesComparator);
}
Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore)
{
cIndex = 0;
memset(candidates, 0, sizeof(Entity*) * QT_MAX_CANDIDATES);
getAllEntsWithinNode(x, y, w, h, ignore, &battle.quadtree);
/* NULL terminate, to allow us to loop through them more easily */
candidates[QT_MAX_CANDIDATES - 1] = NULL;
return candidates;
}
static void getAllEntsWithinNode(int x, int y, int w, int h, Entity *ignore, Quadtree *root)
{
Quadtree *node;
int index, i;
for (i = 0 ; i < root->numEnts ; i++)
{
addCandidate(root->ents[i]);
}
index = getIndex(root, x, y, w, h);
if (root->node[0])
{
if (index != -1)
{
node = root->node[index];
getAllEntsWithinNode(node->x, node->y, node->w, node->h, ignore, node);
}
else
{
for (i = 0; i < 4; i++)
{
node = root->node[i];
getAllEntsWithinNode(node->x, node->y, node->w, node->h, ignore, node);
}
}
}
}
static void addCandidate(Entity *e)
{
int i;
for (i = 0 ; i <= cIndex ; i++)
{
/* already added */
if (candidates[i] == e)
{
return;
}
if (!candidates[i])
{
candidates[cIndex++] = e;
return;
}
}
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "Out of quadtree candidate space");
exit(1);
}
void destroyQuadtree(void)
{
destroyQuadtreeNode(&battle.quadtree);
}
static void destroyQuadtreeNode(Quadtree *root)
{
int i;
if (root->node[0])
{
for (i = 0 ; i < 4 ; i++)
{
destroyQuadtreeNode(root->node[i]);
free(root->node[i]);
root->node[i] = NULL;
}
}
}
static int candidatesComparator(const void *a, const void *b)
{
Entity *e1 = *((Entity**)a);
Entity *e2 = *((Entity**)b);
if (!e1)
{
return 1;
}
else if (!e2)
{
return -1;
}
else
{
return 0;
}
}

View File

@ -90,8 +90,8 @@ void drawRadarRangeWarning(void)
{ {
int x, y, leaving; int x, y, leaving;
x = (int)player->x / GRID_CELL_WIDTH; x = (int)player->x / (SCREEN_WIDTH / 2);
y = (int)player->y / GRID_CELL_HEIGHT; y = (int)player->y / (SCREEN_HEIGHT / 2);
leaving = 0; leaving = 0;
if (x <= 2 && player->dx < 0) if (x <= 2 && player->dx < 0)
@ -108,14 +108,14 @@ void drawRadarRangeWarning(void)
leaving = 1; leaving = 1;
} }
if (x >= GRID_SIZE - 2 && player->dx > 0) if (x >= (SCREEN_WIDTH / 2) - 2 && player->dx > 0)
{ {
blitRotated(radarWarningTexture, SCREEN_WIDTH - 85, SCREEN_HEIGHT - 85, 90); blitRotated(radarWarningTexture, SCREEN_WIDTH - 85, SCREEN_HEIGHT - 85, 90);
leaving = 1; leaving = 1;
} }
if (y >= GRID_SIZE - 2 && player->dy > 0) if (y >= (SCREEN_HEIGHT / 2) - 2 && player->dy > 0)
{ {
blitRotated(radarWarningTexture, SCREEN_WIDTH - 85, SCREEN_HEIGHT - 85, 180); blitRotated(radarWarningTexture, SCREEN_WIDTH - 85, SCREEN_HEIGHT - 85, 180);

View File

@ -60,11 +60,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MAX_FIGHTER_GUNS 12 #define MAX_FIGHTER_GUNS 12
#define MAX_TARGET_RANGE 65536 #define MAX_TARGET_RANGE 65536
#define GRID_CELL_WIDTH 640 #define QT_MAX_DEPTH 5
#define GRID_CELL_HEIGHT 360 #define QT_MAX_ENTS 96
#define GRID_SIZE 50 #define QT_MAX_CANDIDATES 256
#define MAX_GRID_CANDIDATES 256
#define GRID_RESTRICTION_SIZE 250 #define BATTLE_AREA_CELLS 50
#define BATTLE_AREA_WIDTH (640 * BATTLE_AREA_CELLS)
#define BATTLE_AREA_HEIGHT (360 * BATTLE_AREA_CELLS)
#define BATTLE_AREA_EDGE 250
#define BF_NONE 0 #define BF_NONE 0
#define BF_ENGINE (2 << 0) #define BF_ENGINE (2 << 0)

View File

@ -192,13 +192,13 @@ static void loadPlayer(cJSON *node)
side = lookup(cJSON_GetObjectItem(node, "side")->valuestring); side = lookup(cJSON_GetObjectItem(node, "side")->valuestring);
player = spawnFighter(type, 0, 0, side); player = spawnFighter(type, 0, 0, side);
player->x = (GRID_SIZE * GRID_CELL_WIDTH) / 2; player->x = BATTLE_AREA_WIDTH / 2;
player->y = (GRID_SIZE * GRID_CELL_HEIGHT) / 2; player->y = BATTLE_AREA_HEIGHT / 2;
if (cJSON_GetObjectItem(node, "x")) if (cJSON_GetObjectItem(node, "x"))
{ {
player->x = (cJSON_GetObjectItem(node, "x")->valueint * GRID_CELL_WIDTH); player->x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
player->y = (cJSON_GetObjectItem(node, "y")->valueint * GRID_CELL_HEIGHT); player->y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
} }
if (strcmp(type, "Tug") == 0) if (strcmp(type, "Tug") == 0)
@ -237,8 +237,8 @@ static void loadFighters(cJSON *node)
types = toTypeArray(cJSON_GetObjectItem(node, "types")->valuestring, &numTypes); types = toTypeArray(cJSON_GetObjectItem(node, "types")->valuestring, &numTypes);
side = lookup(cJSON_GetObjectItem(node, "side")->valuestring); side = lookup(cJSON_GetObjectItem(node, "side")->valuestring);
x = cJSON_GetObjectItem(node, "x")->valuedouble * GRID_CELL_WIDTH; x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
y = cJSON_GetObjectItem(node, "y")->valuedouble * GRID_CELL_HEIGHT; y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
if (cJSON_GetObjectItem(node, "name")) if (cJSON_GetObjectItem(node, "name"))
{ {
@ -364,8 +364,8 @@ static void loadCapitalShips(cJSON *node)
types = toTypeArray(cJSON_GetObjectItem(node, "types")->valuestring, &numTypes); types = toTypeArray(cJSON_GetObjectItem(node, "types")->valuestring, &numTypes);
side = lookup(cJSON_GetObjectItem(node, "side")->valuestring); side = lookup(cJSON_GetObjectItem(node, "side")->valuestring);
x = cJSON_GetObjectItem(node, "x")->valuedouble * GRID_CELL_WIDTH; x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
y = cJSON_GetObjectItem(node, "y")->valuedouble * GRID_CELL_HEIGHT; y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
if (cJSON_GetObjectItem(node, "name")) if (cJSON_GetObjectItem(node, "name"))
{ {
@ -465,8 +465,8 @@ static void loadEntities(cJSON *node)
{ {
e = NULL; e = NULL;
type = lookup(cJSON_GetObjectItem(node, "type")->valuestring); type = lookup(cJSON_GetObjectItem(node, "type")->valuestring);
x = cJSON_GetObjectItem(node, "x")->valuedouble * GRID_CELL_WIDTH; x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
y = cJSON_GetObjectItem(node, "y")->valuedouble * GRID_CELL_HEIGHT; y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
name = NULL; name = NULL;
groupName = NULL; groupName = NULL;
number = 1; number = 1;
@ -563,8 +563,8 @@ static void loadItems(cJSON *node)
while (node) while (node)
{ {
type = cJSON_GetObjectItem(node, "type")->valuestring; type = cJSON_GetObjectItem(node, "type")->valuestring;
x = cJSON_GetObjectItem(node, "x")->valuedouble * GRID_CELL_WIDTH; x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
y = cJSON_GetObjectItem(node, "y")->valuedouble * GRID_CELL_HEIGHT; y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
name = NULL; name = NULL;
groupName = NULL; groupName = NULL;
number = 1; number = 1;
@ -665,8 +665,9 @@ static void loadLocations(cJSON *node)
battle.locationTail = l; battle.locationTail = l;
STRNCPY(l->name, cJSON_GetObjectItem(node, "name")->valuestring, MAX_NAME_LENGTH); STRNCPY(l->name, cJSON_GetObjectItem(node, "name")->valuestring, MAX_NAME_LENGTH);
l->x = cJSON_GetObjectItem(node, "x")->valueint * GRID_CELL_WIDTH; l->x = (cJSON_GetObjectItem(node, "x")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_WIDTH;
l->y = cJSON_GetObjectItem(node, "y")->valueint * GRID_CELL_HEIGHT; l->y = (cJSON_GetObjectItem(node, "y")->valuedouble / BATTLE_AREA_CELLS) * BATTLE_AREA_HEIGHT;
l->size = cJSON_GetObjectItem(node, "size")->valueint; l->size = cJSON_GetObjectItem(node, "size")->valueint;
if (cJSON_GetObjectItem(node, "active")) if (cJSON_GetObjectItem(node, "active"))
@ -674,8 +675,8 @@ static void loadLocations(cJSON *node)
active = cJSON_GetObjectItem(node, "active")->valueint; active = cJSON_GetObjectItem(node, "active")->valueint;
} }
l->x += (GRID_CELL_WIDTH / 2); l->x += (SCREEN_WIDTH / 2);
l->y += (GRID_CELL_HEIGHT / 2); l->y += (SCREEN_HEIGHT / 2);
l->active = active; l->active = active;
node = node->next; node = node->next;

View File

@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
typedef struct Texture Texture; typedef struct Texture Texture;
typedef struct Lookup Lookup; typedef struct Lookup Lookup;
typedef struct Weapon Weapon; typedef struct Weapon Weapon;
typedef struct Quadtree Quadtree;
typedef struct Entity Entity; typedef struct Entity Entity;
typedef struct Bullet Bullet; typedef struct Bullet Bullet;
typedef struct Debris Debris; typedef struct Debris Debris;
@ -263,9 +264,12 @@ struct StarSystem {
StarSystem *next; StarSystem *next;
}; };
struct GridCell { struct Quadtree {
Entity *entity; int depth;
GridCell *next; int x, y, w, h;
Entity *ents[QT_MAX_ENTS];
int numEnts;
Quadtree *node[4];
}; };
typedef struct { typedef struct {
@ -298,7 +302,7 @@ typedef struct {
Location locationHead, *locationTail; Location locationHead, *locationTail;
struct cJSON *missionJSON; struct cJSON *missionJSON;
unsigned int stats[STAT_MAX]; unsigned int stats[STAT_MAX];
GridCell grid[GRID_SIZE][GRID_SIZE]; Quadtree quadtree;
} Battle; } Battle;
struct ScriptRunner { struct ScriptRunner {