view src/creep.c @ 14:5c7f33441e43

Creeps now move towards the goal
author Mike Pavone <pavone@retrodev.com>
date Sun, 12 Jan 2014 18:16:51 -0800
parents d118fe8fb1db
children 08f2bcf3447f
line wrap: on
line source

#include <genesis.h>
#include "creep.h"

creep creeps[MAX_CREEPS];
u16 cur_creeps;
extern u16 tilemap[40*28];

u16 distances[20*14];

const s16 speeds[NUM_SPECIES] = { 2 };

u16 spawn_creep(u8 species, s16 x, s16 y)
{
	u16 index;
	for (index = 0; index < MAX_SPRITE; index++)
	{
		if (spriteDefCache[index].posx == -0x80) {
			break;
		}
	}
	if (index > 0) {
		VDP_setSprite(index, x, y, SPRITE_SIZE(1, 1), TILE_ATTR_FULL(2, 0, 0, 0, 'C' + TILE_FONTINDEX), spriteDefCache[0].link);
		spriteDefCache[0].link = index;
	} else {
		VDP_setSprite(index, x, y, SPRITE_SIZE(1, 1), TILE_ATTR_FULL(2, 0, 0, 0, 'C' + TILE_FONTINDEX), 0);
	}
	creeps[cur_creeps].index = index;
	creeps[cur_creeps].health = 1000;
	creeps[cur_creeps].species = species;
	creeps[cur_creeps].direction = 0;
	creeps[cur_creeps].targetx = x;
	creeps[cur_creeps].targety = y;
	return cur_creeps++;
}

typedef struct {
	u16 index;
	u16 x;
	u16 y;
} mpoint;

s16 explore(mpoint * points, s16 num_points, u16 src, u16 srcx, u16 srcy)
{
	u16 x,y,index,cindex,xmax,ymax,ystrt,dist;
	dist = distances[src]+1;
	xmax = srcx < 19 ? srcx+1 : srcx;
	ymax = srcy < 13 ? srcy+1 : srcy;
	if (srcy)
	{
		ystrt = srcy-1;
		cindex = srcx ? src - 21 : src - 20;
	} else {
		ystrt = srcy;
		cindex = srcx ? src - 1 : src;
	}
	for (x = srcx ? srcx-1 : srcx; x <= xmax; x++, cindex++)
	{
		for (y = ystrt, index=cindex; y<=ymax; y++,index+=20)
		{
			if (distances[index] > dist && !tilemap[x*2+y*2*40])
			{
				distances[index] = dist;
				if (dist == 0xFFFF)
				{
					tilemap[x*2 + y*2*40] = TILE_ATTR_FULL(2, 0, 0, 0, 'E' - 32 + TILE_FONTINDEX);
				}
				points[num_points].index = index;
				points[num_points].x = x;
				points[num_points++].y = y;
			}
		}
	}
	return num_points;
}

void gen_distances(u16 x, u16 y)
{
	//TODO: Figure out the actual maximum number of candidate points that can exist
	mpoint pointsa[20*14];
	mpoint pointsb[20*14];
	mpoint *points=pointsa;
	mpoint *new_points;
	s16 num_points = 0, old_points;
	x /= 2;
	y /= 2;
	memset(distances, 0xFF, sizeof(distances));

	distances[x + y*20] = 0;
	num_points = explore(points, num_points, x + y*20, x, y);

	while (num_points)
	{
		new_points = points == pointsa ? pointsb : pointsa;
		old_points = num_points;
		for (num_points = 0, old_points--; old_points >= 0; old_points--)
		{
			num_points = explore(new_points, num_points, points[old_points].index, points[old_points].x, points[old_points].y);
		}
		points = new_points;
	}
}

void print_distances(void)
{
	u16 x,y,tindex,dindex,dist;
	for (y = 0; y < 14; y++)
	{
		dindex = y * 20;
		tindex = y * 2 * 40;
		for (x = 0; x < 20; x++, dindex++, tindex += 2)
		{
			dist = distances[dindex];
			if (dist < 10000)
			{
				tilemap[tindex+41] = TILE_ATTR_FULL(3, 0, 0, 0, '0' - 32 + dist % 10 + TILE_FONTINDEX);
				dist /= 10;
				if (dist)
				{
					tilemap[tindex+40] = TILE_ATTR_FULL(3, 0, 0, 0, '0' - 32 + dist % 10 + TILE_FONTINDEX);
					dist /= 10;
					if (dist)
					{
						tilemap[tindex+1] = TILE_ATTR_FULL(3, 0, 0, 0, '0' - 32 + dist % 10 + TILE_FONTINDEX);
						dist /= 10;
						if (dist)
							tilemap[tindex] = TILE_ATTR_FULL(3, 0, 0, 0, '0' - 32 + dist % 10 + TILE_FONTINDEX);
					}
				}
			}
		}
	}
}

void update_creeps(void)
{
	s16 i, disty, distx, mdist;
	for (i = cur_creeps-1; i >= 0; --i)
	{
		creep *cur = creeps + i;
		SpriteDef * sprite = spriteDefCache + cur->index;
		distx = sprite->posx - cur->targetx;
		if (distx < 0)
			distx = -distx;
		disty = sprite->posy - cur->targety;
		if (disty < 0)
			disty = -disty;
		mdist = distx > disty ? distx : disty;
		if (mdist < speeds[cur->species])
		{
			s16 dindex = sprite->posx / 16 + (sprite->posy / 16) * 20;
			if (distances[dindex])
			{
				u16 bestdist = 0xFFFF;
				s16 bestindex = 0xFFFF,diff,next;
				if (sprite->posx > 8 && distances[dindex-1] < bestdist)
				{
					bestindex = dindex-1;
					bestdist = distances[bestindex];
				}
				if (sprite->posx < (320-16) && distances[dindex+1] < bestdist)
				{
					bestindex = dindex+1;
					bestdist = distances[bestindex];
				}
				if (sprite->posy > 8 && distances[dindex-20] < bestdist)
				{
					bestindex = dindex-20;
					bestdist = distances[bestindex];
				}
				if (sprite->posy < (224-16) && distances[dindex+20] < bestdist)
				{
					bestindex = dindex+20;
					bestdist = distances[bestindex];
				}
				diff = bestindex-dindex;
				next = bestindex + diff;
				while (next >= 0 && next < 20*14 && distances[next] < bestdist)
				{
					bestindex = next;
					bestdist = distances[bestindex];
				}
				cur->targetx = (bestindex % 20) * 16 + 4;
				cur->targety = (bestindex / 20) * 16 + 4;
			} else {
				//creep is at the goal
				VDP_setSpritePosition(cur->index, -0x80, -0x80);
				cur_creeps--;
				if (i != cur_creeps)
				{
					memcpy(cur, creeps+cur_creeps, sizeof(creep));
				}
			}
		} else {
			if (distx > disty) {
				VDP_setSpritePosition(cur->index,
					sprite->posx + (sprite->posx > cur->targetx ? -speeds[cur->species] : speeds[cur->species]),
					sprite->posy);
			} else {
				VDP_setSpritePosition(cur->index,
					sprite->posx,
					sprite->posy + (sprite->posy > cur->targety ? -speeds[cur->species] : speeds[cur->species]));
			}
		}
	}
}