Get NPCs showing up in-engine

This commit is contained in:
Pyrex 2024-02-28 19:42:03 -08:00
parent 567db0bd71
commit f5f5e2c20b
8 changed files with 202 additions and 16 deletions

View File

@ -5,6 +5,7 @@ cc_library(
name = "game",
srcs = glob(["*.c"]) + [
"art/game_collectibles.c",
"art/game_npcs.c",
"art/game_player.c",
"art/game_tiles.c",
"map/game_map.c",

View File

@ -30,6 +30,7 @@ void game_update() {
game_frame += 1;
game_collectibles_update();
game_npcs_update();
game_player_update();
}
@ -41,6 +42,7 @@ void game_draw() {
sys_map_draw(map_game_map, spr_game_tiles, 0, 0, 0, 0, map_game_map.width, map_game_map.height);
game_collectibles_draw();
game_npcs_draw();
game_player_draw();
sys_camera_reset();

View File

@ -4,6 +4,7 @@
#include "game_collectible.h"
#include "game_collision.h"
#include "game_math.h"
#include "game_npc.h"
#include "game_palette.h"
#include "game_player.h"

View File

@ -1 +1,91 @@
#include "game_npc.h"
#include <assert.h>
#include "art/game_npcs.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,
};
game_npcs[id] = npc;
return &game_npcs[id];
}
void game_npcs_update() {
// TODO
}
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[game_npcs[i].palette_id % GAME_NPC_N_PALETTES];
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();
}
}

View File

@ -1,4 +1,31 @@
#ifndef GAME_NPC_H
#define GAME_NPC_H
#include "sys/sys.h"
#define GAME_NPC_MAX_N_DIALOGUES 16
typedef struct {
sys_i32 x;
sys_i32 y;
uint8_t sprite_id;
uint8_t palette_id;
uint8_t inflict_id;
bool face_left;
int n_dialogues;
const char* no_cake_dialogue;
const char* dialogues[GAME_NPC_MAX_N_DIALOGUES];
bool present;
int n_dialogues_seen;
} game_npc;
// pointer goes to data section and will be valid forever
game_npc* game_npc_create(sys_i32 x, sys_i32 y);
void game_npcs_update();
void game_npcs_draw();
#endif // GAME_NPC_H

View File

@ -11,7 +11,7 @@
"iid": "7db5fd20-b0a0-11ee-9688-af2c6adbc1d6",
"jsonVersion": "1.5.3",
"appBuildId": 473703,
"nextUid": 130,
"nextUid": 131,
"identifierStyle": "Lowercase",
"toc": [],
"worldLayout": "Free",
@ -3696,6 +3696,43 @@
"allowedRefsEntityUid": null,
"allowedRefTags": [],
"tilesetUid": null
},
{
"identifier": "face_left",
"doc": null,
"__type": "Bool",
"uid": 130,
"type": "F_Bool",
"isArray": false,
"canBeNull": false,
"arrayMinLength": null,
"arrayMaxLength": null,
"editorDisplayMode": "Hidden",
"editorDisplayScale": 1,
"editorDisplayPos": "Above",
"editorLinkStyle": "StraightArrow",
"editorDisplayColor": null,
"editorAlwaysShow": false,
"editorShowInWorld": true,
"editorCutLongValues": true,
"editorTextSuffix": null,
"editorTextPrefix": null,
"useForSmartColor": false,
"exportToToc": false,
"searchable": false,
"min": null,
"max": null,
"regex": null,
"acceptFileTypes": null,
"defaultOverride": null,
"textLanguageMode": null,
"symmetricalRef": false,
"autoChainRef": true,
"allowOutOfLevelRef": true,
"allowedRefs": "OnlySame",
"allowedRefsEntityUid": null,
"allowedRefTags": [],
"tilesetUid": null
}
]
}
@ -4216,7 +4253,11 @@
"id": "V_String",
"params": ["But you should go to the next screen."]
} ] },
{ "__identifier": "no_cake_dialogue", "__type": "String", "__value": null, "__tile": null, "defUid": 129, "realEditorValues": [] }
{ "__identifier": "no_cake_dialogue", "__type": "String", "__value": null, "__tile": null, "defUid": 129, "realEditorValues": [] },
{ "__identifier": "face_left", "__type": "Bool", "__value": true, "__tile": null, "defUid": 130, "realEditorValues": [{
"id": "V_Bool",
"params": [ true ]
}] }
],
"__worldX": 464,
"__worldY": 528

View File

@ -1,3 +1,4 @@
#include <assert.h>
#include "sys/sys.h"
#include "game/game.h"
#include "game_map.h"
@ -36,26 +37,44 @@ void map_game_map_collectible_money_small_create(sys_i32 x, sys_i32 y) {
);
}
game_npc* game_map_npc_in_progress = NULL;
void map_game_map_npc_create(sys_i32 x, sys_i32 y) {
// TODO
// center NPC
game_map_npc_in_progress = game_npc_create(
(x + 1) * TILE_SZ_MICROPIXEL,
(y + 1) * TILE_SZ_MICROPIXEL
);
}
void map_game_map_npc_set_sprite_id(sys_i32 id) {
// TODO
}
void map_game_map_npc_set_inflict_id(sys_i32 id) {
// TODO
}
void map_game_map_npc_set_no_cake_dialogue(const char* dialogue) {
// TODO
assert(game_map_npc_in_progress && "NPC has to be in progress");
game_map_npc_in_progress->sprite_id = id;
}
void map_game_map_npc_set_palette_id(sys_i32 id) {
// TODO
assert(game_map_npc_in_progress && "NPC has to be in progress");
game_map_npc_in_progress->palette_id = id;
}
void map_game_map_npc_set_inflict_id(sys_i32 id) {
assert(game_map_npc_in_progress && "NPC has to be in progress");
game_map_npc_in_progress->inflict_id = id;
}
void map_game_map_npc_set_face_left(bool face_left) {
game_map_npc_in_progress->face_left = face_left;
}
void map_game_map_npc_set_no_cake_dialogue(const char* dialogue) {
assert(game_map_npc_in_progress && "NPC has to be in progress");
game_map_npc_in_progress->no_cake_dialogue = dialogue;
}
void map_game_map_npc_add_dialogue(const char* dialogue) {
// TODO
assert(game_map_npc_in_progress && "NPC has to be in progress");
assert(game_map_npc_in_progress->n_dialogues < GAME_NPC_MAX_N_DIALOGUES &&
"NPC can't have too many dialogues");
sys_i32 ix = game_map_npc_in_progress->n_dialogues++;
game_map_npc_in_progress->dialogues[ix] = dialogue;
}

View File

@ -4,6 +4,7 @@ import shared
TEMPLATE = """
// generated code! be nice
#include <stdbool.h>
#include "sys/sys.h"
sys_maptile map_{{map_name}}_data[{{width * height}}] = { {{ tiles|join(",") }} };
@ -128,7 +129,9 @@ def load_mapdata(fname_ldtk):
def format_field_value(ty, val):
if ty == "Int":
if ty == "Bool":
return "true" if val else "false", "scalar", "bool"
elif ty == "Int":
return str(val), "scalar", "sys_i32"
elif ty == "String":
if val is None:
@ -138,6 +141,8 @@ def format_field_value(ty, val):
return [format_field_value("Int", i)[0] for i in val], "array", "sys_i32"
elif ty == "Array<String>":
return [format_field_value("String", i)[0] for i in val], "array", "const char*"
else:
assert False, f"unknown type: {ty}"
def annot_xy(lst, w, h):