#include #include "art/game_hud.h" #include "art/game_npcs.h" #include "device/device.h" #include "sys/sys.h" #include "game.h" // If this isn't enough, raise the number #define GAME_NPCS_N 32 typedef struct { uint8_t main; // alt0 and alt1 are ramps uint8_t alt0_0; uint8_t alt0_1; uint8_t alt1_0; uint8_t alt1_1; uint8_t eye_0; uint8_t eye_1; uint8_t pupil; uint8_t adornment; uint8_t shine; } game_npc_palette; game_npc_palette game_npc_palettes[1] = { {14, 12, 13, 6, 7, 6, 7, 0, 8, 7} }; #define GAME_NPC_N_PALETTES (sizeof(game_npc_palettes)/sizeof(game_npc_palettes[0])) sys_i32 game_npc_next = 0; game_npc game_npcs[GAME_NPCS_N]; game_npc* game_npc_create(sys_i32 x, sys_i32 y) { assert(game_npc_next < GAME_NPCS_N && "too many NPCs"); sys_i32 id = game_npc_next++; game_npc npc = { .x = x, .y = y, .sprite_id = 0, .palette_id = 0, .inflict_id = 0, .face_left = false, .n_dialogues = 0, .no_cake_dialogue = NULL, /* .dialogues = { doesn't matter }, */ .present = true, .n_dialogues_seen = 0, .received_cake = false, }; game_npcs[id] = npc; return &game_npcs[id]; } void game_npc_trigger_dialogue(sys_i32 npc_id); void game_npcs_update(bool* allow_input) { if (!*allow_input) { return; } // check collision with player sys_i32 player_x, player_y; game_player_get_center(&player_x, &player_y); for (sys_i32 i = 0; i < game_npc_next; i++) { game_npc* n = &game_npcs[i]; if (!n->present) { continue; } sys_i32 r_distcheck = 21 * PIXEL_SZ_MICROPIXEL; int64_t dx = player_x - n->x; int64_t dy = player_y - n->y; if ( sys_btnp(DEVICE_BUTTON_0, false) && dx * dx + dy * dy <= r_distcheck * r_distcheck ) { n->face_left = dx < 0; game_npc_trigger_dialogue(i); *allow_input = false; } } } void game_npc_trigger_dialogue(sys_i32 npc_id) { const char* dialogue; // TODO: Make it possible for the player to have the cake game_npc* npc = &game_npcs[npc_id]; if ( !npc->received_cake && game_player_collectibles.n_cake == 0 && npc->no_cake_dialogue != NULL ) { dialogue = npc->no_cake_dialogue; } else if (npc->n_dialogues_seen < npc->n_dialogues) { dialogue = npc->dialogues[npc->n_dialogues_seen++]; } else if (npc->n_dialogues > 0) { dialogue = npc->dialogues[npc->n_dialogues - 1]; } else { // nothing to do with this npc return; } // give the NPC cake if possible if (!npc->received_cake && game_player_collectibles.n_cake > 0) { npc->received_cake = true; game_player_collectibles.n_cake -= 1; } game_dialogue_display(dialogue); } void game_npcs_draw() { for (sys_i32 i = 0; i < game_npc_next; i++) { game_npc* n = &game_npcs[i]; if (!n->present) { continue; } game_npc_palette palette = game_npc_palettes[n->palette_id % GAME_NPC_N_PALETTES]; if (n->received_cake) { sys_sprite_draw_ext( spr_game_hud, 0, n->x / PIXEL_SZ_MICROPIXEL - 4, n->y / PIXEL_SZ_MICROPIXEL - 18, 1, 1, !n->face_left, false ); } sys_dpal_set(14, palette.main); sys_dpal_set(12, palette.alt0_0); sys_dpal_set(13, palette.alt0_1); sys_dpal_set(6, palette.alt1_0); sys_dpal_set(7, palette.alt1_1); sys_dpal_set(9, palette.eye_0); sys_dpal_set(10, palette.eye_1); sys_dpal_set(1, palette.pupil); sys_dpal_set(8, palette.adornment); sys_dpal_set(11, palette.shine); // TODO: Palette sys_sprite_draw_ext( spr_game_npcs, n->sprite_id, n->x / PIXEL_SZ_MICROPIXEL - 8, n->y / PIXEL_SZ_MICROPIXEL - 8, 2, 2, n->face_left, false ); sys_dpal_reset(); } }