/* Copyright (C) 2018 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 "radar.h" static void logic(void); static void draw(void); static void getMapTileColor(int i, SDL_Color *c); static void drawMap(void); static void drawEntities(void); static int isValidBlip(Entity *e); static void getBlipColor(Entity *e, SDL_Color *c); static void drawMarkers(void); static void initMarker(int i, int x, int y, int angle, int type); static void initBlips(void); static void enableMarker(int type, int i); static SDL_Rect viewRect; static Texture *atlasTexture; static Atlas *background; static Atlas *arrow; static int blinkTimer; static SDL_Point offset; static Marker marker[MAX_MARKERS]; static Entity *blips[MAX_BLIPS]; void initRadar(void) { SDL_Rect limits; int renderWidth, renderHeight; renderWidth = (app.config.winWidth / MAP_TILE_SIZE) + 1; renderHeight = (app.config.winHeight / MAP_TILE_SIZE) + 1; startSectionTransition(); memset(blips, 0, sizeof(Entity*) * MAX_BLIPS); memset(marker, 0, sizeof(Marker) * MAX_MARKERS); app.delegate.logic = &logic; app.delegate.draw = &draw; viewRect.x = (world.bob->x / MAP_TILE_SIZE) - (VIEW_SIZE_X / 2); viewRect.y = (world.bob->y / MAP_TILE_SIZE) - (VIEW_SIZE_Y / 2); viewRect.w = VIEW_SIZE_X; viewRect.h = VIEW_SIZE_Y; limits.x = world.map.bounds.x / MAP_TILE_SIZE; limits.y = world.map.bounds.y / MAP_TILE_SIZE; limits.w = (world.map.bounds.w / MAP_TILE_SIZE) - (VIEW_SIZE_X - renderWidth) - 1; limits.h = (world.map.bounds.h / MAP_TILE_SIZE) - (VIEW_SIZE_Y - renderHeight); viewRect.x = limit(viewRect.x, limits.x, limits.w); viewRect.y = limit(viewRect.y, limits.y, limits.h); if (viewRect.y > limits.h) { viewRect.y -= (viewRect.y - limits.h); } blinkTimer = 0; atlasTexture = getTexture("gfx/atlas/atlas.png"); background = getImageFromAtlas("gfx/radar/background.png"); arrow = getImageFromAtlas("gfx/radar/arrow.png"); /* top */ initMarker(0, app.config.winWidth / 2 - 275, app.config.winHeight / 2 - 275, 0, M_MIA); initMarker(1, app.config.winWidth / 2, app.config.winHeight / 2 - 275, 0, M_ITEM); initMarker(2, app.config.winWidth / 2 + 275, app.config.winHeight / 2 - 275, 0, M_ENEMY); /* bottom */ initMarker(3, app.config.winWidth / 2 - 275, app.config.winHeight / 2 + 275, 180, M_MIA); initMarker(4, app.config.winWidth / 2, app.config.winHeight / 2 + 275, 180, M_ITEM); initMarker(5, app.config.winWidth / 2 + 275, app.config.winHeight / 2 + 275, 180, M_ENEMY); /* left */ initMarker(6, app.config.winWidth / 2 - 450, app.config.winHeight / 2 - 200, 270, M_MIA); initMarker(7, app.config.winWidth / 2 - 450, app.config.winHeight / 2, 270, M_ITEM); initMarker(8, app.config.winWidth / 2 - 450, app.config.winHeight / 2 + 200, 270, M_ENEMY); /* right */ initMarker(9, app.config.winWidth / 2 + 450, app.config.winHeight / 2 - 200, 90, M_MIA); initMarker(10, app.config.winWidth / 2 + 450, app.config.winHeight / 2, 90, M_ITEM); initMarker(11, app.config.winWidth / 2 + 450, app.config.winHeight / 2 + 200, 90, M_ENEMY); initBlips(); offset.x = ((app.config.winWidth - (RADAR_TILE_SIZE * VIEW_SIZE_X)) / 2); offset.y = ((app.config.winHeight - (RADAR_TILE_SIZE * VIEW_SIZE_Y)) / 2); endSectionTransition(); } static void initMarker(int i, int x, int y, int angle, int type) { marker[i].x = x; marker[i].y = y; marker[i].angle = angle; marker[i].type = type; } static void initBlips(void) { Entity *e; int i, x, y; i = 0; for (e = world.entityHead.next ; e != NULL ; e = e->next) { if (isValidBlip(e)) { x = (e->x / MAP_TILE_SIZE); y = (e->y / MAP_TILE_SIZE); if (y < viewRect.y) { enableMarker(e->type, M_MIA); } if (y > viewRect.y + viewRect.h) { enableMarker(e->type, M_MIA + (M_MAX)); } if (x < viewRect.x) { enableMarker(e->type, M_MIA + (M_MAX * 2)); } if (x > viewRect.x + viewRect.w) { enableMarker(e->type, M_MIA + (M_MAX * 3)); } if (i < MAX_BLIPS) { blips[i++] = e; } } } } static void enableMarker(int type, int i) { switch (type) { case ET_BOB: case ET_MIA: case ET_TEEKA: marker[i].visible = 1; break; case ET_HEART: case ET_CELL: case ET_KEY: case ET_ITEM: marker[i + 1].visible = 1; break; case ET_ENEMY: case ET_BOSS: case ET_DESTRUCTABLE: case ET_ITEM_PAD: marker[i + 2].visible = 1; break; default: break; } } static void logic(void) { int i; Marker *m; blinkTimer++; blinkTimer %= 60; for (i = 0 ; i < MAX_MARKERS ; i++) { m = &marker[i]; if (i / 3 % 2 == 0) { m->value += 0.1; } else { m->value -= 0.1; } if (i < 6) { m->y += (float) sin(m->value); } else { m->x += (float) sin(m->value); } } if (isControl(CONTROL_MAP)) { pauseSound(0); clearControl(CONTROL_MAP); exitRadar(); } } static void draw(void) { blitRectScaled(atlasTexture->texture, 0, 0, app.config.winWidth, app.config.winHeight, &background->rect, 0); drawMap(); drawEntities(); drawMarkers(); drawRect((app.config.winWidth / 2) - 230, app.config.winHeight - 58, 14, 14, 255, 255, 0, 255); drawText((app.config.winWidth / 2) - 200, app.config.winHeight - 65, 20, TA_LEFT, colors.yellow, app.strings[ST_MIAS]); drawRect((app.config.winWidth / 2) - 30, app.config.winHeight - 58, 14, 14, 0, 255, 255, 255); drawText((app.config.winWidth / 2), app.config.winHeight - 65, 20, TA_LEFT, colors.cyan, app.strings[ST_ITEMS]); drawRect((app.config.winWidth / 2) + 170, app.config.winHeight - 58, 14, 14, 255, 0, 0, 255); drawText((app.config.winWidth / 2) + 200, app.config.winHeight - 65, 20, TA_LEFT, colors.red, app.strings[ST_TARGETS]); } static void drawMap(void) { int x, y, mx, my, i; SDL_Color c; for (x = 0 ; x < viewRect.w ; x++) { for (y = 0 ; y < viewRect.h ; y++) { mx = viewRect.x + x; my = viewRect.y + y; drawRect(offset.x + (x * RADAR_TILE_SIZE), offset.y + (y * RADAR_TILE_SIZE), RADAR_TILE_SIZE - 1, RADAR_TILE_SIZE - 1, 0, 0, 0, 255); if (isWithinMap(mx, my)) { i = world.map.data[mx][my]; if (i > MAP_TILE_AIR && i < MAP_TILE_NON_SOLID) { getMapTileColor(i, &c); drawRect(offset.x + (x * RADAR_TILE_SIZE), offset.y + (y * RADAR_TILE_SIZE), RADAR_TILE_SIZE - 1, RADAR_TILE_SIZE - 1, c.r, c.g, c.b, 255); } } } } drawOutlineRect(offset.x, offset.y, viewRect.w * RADAR_TILE_SIZE, viewRect.h * RADAR_TILE_SIZE, 0, 128, 0, 255); } static void getMapTileColor(int i, SDL_Color *c) { c->r = c->g = c->b = 0; switch (i) { case MAP_TILE_WATER: c->b = 255; break; case MAP_TILE_SLIME: c->g = 255; break; case MAP_TILE_LAVA: c->g = 128; c->r = 255; break; default: if (i < MAP_TILE_NON_SOLID) { c->r = c->g = c->b = 168; } break; } } static void drawEntities(void) { Entity *e; int i, x, y; SDL_Color c; for (i = 0 ; i < MAX_BLIPS ; i++) { e = blips[i]; if (e != NULL) { x = (e->x / MAP_TILE_SIZE); y = (e->y / MAP_TILE_SIZE); if (x >= viewRect.x && x < viewRect.x + viewRect.w && y >= viewRect.y && y < viewRect.y + viewRect.h) { x -= viewRect.x; y -= viewRect.y; getBlipColor(e, &c); if (blinkTimer < 30) { drawRect(offset.x + (x * RADAR_TILE_SIZE), offset.y + (y * RADAR_TILE_SIZE), RADAR_TILE_SIZE - 1, RADAR_TILE_SIZE - 1, c.r, c.g, c.b, 255); } } } } } static int isValidBlip(Entity *e) { Item *i; if (!(e->flags & (EF_GONE | EF_TELEPORTING))) { switch (e->type) { case ET_BOB: case ET_MIA: case ET_TEEKA: case ET_BOSS: case ET_HEART: case ET_CELL: case ET_KEY: case ET_DESTRUCTABLE: return 1; case ET_ITEM: i = (Item*)e; return i->canBeCarried || i->canBePickedUp || i->isMissionTarget; case ET_ENEMY: return e->isMissionTarget || ((Unit*)e)->carriedItem != NULL || world.isEliminateAllEnemies; case ET_ITEM_PAD: return !e->active; default: return 0; } } return 0; } static void getBlipColor(Entity *e, SDL_Color *c) { Unit *u; c->r = c->g = c->b = 0; switch (e->type) { case ET_BOB: c->r = c->g = c->b = 255; break; case ET_ENEMY: u = (Unit*)e; if (u->carriedItem != NULL) { c->g = 168; c->b = 255; } else { c->r = 255; } break; case ET_BOSS: case ET_DESTRUCTABLE: case ET_ITEM_PAD: c->r = 255; break; case ET_TEEKA: case ET_MIA: c->r = c->g = 255; break; case ET_HEART: case ET_CELL: case ET_KEY: case ET_ITEM: c->g = 168; c->b = 255; break; default: break; } } static void drawMarkers(void) { int i; for (i = 0 ; i < MAX_MARKERS ; i++) { if (marker[i].visible) { switch (i % M_MAX) { case M_MIA: SDL_SetTextureColorMod(atlasTexture->texture, 255, 255, 0); break; case M_ITEM: SDL_SetTextureColorMod(atlasTexture->texture, 0, 192, 255); break; case M_ENEMY: SDL_SetTextureColorMod(atlasTexture->texture, 255, 0, 0); break; } blitRectRotated(atlasTexture->texture, marker[i].x, marker[i].y, &arrow->rect, marker[i].angle); } } SDL_SetTextureColorMod(atlasTexture->texture, 255, 255, 255); }