#include #include #include #include "draw.h" #include "main.h" #include "items.h" #include "level.h" #include "paths.h" #include "gfx/gfx.h" #include "gfx/tiles.h" #define SPRITES_HEIGHT_ABOVE 4 #define SPRITES_HEIGHT_CARGO 6 #define PALETTE_COLOR_TRSP 0 // magenta #define PALETTE_COLOR_BLACK 1 #define PALETTE_COLOR_WHITE 192 /* rgb(255, 255, 255) */ #define PALETTE_COLOR_GREY 193 /* rgb(128, 128, 128) */ #define PALETTE_COLOR_GRASS 194 /* rgb(140, 182, 66) */ #define PALETTE_COLOR_OCEAN 195 /* rgb( 41, 125, 165) */ #define PALETTE_COLOR_RED 243 /* rgb(206, 65, 66) */ #define PALETTE_COLOR_GREEN 235 /* rgb( 58, 174, 41) */ #define PALETTE_COLOR_BLUE 231 /* rgb( 49, 158, 189) */ #define PALETTE_COLOR_YELLOW 251 /* rgb(197, 150, 41) */ #define PALETTE_COLOR_LIGHT 24 /* rgb(230, 231, 230) */ #define PALETTE_COLOR_PURPLE 26 /* rgb(247, 146, 230) */ static const uint8_t PALETTE_COLORS[7] = { PALETTE_COLOR_BLACK, PALETTE_COLOR_RED, PALETTE_COLOR_GREEN, PALETTE_COLOR_BLUE, PALETTE_COLOR_YELLOW, PALETTE_COLOR_LIGHT, PALETTE_COLOR_PURPLE, }; #define TILE_SPRITE_SIZE (2+(20*20)) #define ROAD_SPRITE_COUNT 16 static uint8_t water_sprite[TILE_SPRITE_SIZE]; static uint8_t grass_sprite[TILE_SPRITE_SIZE]; static uint8_t roads_sprites[TILE_SPRITE_SIZE * ROAD_SPRITE_COUNT]; #define SPRITES(index) tiles_tiles_data[(index)] #define SPRITE_WATER_SIDE (&tiles_tile_0_data[0]) #define SPRITE_GRASS_SIDE (&tiles_tile_1_data[0]) #define SPRITES_ROAD(index) (&roads_sprites[(index)*TILE_SPRITE_SIZE]) #define SPRITES_TRUCK(color,dir) trucks_tiles_data[(((color-1) * 4) + (dir))] #define SPRITES_CARGO(color) cargos_tiles_data[(color-1)] #define SPRITES_HOUSE(color,light) houses_tiles_data[((color-1) * 2) + (light)] #define SPRITES_DROPP(enabled) droppoints_tiles_data[(enabled)] #define SPRITES_BUTTN(color,pressed) buttons_tiles_data[(color * 2) + (pressed)] #define SPRITES_BRIDG(color,status) bridges_tiles_data[(color * 4) + (status)] #define SPRITE_ROAD_L_INDEX 0x4 #define SPRITE_ROAD_LR_INDEX 0x6 #define SPRITE_ROAD_R_INDEX 0x2 #define SPRITE_TRUCK_L_INDEX 1 #define SPRITE_TRUCK_RED_INDEX 1 #define SPRITE_TRUCK_R_INDEX 2 #define DELTA_XY_CARGO (0x68) #define DELTA_XY_HOUSE (0x11) #define DELTA_XY_TRUCK (0x10) #define DELTA_XY_DROPP (0x59) #define DELTA_XY_BUTTN (0x49) #define DELTA_XY_BRIDG (0x00) gfx_sprite_t *gfx_CopySprite(gfx_sprite_t *sprite_in, gfx_sprite_t *sprite_out) { uint8_t* in = (uint8_t*) sprite_in; uint8_t* out = (uint8_t*) sprite_out; uint8_t w = (*out++ = *in++); uint8_t h = (*out++ = *in++); memcpy(out, in, w*h); return sprite_out; } void draw_tiles_init(uint8_t count, const void** src, unsigned char* dst, const uint8_t* base, const uint8_t* rots) { typedef gfx_sprite_t* fun_t(gfx_sprite_t*, gfx_sprite_t*); uint8_t i = count; do { fun_t* fun = &gfx_CopySprite; switch (*rots++) { case 1: fun = &gfx_RotateSpriteC; break; case 2: fun = &gfx_RotateSpriteHalf; break; case 3: fun = &gfx_RotateSpriteCC; break; } (fun)( (gfx_sprite_t*) src[*base++], (gfx_sprite_t*) dst ); dst += TILE_SPRITE_SIZE; } while (--i); } void draw_ground_init(void) { water_sprite[0] = 20; water_sprite[1] = 20; memset(&water_sprite[2], PALETTE_COLOR_OCEAN, 20*20); grass_sprite[0] = 20; grass_sprite[1] = 20; memset(&grass_sprite[2], PALETTE_COLOR_GRASS, 20*20); } void draw_roads_init(void) { static const uint8_t base[ROAD_SPRITE_COUNT] = {0,1,1,2, 1,2,3,4, 1,3,2,4, 2,4,4,5}; static const uint8_t rots[ROAD_SPRITE_COUNT] = {0,2,1,2, 3,3,0,2, 0,3,1,1, 0,3,0,0}; draw_tiles_init(ROAD_SPRITE_COUNT, roads_tiles_data, roads_sprites, base, rots); } void draw_init(void) { gfx_Begin(); gfx_SetPalette(global_palette, sizeof_global_palette, 0); gfx_SetDrawBuffer(); gfx_SetTransparentColor(PALETTE_COLOR_TRSP); gfx_SetTextFGColor(PALETTE_COLOR_BLACK); } void draw_done(void) { gfx_SwapDraw(); } void draw_exit(void) { gfx_End(); } void draw_sprite_full(uint8_t x, uint8_t y, unsigned char* sprite) { gfx_Sprite_NoClip( (gfx_sprite_t*) sprite, (x-1)*20 + ((320 - 220) / 2), (y-1)*20 + ((240 - 232) / 2) + 1 + SPRITES_HEIGHT_ABOVE ); } void draw_sprite(uint8_t x, uint8_t y, unsigned char* sprite, int dx, int dy) { gfx_TransparentSprite_NoClip( (gfx_sprite_t*) sprite, (x-1)*20 + ((320 - 220) / 2) + dx, (y-1)*20 + ((240 - 232) / 2) + 1 + dy ); } void gfx_Or_TransparentSprite_NoClip(gfx_sprite_t* sprite, uint24_t x, uint8_t y); void draw_sprite_or(uint8_t x, uint8_t y, unsigned char* sprite) { gfx_Or_TransparentSprite_NoClip( (gfx_sprite_t*) sprite, (x-1)*20 + ((320 - 220) / 2), (y-1)*20 + ((240 - 232) / 2) + 1 + SPRITES_HEIGHT_ABOVE ); } void draw_bubble(int x, int y, int w, int h) { uint8_t d; for (d = 0; d <= 1; ++d) { int dx = (w-3)*d + x+1; int dy = (h-3)*d + y+1; gfx_SetColor(PALETTE_COLOR_BLACK); gfx_HorizLine_NoClip(x+4, (h-1)*d + y, w-8); gfx_HorizLine_NoClip(x+2, dy, w-4); gfx_VertLine_NoClip((w-1)*d + x, y+4, h-8); gfx_VertLine_NoClip(dx, y+2, h-4); gfx_SetColor(PALETTE_COLOR_WHITE); gfx_HorizLine_NoClip(x+4, dy, w-8); gfx_VertLine_NoClip(dx, y+4, h-8); } gfx_FillRectangle_NoClip(x+2, y+2, w-4, h-4); } void draw_bubble_thick(int x, int y, int w, int h) { draw_bubble(x,y,w,h); draw_bubble(x,y+1,w,h-2); draw_bubble(x+1,y,w-2,h); draw_bubble(x+1,y+1,w-2,h-2); } void draw_bubble_arrow(int x, int y) { uint8_t l; for (l = 7; l > 0; --l, ++y) { gfx_SetColor(PALETTE_COLOR_BLACK); gfx_HorizLine_NoClip(x, y, l); if (l > 2) { gfx_SetColor(PALETTE_COLOR_WHITE); gfx_HorizLine_NoClip(x+1, y, l-2); } } } void draw_menu_road(int x, int y) { if (x < 0) x -= ((x / 20) + 1) * 20; else gfx_Sprite((gfx_sprite_t*) SPRITES_ROAD(SPRITE_ROAD_R_INDEX), x -= 20, y); for (; x < 320 ;) gfx_Sprite((gfx_sprite_t*) SPRITES_ROAD(SPRITE_ROAD_LR_INDEX), x += 20, y); } void draw_menu_truck(int x, int y, int d) { gfx_TransparentSprite( (gfx_sprite_t*) SPRITES_TRUCK(SPRITE_TRUCK_RED_INDEX, d < 0 ? SPRITE_TRUCK_L_INDEX : SPRITE_TRUCK_R_INDEX), x, y ); } void draw_house(int x, int y, uint8_t c, uint8_t l) { gfx_TransparentSprite( (gfx_sprite_t*) SPRITES_HOUSE(c+1,l), x, y ); } void draw_cursor(void) { int x = (paths_cursor_x-1) * 20 + ((320 - 220) / 2); int y = (paths_cursor_y-1) * 20 + ((240 - 232) / 2) + 1 + SPRITES_HEIGHT_ABOVE; gfx_SetColor(PALETTE_COLORS[paths_cursor_col]); gfx_Rectangle_NoClip(x-1, y-1, 20+1+1, 20+1+1); gfx_Rectangle_NoClip(x-2, y-2, 20+2+2, 20+2+2); } void draw_level_name(uint16_t level_index, int x, int y) { static char text_buffer[] = {'L','e','v','e','l',' ',' ',' ',' ','0','0','0','\0'}; text_buffer[11] = (level_index % 10) + '0'; text_buffer[10] = (level_index < 10 ? ' ' : ((level_index / 10) % 10) + '0'); text_buffer[9] = (level_index < 100 ? ' ' : (level_index / 100) + '0'); gfx_PrintStringXY(text_buffer, x, y); } void draw_level_ground(void) { gfx_FillScreen(PALETTE_COLOR_OCEAN); { uint8_t y; for (y = 1; y <= 11 + 1; ++y) { uint8_t x; for (x = 1; x <= 11; ++x) { uint8_t index = y*16+x; unsigned char* sprite; switch (cells_ground_type[index]) { case GROUND_WATER: sprite = water_sprite; break; case GROUND_GRASS: sprite = grass_sprite; break; case GROUND_ROAD: if (cells_item_type[index] == ITEM_BRIDGE) { draw_sprite_full(x,y,water_sprite); sprite = SPRITES_BRIDG(cells_item_color[index], cells_item_state[index]); draw_sprite(x,y,sprite, (DELTA_XY_BRIDG >> 4), (DELTA_XY_BRIDG & 0x0F)); continue; } sprite = SPRITES_ROAD(cells_ground_links[index] >> 4); break; default: if (cells_ground_type[index-16] == GROUND_NONE) { continue; } sprite = (cells_ground_type[index-16] == GROUND_WATER) ? SPRITE_WATER_SIDE : SPRITE_GRASS_SIDE; } draw_sprite_full(x,y,sprite); } } } } void draw_level_items(void) { uint8_t y; for (y = 1; y <= 11 + 1; ++y) { uint8_t x; for (x = 1; x <= 11; ++x) { uint8_t index = y*16+x; unsigned char* sprite; switch (cells_item_type[index]) { case ITEM_CARGO: sprite = SPRITES_CARGO(cells_item_color[index]); index = DELTA_XY_CARGO; break; //case ITEM_TRUCK: sprite = SPRITES_TRUCK(cells_item_color[index], cells_item_state[index]); index = DELTA_XY_TRUCK; break; case ITEM_HOUSE: sprite = SPRITES_HOUSE(cells_item_color[index], cells_item_state[index]); index = DELTA_XY_HOUSE; break; case ITEM_DROPPOINT: sprite = SPRITES_DROPP(cells_item_state[index]); index = DELTA_XY_DROPP; break; case ITEM_BUTTON: sprite = SPRITES_BUTTN(cells_item_color[index], cells_item_state[index]); index = DELTA_XY_BUTTN; break; default: continue; } draw_sprite(x,y,sprite,((uint8_t)(index >> 4)),((uint8_t)(index & 0x0F))); } } } void draw_level_trucks(void) { static const int8_t deltas_x_dir[] = { 8-2, 11-2, 4-2, 8-2}; static const int8_t deltas_y_dir[] = {10-6, 10-6, 10-6, 3-6}; const struct truck* truck = &level_trucks[0]; uint8_t index; for (index = 0; index < level.count.trucks; ++truck, ++index) { const uint8_t x = truck->position & 0x0F; const uint8_t y = truck->position >> 4; const uint8_t direction = (truck->directions_last_next >> 4) - 1; draw_sprite(x,y,SPRITES_TRUCK(truck->color,direction),DELTA_XY_TRUCK >> 4,DELTA_XY_TRUCK & 0x0F); { int8_t dx = deltas_x_dir[direction]; int8_t dy = deltas_y_dir[direction] + (y==1); uint8_t cargo_index = 3; do { if (truck->cargos[--cargo_index] != COLOR_NONE) { unsigned char* sprite = SPRITES_CARGO(truck->cargos[cargo_index]); draw_sprite(x, y, sprite, dx, dy); dy -= SPRITES_HEIGHT_CARGO - (y==1); } } while (cargo_index); } } } void draw_smoke(uint8_t x, uint8_t y) { int sx = (x-1)*20 + ((320 - 220) / 2); int sy = (y-1)*20 + ((240 - 232) / 2) + 1; draw_bubble_thick(sx+1, sy+1, 20 - 2, 20 + SPRITES_HEIGHT_ABOVE - 2); gfx_PrintStringXY("!", sx + (20/2 - 2/2), sy + ((20 + SPRITES_HEIGHT_ABOVE)/2 - 7/2)); }