Added an inventory in a menu bar. Not all rooms are updated - only the lobby.
parent
f5e5886827
commit
30c06a6efb
2
Makefile
2
Makefile
|
@ -1,6 +1,6 @@
|
|||
PROJECT_ROOT = $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||
|
||||
OBJS = pinetab2_framework.o game.o textbox.o
|
||||
OBJS = pinetab2_framework.o game.o textbox.o inventory.o
|
||||
SPRITES = $(patsubst $(PROJECT_ROOT)sprites/%.xcf,%,$(wildcard $(PROJECT_ROOT)sprites/*.xcf))
|
||||
NAVMESHES = $(patsubst $(PROJECT_ROOT)navmesh/%.tmx,%,$(wildcard $(PROJECT_ROOT)navmesh/*.tmx))
|
||||
|
||||
|
|
18
engine.h
18
engine.h
|
@ -1,4 +1,5 @@
|
|||
#define MAX_OBJECTS_PER_SCENE 30
|
||||
#define INVENTORY_SIZE 12
|
||||
#define MAX_OBJECTS_PER_SCENE (30+INVENTORY_SIZE)
|
||||
#define MAX_SCRIPTS_PER_SCENE 30
|
||||
#define MAX_STACKED_SCENES 5
|
||||
|
||||
|
@ -38,6 +39,9 @@ extern struct scene {
|
|||
scene_animtimer_fn animtimer_fn; // default null
|
||||
scene_handle_tap_fn handle_tap_fn; // default standard_handle_tap
|
||||
struct navmesh *navmesh; // defaults to non-null pointer to empty navmesh
|
||||
|
||||
bool use_standard_inventory; // defaults to true
|
||||
|
||||
} scenes[MAX_STACKED_SCENES];
|
||||
extern int scene_depth; // number of stacked scenes
|
||||
#define top_scene scenes[scene_depth-1]
|
||||
|
@ -55,7 +59,7 @@ struct script_player_walk {
|
|||
#define SCRIPT_WAKEUP_OTHER_SCRIPT 2
|
||||
#define SCRIPT_WAKEUP_OTHER_SCRIPT_INTERRUPTED 3 // Delivered to script that registers for SCRIPT_WAKEUP_OTHER_SCRIPT if that script is interrupted instead of completing.
|
||||
|
||||
typedef void (*scene_setup_fn)(int scene, int fromscene);
|
||||
typedef void (*scene_setup_fn)(scene *s, int scene, int fromscene);
|
||||
|
||||
// engine
|
||||
// Scene changes - even push - may discard remaining events for the scene.
|
||||
|
@ -64,8 +68,8 @@ void push_scene(int scene, scene_setup_fn setup_fn);
|
|||
void replace_scene(int scene);
|
||||
void pop_scene();
|
||||
void scene_add_clickrect(int id, int x, int y, int width, int height);
|
||||
struct object *scene_add_object(int id, int x, int y, int width, int height, const char *pixels);
|
||||
void scene_load_predef(const struct level_predef_data *predef);
|
||||
struct object *scene_add_object(scene *s, int id, int x, int y, int width, int height, const char *pixels);
|
||||
void scene_load_predef(struct scene *sc, const struct level_predef_data *predef);
|
||||
struct object *find_object_by_id(int id);
|
||||
struct script *scene_add_script(int id, bool interrupt_existing);
|
||||
struct script *scene_get_script(int id);
|
||||
|
@ -74,6 +78,10 @@ void start_player_walk_to_point(int x, int y); // x and y are not corrected to l
|
|||
|
||||
void push_scene_textbox(const char *text);
|
||||
|
||||
// standard inventory
|
||||
void create_standard_inventory(scene *s);
|
||||
void standard_inventory_onclick(struct object *obj);
|
||||
|
||||
// used during rendering
|
||||
// pixel is 0xRRGGBB
|
||||
extern uint32_t *curfb;
|
||||
|
@ -90,5 +98,5 @@ void blit(int x, int y, int width, int height, uint32_t *pixels);
|
|||
#define SCENE_TEXTBOX 5
|
||||
|
||||
// game.cpp
|
||||
void scene_setup(int scene, int fromscene);
|
||||
void scene_setup(scene *s, int scene, int fromscene);
|
||||
void onclick(int curscene, struct object *obj);
|
||||
|
|
65
game.cpp
65
game.cpp
|
@ -2,8 +2,11 @@
|
|||
#include <stdio.h>
|
||||
#include "engine.h"
|
||||
#include "objids.h"
|
||||
#include "inventory.h"
|
||||
|
||||
#define BGWIDTH 1280
|
||||
|
||||
|
||||
#define BGWIDTH 1066
|
||||
#define BGHEIGHT 800
|
||||
|
||||
extern const char _binary_sprite_lobby_raw_start[];
|
||||
|
@ -18,57 +21,59 @@ extern struct navmesh navmesh_managers_office;
|
|||
extern struct navmesh navmesh_basement;
|
||||
extern struct level_predef_data predef_basement, predef_lobby, predef_managers_office;
|
||||
|
||||
static void create_player(int x, int y) {
|
||||
static void create_player(scene *me, int x, int y) {
|
||||
const int WIDTH=51, HEIGHT=111;
|
||||
scene_add_object(OBJID_PLAYER, x-WIDTH/2, y-HEIGHT, WIDTH, HEIGHT, _binary_sprite_stickman_raw_start);
|
||||
scene_add_object(me, OBJID_PLAYER, x-WIDTH/2, y-HEIGHT, WIDTH, HEIGHT, _binary_sprite_stickman_raw_start);
|
||||
}
|
||||
|
||||
void scene_setup(int scene, int fromscene) {
|
||||
void scene_setup(scene *me, int scene, int fromscene) {
|
||||
switch(scene) {
|
||||
case SCENE_LOBBY:
|
||||
scene_add_object(OBJID_BACKGROUND, 0, 0, BGWIDTH, BGHEIGHT, _binary_sprite_lobby_raw_start);
|
||||
scene_load_predef(&predef_lobby);
|
||||
scene_add_object(me, OBJID_BACKGROUND, 0, 0, BGWIDTH, BGHEIGHT, _binary_sprite_lobby_raw_start);
|
||||
scene_load_predef(me, &predef_lobby);
|
||||
switch(fromscene) {
|
||||
case SCENE_MANAGERS_OFFICE:
|
||||
create_player(256, 445);
|
||||
create_player(me, 256, 445);
|
||||
break;
|
||||
default:
|
||||
create_player(424, 675);
|
||||
create_player(me, 424, 675);
|
||||
break;
|
||||
}
|
||||
top_scene.navmesh = &navmesh_lobby;
|
||||
push_scene_textbox("Welcome\n\nto\n\ntestgame");
|
||||
if(fromscene == -1) {
|
||||
push_scene_textbox("Welcome\n\nto\n\ntestgame");
|
||||
}
|
||||
break;
|
||||
case SCENE_MANAGERS_OFFICE:
|
||||
scene_add_object(OBJID_BACKGROUND, 0, 0, BGWIDTH, BGHEIGHT, _binary_sprite_managers_office_raw_start);
|
||||
scene_load_predef(&predef_managers_office);
|
||||
scene_add_object(me, OBJID_BACKGROUND, 0, 0, BGWIDTH, BGHEIGHT, _binary_sprite_managers_office_raw_start);
|
||||
scene_load_predef(me, &predef_managers_office);
|
||||
switch(fromscene) {
|
||||
case SCENE_LOBBY:
|
||||
create_player(804, 708);
|
||||
create_player(me, 804, 708);
|
||||
break;
|
||||
case SCENE_BASEMENT:
|
||||
create_player(408, 559);
|
||||
create_player(me, 408, 559);
|
||||
break;
|
||||
default:
|
||||
create_player(424, 675);
|
||||
create_player(me, 424, 675);
|
||||
break;
|
||||
}
|
||||
top_scene.navmesh = &navmesh_managers_office;
|
||||
break;
|
||||
case SCENE_MANAGERS_OFFICE_SAFE:
|
||||
scene_add_object(OBJID_BACKGROUND, 248, 0, 787, BGHEIGHT, _binary_sprite_managers_office_safe_raw_start);
|
||||
scene_add_object(OBJID_CLOSE_MODAL, 0, 0, 248, 800, nullptr);
|
||||
scene_add_object(OBJID_CLOSE_MODAL, 1035, 0, 1280-1035, 800, nullptr);
|
||||
scene_add_object(me, OBJID_BACKGROUND, 248, 0, 787, BGHEIGHT, _binary_sprite_managers_office_safe_raw_start);
|
||||
scene_add_object(me, OBJID_CLOSE_MODAL, 0, 0, 248, 800, nullptr);
|
||||
scene_add_object(me, OBJID_CLOSE_MODAL, 1035, 0, 1280-1035, 800, nullptr);
|
||||
break;
|
||||
case SCENE_BASEMENT:
|
||||
scene_add_object(OBJID_BACKGROUND, 0, 0, BGWIDTH, BGHEIGHT, _binary_sprite_basement_raw_start);
|
||||
scene_load_predef(&predef_basement);
|
||||
scene_add_object(me, OBJID_BACKGROUND, 0, 0, BGWIDTH, BGHEIGHT, _binary_sprite_basement_raw_start);
|
||||
scene_load_predef(me, &predef_basement);
|
||||
switch(fromscene) {
|
||||
case SCENE_MANAGERS_OFFICE:
|
||||
create_player(435, 404);
|
||||
create_player(me, 435, 404);
|
||||
break;
|
||||
default:
|
||||
create_player(424, 675);
|
||||
create_player(me, 424, 675);
|
||||
break;
|
||||
}
|
||||
top_scene.navmesh = &navmesh_basement;
|
||||
|
@ -102,7 +107,17 @@ static void start_player_walk_to_point_then_transition_scene(int x, int y, int s
|
|||
static void do_popcorn_on_walk_finish(struct script *scr, int wakeupMode, int arg1, int arg2, int arg3, int arg4) {
|
||||
scr->id = 0;
|
||||
if(wakeupMode == SCRIPT_WAKEUP_OTHER_SCRIPT) {
|
||||
push_scene_textbox("You got popcorn.");
|
||||
if(count_item_in_inventory(INVITEM_POPCORN) >= 3) {
|
||||
push_scene_textbox(
|
||||
"You already have\n"
|
||||
"enough popcorn."
|
||||
);
|
||||
} else {
|
||||
if(add_to_inventory(INVITEM_POPCORN) < 0)
|
||||
push_scene_textbox("Inventory is full.");
|
||||
else
|
||||
push_scene_textbox("You got popcorn.");
|
||||
}
|
||||
}
|
||||
else
|
||||
assert(wakeupMode == SCRIPT_WAKEUP_OTHER_SCRIPT_INTERRUPTED);
|
||||
|
@ -122,12 +137,16 @@ void onclick(int curscene, struct object *obj) {
|
|||
pop_scene();
|
||||
return;
|
||||
}
|
||||
if(obj->id >= OBJID_INVENTORY_SLOTS && obj->id < OBJID_INVENTORY_SLOTS + INVENTORY_SIZE) {
|
||||
standard_inventory_onclick(obj);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(curscene) {
|
||||
case SCENE_LOBBY:
|
||||
switch(obj->id) {
|
||||
case OBJID_DOOR_TO_MANAGERS_OFFICE_FROM_LOBBY:
|
||||
start_player_walk_to_point_then_transition_scene(312, 441, SCENE_MANAGERS_OFFICE);
|
||||
start_player_walk_to_point_then_transition_scene(256, 441, SCENE_MANAGERS_OFFICE);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
#include "engine.h"
|
||||
#include "objids.h"
|
||||
#include "inventory.h"
|
||||
#include <assert.h>
|
||||
|
||||
extern const char _binary_sprite_menubar_raw_start[];
|
||||
extern const char _binary_sprite_item_popcorn_raw_start[];
|
||||
|
||||
static const char *const inventory_sprites[] = {
|
||||
_binary_sprite_item_popcorn_raw_start
|
||||
};
|
||||
|
||||
int inventory[INVENTORY_SIZE] = {
|
||||
// no default items
|
||||
};
|
||||
|
||||
static void create_inventory_object(scene *s, int index) {
|
||||
int type = inventory[index];
|
||||
if(type == INVITEM_BLANK) return;
|
||||
|
||||
int x = 1066 + 14 + (index & 1) * 100;
|
||||
int y = 200 + (index >> 1) * 100;
|
||||
struct object *obj = scene_add_object(s, OBJID_INVENTORY_SLOTS + index, x, y, 87, 87, inventory_sprites[type-1]);
|
||||
}
|
||||
|
||||
void create_standard_inventory(struct scene *s) {
|
||||
scene_add_object(s, OBJID_MENUBAR, 1066, 0, 234, 800, _binary_sprite_menubar_raw_start);
|
||||
for(int i = 0; i < INVENTORY_SIZE; i++) {
|
||||
create_inventory_object(s, i);
|
||||
}
|
||||
}
|
||||
|
||||
void standard_inventory_onclick(struct object *obj) {
|
||||
int slot = obj->id - OBJID_INVENTORY_SLOTS;
|
||||
assert(inventory[slot] != INVITEM_BLANK);
|
||||
|
||||
// does nothing for now
|
||||
}
|
||||
|
||||
int count_item_in_inventory(int item) {
|
||||
int count = 0;
|
||||
for(int i = 0; i < INVENTORY_SIZE; i++)
|
||||
if(inventory[i] == item)
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
int add_to_inventory(int item) {
|
||||
// returns slot number or -1 if no space available
|
||||
for(int i = 0; i < INVENTORY_SIZE; i++) {
|
||||
if(!inventory[i]) {
|
||||
inventory[i] = item;
|
||||
// TODO: inventory should refresh when a scene is activated when a different scene is activated before.
|
||||
// If not a fully custom rendering. Otherwise, popping a scene may revert inventory objects on screen to an earlier state.
|
||||
create_inventory_object(&top_scene, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
enum invobject {
|
||||
INVITEM_BLANK = 0, // must always be 0
|
||||
|
||||
INVITEM_POPCORN,
|
||||
};
|
||||
|
||||
extern int inventory[INVENTORY_SIZE];
|
||||
|
||||
int count_item_in_inventory(int item);
|
||||
int add_to_inventory(int item); // returns slot number or -1 if no space available
|
|
@ -4,29 +4,29 @@
|
|||
<image source="../build/default/lobby.png" width="1280" height="800"/>
|
||||
</imagelayer>
|
||||
<objectgroup id="3" name="clickable">
|
||||
<object id="1" name="OBJID_DOOR_TO_MANAGERS_OFFICE_FROM_LOBBY" x="273" y="313" width="76" height="128"/>
|
||||
<object id="1" name="OBJID_DOOR_TO_MANAGERS_OFFICE_FROM_LOBBY" x="227" y="312" width="64" height="128"/>
|
||||
</objectgroup>
|
||||
<objectgroup id="4" name="navmesh">
|
||||
<object id="10" x="213" y="441">
|
||||
<polygon points="0,0 135,85 191,-1"/>
|
||||
<object id="10" x="178" y="440">
|
||||
<polygon points="0,0 112,83 159,-1"/>
|
||||
</object>
|
||||
<object id="11" x="213" y="441">
|
||||
<polygon points="0,0 -211,301 134,176 135,85"/>
|
||||
<object id="11" x="178" y="441">
|
||||
<polygon points="0,-1 -178,303 110,173 112,82"/>
|
||||
</object>
|
||||
<object id="13" x="2" y="742">
|
||||
<polygon points="0,0 0,57 330,58 345,-125"/>
|
||||
<object id="13" x="2" y="733">
|
||||
<polygon points="-2,11 -2,67 275,67 286,-119"/>
|
||||
</object>
|
||||
<object id="14" x="2" y="799">
|
||||
<polygon points="330,1 959,1 933,-174 345,-182"/>
|
||||
<object id="14" x="2" y="740">
|
||||
<polygon points="275,60 802,60 776,-117 286,-126"/>
|
||||
</object>
|
||||
<object id="16" x="860" y="440">
|
||||
<polygon points="0,0 76,118 180,0"/>
|
||||
<object id="16" x="717" y="440">
|
||||
<polygon points="0,0 62,119 150,0"/>
|
||||
</object>
|
||||
<object id="17" x="937" y="558">
|
||||
<polygon points="-1,0 -2,67 245,95 103,-118"/>
|
||||
<object id="17" x="782" y="538">
|
||||
<polygon points="-3,21 -4,85 187,82 85,-98"/>
|
||||
</object>
|
||||
<object id="18" x="939" y="559">
|
||||
<polygon points="243,94 -4,66 22,241 341,241"/>
|
||||
<object id="18" x="783" y="539">
|
||||
<polygon points="186,81 -5,84 21,261 283,261"/>
|
||||
</object>
|
||||
</objectgroup>
|
||||
</map>
|
||||
|
|
3
objids.h
3
objids.h
|
@ -11,3 +11,6 @@
|
|||
#define OBJID_BASEMENT_LADDER 11
|
||||
#define OBJID_CLOSE_MODAL 12
|
||||
#define OBJID_POPCORN_BARREL 13
|
||||
#define OBJID_MENUBAR 14
|
||||
|
||||
#define OBJID_INVENTORY_SLOTS 0x10000000 // + slot number
|
||||
|
|
|
@ -174,13 +174,19 @@ void fillrect(int x1, int y1, int width, int height, uint32_t pixel) {
|
|||
}
|
||||
|
||||
static void scene_clear_and_setup(int scene, int fromscene, scene_setup_fn setup_fn) {
|
||||
memset(&top_scene, 0, sizeof(top_scene));
|
||||
top_scene.id = scene;
|
||||
top_scene.navmesh = &null_navmesh;
|
||||
top_scene.handle_tap_fn = standard_handle_tap;
|
||||
top_scene.render_fn = standard_scene_render;
|
||||
struct scene *me = &top_scene; // setup_fn might push additional scenes such as textboxes
|
||||
memset(me, 0, sizeof(*me));
|
||||
me->id = scene;
|
||||
me->navmesh = &null_navmesh;
|
||||
me->handle_tap_fn = standard_handle_tap;
|
||||
me->render_fn = standard_scene_render;
|
||||
me->use_standard_inventory = true;
|
||||
|
||||
setup_fn(scene, fromscene);
|
||||
setup_fn(me, scene, fromscene);
|
||||
|
||||
if(me->use_standard_inventory) {
|
||||
create_standard_inventory(me);
|
||||
}
|
||||
|
||||
need_rerender = true;
|
||||
}
|
||||
|
@ -202,10 +208,10 @@ void pop_scene() {
|
|||
need_rerender = true;
|
||||
}
|
||||
|
||||
struct object *scene_add_object(int id, int x, int y, int width, int height, const char *pixels) {
|
||||
struct object *scene_add_object(struct scene *sc, int id, int x, int y, int width, int height, const char *pixels) {
|
||||
if(id == 0) error(1, 0, "scene_add_object: id 0 is invalid");
|
||||
|
||||
struct object *objects = top_scene.objects;
|
||||
struct object *objects = sc->objects;
|
||||
for(int i = 0; i < MAX_OBJECTS_PER_SCENE; i++) {
|
||||
if(objects[i].id == 0) {
|
||||
objects[i].id = id;
|
||||
|
@ -220,9 +226,9 @@ struct object *scene_add_object(int id, int x, int y, int width, int height, con
|
|||
error(1, 0, "too many game objects");
|
||||
}
|
||||
|
||||
void scene_load_predef(const struct level_predef_data *predef) {
|
||||
void scene_load_predef(struct scene *sc, const struct level_predef_data *predef) {
|
||||
for(const struct level_clickregion *cr = predef->clickregions; cr->num_edges; cr++) {
|
||||
struct object *obj = scene_add_object(cr->id, cr->x, cr->y, cr->width, cr->height, nullptr);
|
||||
struct object *obj = scene_add_object(sc, cr->id, cr->x, cr->y, cr->width, cr->height, nullptr);
|
||||
obj->clickregion = cr;
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -52,10 +52,10 @@ static void textbox_handle_tap(struct scene *s, int x, int y) {
|
|||
}
|
||||
}
|
||||
|
||||
static void textbox_setup_fn(int scene, int fromscene) {
|
||||
top_scene.render_fn = textbox_render_fn;
|
||||
top_scene.animtimer_fn = textbox_animtimer_fn;
|
||||
top_scene.handle_tap_fn = textbox_handle_tap;
|
||||
static void textbox_setup_fn(scene *s, int scene, int fromscene) {
|
||||
s->render_fn = textbox_render_fn;
|
||||
s->animtimer_fn = textbox_animtimer_fn;
|
||||
s->handle_tap_fn = textbox_handle_tap;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue