Compare commits

...

10 Commits

37 changed files with 982 additions and 119 deletions

View File

@ -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 decompress_sprite.o
SPRITES = $(patsubst $(PROJECT_ROOT)sprites/%.xcf,%,$(wildcard $(PROJECT_ROOT)sprites/*.xcf))
NAVMESHES = $(patsubst $(PROJECT_ROOT)navmesh/%.tmx,%,$(wildcard $(PROJECT_ROOT)navmesh/*.tmx))
@ -44,15 +44,8 @@ pinetab2_framework: $(OBJS)
clean:
rm -fr pinetab2_framework $(OBJS) $(EXTRA_CLEAN)
sprite_%.o: $(PROJECT_ROOT)sprites/%.xcf
gimp -in -b '(let ((image (car (gimp-xcf-load 0 "$<" "$(notdir $<)")))) ;\
;(gimp-image-scale image 1280 800) ;\
(gimp-image-rotate image ROTATE-90) ;\
(let ((layer (car (gimp-image-merge-visible-layers image CLIP-TO-IMAGE)))) ;\
(plug-in-colors-channel-mixer RUN-NONINTERACTIVE image layer 0 0 0 1 0 1 0 1 0 0) ; swap red and blue channels \
(file-raw-save 1 image layer "$(patsubst %.o,%.raw,$@)" "$(patsubst %.o,%.raw,$@)") ;\
) ;\
)' -b '(gimp-quit 0)'
sprite_%.o: %.png $(PROJECT_ROOT)compress_sprite.py
python3 "$(PROJECT_ROOT)compress_sprite.py" "$<" $(patsubst %.o,%.raw,$@)
$(OBJCOPY) -I binary --rename-section .data=.rodata,alloc,load,readonly,data,contents $(patsubst %.o,%.raw,$@) $@
rm $(patsubst %.o,%.raw,$@)
@# symbols are _binary_sprite_%_raw_start / _end / _size
@ -62,6 +55,7 @@ navmesh_%.c: $(PROJECT_ROOT)navmesh/%.tmx $(PROJECT_ROOT)compile_navmesh.py
@# symbols are navmesh_% and predef_%
navmesh_%.o: $(PROJECT_ROOT)compiled_structures.h $(PROJECT_ROOT)objids.h
pinetab2_framework.o: $(PROJECT_ROOT)engine.h
%.png: $(PROJECT_ROOT)sprites/%.xcf
gimp -in -b '(let ((image (car (gimp-xcf-load 0 "$<" "$(notdir $<)")))) ;\

View File

@ -134,6 +134,16 @@ for dest in range(len(polys)):
out.write("};\n")
out.write(f"extern const struct navmesh navmesh_{basename} = {{{len(polys)}, {basename}_triangles, {basename}_pathfind}};\n")
background = tree.find("imagelayer/image")
bgidentifier, bgwidth, bgheight = "(const unsigned char*)0", 0, 0
if background is not None:
bgidentifier = background.attrib["source"].split("/")[-1]
if "." in bgidentifier: bgidentifier = bgidentifier[:bgidentifier.rindex(".")] # remove .png
bgidentifier = "_binary_sprite_"+bgidentifier+"_raw_start"
out.write(f"extern const unsigned char {bgidentifier}[];\n")
bgwidth = int(background.attrib["width"])
bgheight = int(background.attrib["height"])
out.write("extern const struct level_predef_data predef_"+basename+" = {\n")
out.write("\t(const struct level_clickregion[]){\n") # clickregions start
for object in tree.findall("objectgroup[@name='clickable']/object"):
@ -151,4 +161,13 @@ for object in tree.findall("objectgroup[@name='clickable']/object"):
out.write("\t\t},\n");
out.write("\t\t{0}\n")
out.write("\t},\n") # clickregions end
out.write("\t(const struct level_predef_point[]){\n") # points start
for object in tree.findall("objectgroup[@name='points']/object"):
x,y=int(object.attrib["x"]),int(object.attrib["y"])
# Note: name can contain commas to populate multiple ID fields, or arithmetic expressions
out.write(f"\t\t{{{x},{y},{object.attrib['name']}}},\n")
out.write("\t\t{0}\n")
out.write("\t},\n") # points end
out.write("\t&navmesh_"+basename+",\n")
out.write(f"\t{bgidentifier}, {bgwidth}, {bgheight},\n")
out.write("};\n")

View File

@ -34,8 +34,16 @@ struct level_clickregion {
int num_edges;
const struct level_clickregion_edge *edges;
};
struct level_predef_point {
int x, y;
int id;
};
struct level_predef_data {
const struct level_clickregion *clickregions; // terminated by null entry
const struct level_predef_point *points; // terminated by x=0 y=0
const struct navmesh *navmesh;
const unsigned char *background;
int bgwidth, bgheight;
};

59
compress_sprite.py Normal file
View File

@ -0,0 +1,59 @@
#!/usr/bin/python3
import sys
import struct
import PIL.Image
_, inpath, outpath = sys.argv
image = PIL.Image.open(inpath)
assert image.mode == "RGBA", "image mode is "+image.mode
# We measure width and height prior to the rotation
width, height = image.width, image.height
image = image.transpose(PIL.Image.Transpose.ROTATE_270)
with open(outpath, "wb") as out:
out.write(struct.pack("=HH", width, height))
for channel in "BGRA":
pixelbytes = image.getchannel(channel).tobytes()
def rlegroups():
curpixel=None
count=0
litrun = b""
for pixel in pixelbytes:
if curpixel is None:
curpixel = pixel
count = 1
elif curpixel != pixel:
assert count > 0
if count <= 2:
if len(litrun)+count > 127:
assert len(litrun) > 0
yield litrun
litrun = b""
litrun += bytes([curpixel]) * count
else:
if litrun != b"":
assert len(litrun) > 0
yield litrun
litrun = b""
yield (curpixel, count)
curpixel = pixel
count = 1
else:
count += 1
if litrun != b"":
assert len(litrun) > 0
yield litrun
if count > 0:
yield (curpixel, count)
for group in rlegroups():
if type(group) == bytes:
out.write(struct.pack("=B", len(group)+128) + group)
else:
pixel, count = group
assert count > 0
if count >= 128:
out.write(struct.pack("=BIB", 0, count, pixel))
else:
out.write(struct.pack("=BB", count, pixel))

62
decompress_sprite.cpp Normal file
View File

@ -0,0 +1,62 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include "engine.h"
#include <inttypes.h>
// TODO: even better compression using zlib or something - or vector graphics
#define MAX_SPRITES 5000
static struct sprite sprites[MAX_SPRITES];
static int numsprites;
struct sprite *get_decompressed_sprite(const unsigned char *spritedata) {
for(int i = 0; i < numsprites; i++) {
if(sprites[i].original_data_source == spritedata)
return &sprites[i];
}
struct sprite *s = &sprites[numsprites++];
s->width = *(uint16_t*)(spritedata + 0);
s->height = *(uint16_t*)(spritedata + 2);
s->original_data_source = spritedata;
spritedata += 4;
s->pixels = (uint32_t*)malloc(s->width*s->height*4);
if(!s->pixels) error(1, 0, "get_decompressed_sprite: memory allocation failed");
for(int channel = 0; channel < 4; channel++) {
unsigned char *pixels = (unsigned char*)s->pixels;
pixels += channel;
unsigned int pixelsleft = s->width * s->height;
while(pixelsleft > 0) {
unsigned char control = *spritedata++;
if(control & 0x80) {
control &= 0x7f;
if(control > pixelsleft) error(1, 0, "corrupted compressed sprite A %u > %u", (unsigned int)control, (unsigned int)pixelsleft);
for(int i = 0; i < control; i++) {
*pixels = *spritedata++;
pixels += 4;
}
pixelsleft -= control;
} else {
uint32_t count;
if(control == 0) {
count = *(uint32_t*)spritedata;
spritedata += 4;
} else {
count = control;
}
unsigned char value = *spritedata++;
if(count > pixelsleft) error(1, 0, "corrupted compressed sprite B %u > %u", (unsigned int)count, (unsigned int)pixelsleft);
for(uint32_t i = 0; i < count; i++) {
*pixels = value;
pixels += 4;
}
pixelsleft -= count;
}
}
}
return s;
}

View File

@ -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
@ -37,7 +38,12 @@ extern struct scene {
scene_render_fn render_fn; // default standard_scene_render
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
const struct navmesh *navmesh; // defaults to non-null pointer to empty navmesh
const struct level_predef_data *predef;
bool use_standard_inventory; // defaults to true
bool dim_background; // defaults to false, because most scenes overwrite the whole screen
} scenes[MAX_STACKED_SCENES];
extern int scene_depth; // number of stacked scenes
#define top_scene scenes[scene_depth-1]
@ -55,7 +61,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 +70,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 +80,17 @@ 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);
struct sprite {
int width, height;
uint32_t *pixels;
const unsigned char *original_data_source;
};
struct sprite *get_decompressed_sprite(const unsigned char *spritedata);
// used during rendering
// pixel is 0xRRGGBB
extern uint32_t *curfb;
@ -81,14 +98,10 @@ extern bool need_rerender;
void fillrect(int x1, int y1, int width, int height, uint32_t pixel);
void blit(int x, int y, int width, int height, uint32_t *pixels);
// game-specific constants
#define SCENE_LOBBY 1
#define SCENE_MANAGERS_OFFICE 2
#define SCENE_MANAGERS_OFFICE_SAFE 3
#define SCENE_BASEMENT 4
#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);
extern struct savefile {
bool got_pager_from_basement;
} savefile;

283
game.cpp
View File

@ -2,76 +2,108 @@
#include <stdio.h>
#include "engine.h"
#include "objids.h"
#include "inventory.h"
#include "compiled_structures.h"
#define BGWIDTH 1280
#define BGWIDTH 1066
#define BGHEIGHT 800
extern const char _binary_sprite_lobby_raw_start[];
extern const char _binary_sprite_managers_office_raw_start[];
extern const char _binary_sprite_managers_office_safe_raw_start[];
extern const char _binary_sprite_basement_raw_start[];
extern const char _binary_sprite_item_pager_raw_start[];
extern const char _binary_sprite_stickman_raw_start[];
extern struct navmesh navmesh_lobby;
extern struct navmesh navmesh_managers_office;
extern struct navmesh navmesh_basement;
extern struct level_predef_data predef_basement, predef_lobby, predef_managers_office;
extern const struct level_predef_data predef_basement, predef_lobby, predef_managers_office, predef_cloakroom, predef_hallway1, predef_hallway2, predef_hallway3,
predef_stairway1, predef_hallwayb1, predef_hallwayb2, predef_hallwayb3;
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) {
static const struct level_predef_point *find_level_predef_point(const struct level_predef_data *predef, int id) {
for(const struct level_predef_point *pt = predef->points; pt->x || pt->y; pt++) {
if(pt->id == id)
return pt;
}
return nullptr;
}
static void create_player_startpt(scene *me, int fromscene) {
int x, y;
assert(me->predef);
const struct level_predef_point *pt = (fromscene < 0 ? nullptr : find_level_predef_point(me->predef, OBJID_PLAYER_START+fromscene));
if(!pt)
pt = find_level_predef_point(me->predef, OBJID_PLAYER_START_DEFAULT);
if(pt) {
x = pt->x;
y = pt->y;
} else {
x = BGWIDTH/2;
y = BGHEIGHT/2;
}
create_player(me, x, y);
}
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);
switch(fromscene) {
case SCENE_MANAGERS_OFFICE:
create_player(256, 445);
break;
default:
create_player(424, 675);
break;
scene_load_predef(me, &predef_lobby);
create_player_startpt(me, fromscene);
if(fromscene == -1) {
push_scene_textbox("Welcome\n\nto\n\ntestgame");
}
top_scene.navmesh = &navmesh_lobby;
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);
switch(fromscene) {
case SCENE_LOBBY:
create_player(804, 708);
break;
case SCENE_BASEMENT:
create_player(408, 559);
break;
default:
create_player(424, 675);
break;
}
top_scene.navmesh = &navmesh_managers_office;
scene_load_predef(me, &predef_managers_office);
create_player_startpt(me, fromscene);
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);
me->dim_background = true;
me->use_standard_inventory = false;
break;
case SCENE_BASEMENT:
scene_add_object(OBJID_BACKGROUND, 0, 0, BGWIDTH, BGHEIGHT, _binary_sprite_basement_raw_start);
scene_load_predef(&predef_basement);
switch(fromscene) {
case SCENE_MANAGERS_OFFICE:
create_player(435, 404);
break;
default:
create_player(424, 675);
break;
scene_load_predef(me, &predef_basement);
if(!savefile.got_pager_from_basement) {
scene_add_object(me, OBJID_PAGER, 556, 520, 87, 87, _binary_sprite_item_pager_raw_start);
}
top_scene.navmesh = &navmesh_basement;
create_player_startpt(me, fromscene);
break;
case SCENE_CLOAKROOM:
scene_load_predef(me, &predef_cloakroom);
create_player_startpt(me, fromscene);
break;
case SCENE_HALLWAY1:
scene_load_predef(me, &predef_hallway1);
create_player_startpt(me, fromscene);
break;
case SCENE_HALLWAY2:
scene_load_predef(me, &predef_hallway2);
create_player_startpt(me, fromscene);
break;
case SCENE_HALLWAY3:
scene_load_predef(me, &predef_hallway3);
create_player_startpt(me, fromscene);
break;
case SCENE_STAIRWAY1:
scene_load_predef(me, &predef_stairway1);
create_player_startpt(me, fromscene);
break;
case SCENE_HALLWAY_B1:
scene_load_predef(me, &predef_hallwayb1);
create_player_startpt(me, fromscene);
break;
case SCENE_HALLWAY_B2:
scene_load_predef(me, &predef_hallwayb2);
create_player_startpt(me, fromscene);
break;
case SCENE_HALLWAY_B3:
scene_load_predef(me, &predef_hallwayb3);
create_player_startpt(me, fromscene);
break;
}
}
@ -102,19 +134,72 @@ 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);
}
static void start_player_walk_to_point_then_do_popcorn(int x, int y) {
static void get_pager_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) {
struct object *obj = find_object_by_id(OBJID_PAGER);
if(obj) {
if(add_to_inventory(INVITEM_PAGER) < 0) {
push_scene_textbox("Inventory is full.");
} else {
obj->id = 0;
savefile.got_pager_from_basement = true;
push_scene_textbox(
"You found your pager.\n"
"Now you can get out of here."
);
}
}
}
else
assert(wakeupMode == SCRIPT_WAKEUP_OTHER_SCRIPT_INTERRUPTED);
}
static void start_player_walk_to_point_then(int x, int y, script_wake_fn wake_fn) {
start_player_walk_to_point(x, y);
struct script *scr = scene_add_script(OBJID_PLAYER_WALK_TO_DOOR_SCRIPT, true);
scr->wakeupMode = SCRIPT_WAKEUP_OTHER_SCRIPT;
scr->wakeupArg1 = OBJID_PLAYER_WALK_SCRIPT;
scr->wakeupFn = do_popcorn_on_walk_finish;
scr->wakeupFn = wake_fn;
}
static void do_leave_lobby_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) {
if(count_item_in_inventory(INVITEM_PAGER) == 0) {
push_scene_textbox(
"You can't leave without\n"
"finding your pager."
);
} else {
push_scene_textbox(
"You got killed in a mugging\n"
"and we rewound time for you,\n"
"as required by the plot to\n"
"keep you inside the theatre."
);
}
}
else
assert(wakeupMode == SCRIPT_WAKEUP_OTHER_SCRIPT_INTERRUPTED);
}
void onclick(int curscene, struct object *obj) {
@ -122,12 +207,22 @@ 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;
case OBJID_LEAVE_ROOM:
start_player_walk_to_point_then(obj->x + obj->width/2, obj->y + obj->height, do_leave_lobby_on_walk_finish);
return;
case OBJID_LOBBY_TO_CLOAKROOM:
start_player_walk_to_point_then_transition_scene(777, 441, SCENE_CLOAKROOM);
return;
}
break;
@ -142,6 +237,9 @@ void onclick(int curscene, struct object *obj) {
case OBJID_MANAGERS_OFFICE_TRAPDOOR:
start_player_walk_to_point_then_transition_scene(408, 559, SCENE_BASEMENT);
return;
case OBJID_MANAGERS_OFFICE_TO_HALLWAY:
start_player_walk_to_point_then_transition_scene(665, 418, SCENE_HALLWAY1);
return;
}
break;
case SCENE_BASEMENT:
@ -150,7 +248,84 @@ void onclick(int curscene, struct object *obj) {
start_player_walk_to_point_then_transition_scene(438, 402, SCENE_MANAGERS_OFFICE);
return;
case OBJID_POPCORN_BARREL:
start_player_walk_to_point_then_do_popcorn(obj->x + obj->width/2, obj->y + obj->height);
start_player_walk_to_point_then(obj->x + obj->width/2, obj->y + obj->height, do_popcorn_on_walk_finish);
return;
case OBJID_PAGER:
start_player_walk_to_point_then(obj->x + obj->width/2, obj->y + obj->height, get_pager_on_walk_finish);
return;
}
break;
case SCENE_CLOAKROOM:
switch(obj->id) {
case OBJID_LEAVE_ROOM:
start_player_walk_to_point_then_transition_scene(obj->x + obj->width/2, obj->y + obj->height, SCENE_LOBBY);
return;
}
break;
case SCENE_HALLWAY1:
switch(obj->id) {
case OBJID_LEAVE_ROOM:
start_player_walk_to_point_then_transition_scene(obj->x + obj->width/2, obj->y + obj->height, SCENE_MANAGERS_OFFICE);
return;
case OBJID_NEXT_ROOM:
start_player_walk_to_point_then_transition_scene(obj->x + obj->width/2, obj->y + obj->height, SCENE_HALLWAY2);
return;
case OBJID_GO_LEFT:
start_player_walk_to_point_then_transition_scene(obj->x + obj->width/2, obj->y + obj->height, SCENE_STAIRWAY1);
return;
}
break;
case SCENE_HALLWAY2:
switch(obj->id) {
case OBJID_LEAVE_ROOM:
start_player_walk_to_point_then_transition_scene(obj->x + obj->width/2, obj->y + obj->height, SCENE_HALLWAY1);
return;
case OBJID_NEXT_ROOM:
start_player_walk_to_point_then_transition_scene(obj->x + obj->width/2, obj->y + obj->height, SCENE_HALLWAY3);
return;
}
break;
case SCENE_HALLWAY3:
switch(obj->id) {
case OBJID_LEAVE_ROOM:
start_player_walk_to_point_then_transition_scene(obj->x + obj->width/2, obj->y + obj->height, SCENE_HALLWAY2);
return;
}
break;
case SCENE_STAIRWAY1:
switch(obj->id) {
case OBJID_STAIRWAY1_TOP:
start_player_walk_to_point_then_transition_scene(obj->x + obj->width/2, obj->y + obj->height, SCENE_HALLWAY_B2);
return;
case OBJID_STAIRWAY1_BOTTOM:
start_player_walk_to_point_then_transition_scene(obj->x + obj->width/2, obj->y + obj->height, SCENE_HALLWAY1);
return;
}
break;
case SCENE_HALLWAY_B1:
switch(obj->id) {
case OBJID_GO_RIGHT:
start_player_walk_to_point_then_transition_scene(obj->x + obj->width/2, obj->y + obj->height, SCENE_HALLWAY_B2);
return;
}
break;
case SCENE_HALLWAY_B2:
switch(obj->id) {
case OBJID_GO_LEFT:
start_player_walk_to_point_then_transition_scene(obj->x + obj->width/2, obj->y + obj->height, SCENE_HALLWAY_B1);
return;
case OBJID_GO_RIGHT:
start_player_walk_to_point_then_transition_scene(obj->x + obj->width/2, obj->y + obj->height, SCENE_HALLWAY_B3);
return;
case OBJID_LEAVE_ROOM:
start_player_walk_to_point_then_transition_scene(obj->x + obj->width/2, obj->y + obj->height, SCENE_STAIRWAY1);
return;
}
break;
case SCENE_HALLWAY_B3:
switch(obj->id) {
case OBJID_GO_LEFT:
start_player_walk_to_point_then_transition_scene(obj->x + obj->width/2, obj->y + obj->height, SCENE_HALLWAY_B2);
return;
}
break;

61
inventory.cpp Normal file
View File

@ -0,0 +1,61 @@
#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[];
extern const char _binary_sprite_item_pager_raw_start[];
static const char *const inventory_sprites[] = {
_binary_sprite_item_popcorn_raw_start,
_binary_sprite_item_pager_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;
}

11
inventory.h Normal file
View File

@ -0,0 +1,11 @@
enum invobject {
INVITEM_BLANK = 0, // must always be 0
INVITEM_POPCORN,
INVITEM_PAGER,
};
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

View File

@ -31,6 +31,8 @@ struct scene scenes[MAX_STACKED_SCENES];
int scene_depth = 0;
bool need_rerender = false;
struct savefile savefile;
#define MAX_MT_SLOTS 16
@ -174,13 +176,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 +210,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;
@ -213,16 +221,21 @@ struct object *scene_add_object(int id, int x, int y, int width, int height, con
objects[i].y = y;
objects[i].width = width;
objects[i].height = height;
objects[i].pixels = pixels;
objects[i].pixels = pixels ? (const char*)get_decompressed_sprite((const unsigned char*)pixels)->pixels : nullptr;
return &objects[i];
}
}
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) {
sc->predef = predef;
sc->navmesh = predef->navmesh;
if(predef->background) {
scene_add_object(sc, OBJID_BACKGROUND, 0, 0, predef->bgwidth, predef->bgheight, (const char*)predef->background);
}
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;
}
}
@ -344,7 +357,7 @@ static double is_point_in_tri(int x, int y, const struct navmesh_tri *tri) {
static int find_navmesh_tri(int x, int y, int tolerance) {
int best_tri = -1;
double best_dist = tolerance;
struct navmesh *cur_navmesh = top_scene.navmesh;
const struct navmesh *cur_navmesh = top_scene.navmesh;
for(int i = 0; i < cur_navmesh->num_tris; i++) {
double dist = is_point_in_tri(x, y, &cur_navmesh->tris[i]);
if(dist == 0)
@ -384,7 +397,7 @@ void start_player_walk_to_point(int targetX, int targetY) {
void standard_handle_tap(struct scene *scene, int x, int y) {
uint32_t walkgen = player_walk_generation;
int sceneid = scene->id;
struct navmesh *cur_navmesh = top_scene.navmesh;
const struct navmesh *cur_navmesh = top_scene.navmesh;
struct object *objects = top_scene.objects;
for(int i = 0; i < MAX_OBJECTS_PER_SCENE; i++) {
if(!objects[i].id) continue;
@ -435,7 +448,7 @@ static void update_player_walk_script_on_frame(struct script *scr, int wakeupMod
deliver_script_wakeup(SCRIPT_WAKEUP_OTHER_SCRIPT, script_id, SCRIPT_WAKEUP_OTHER_SCRIPT_INTERRUPTED, 0, 0, 0, 0);
return;
}
struct navmesh *cur_navmesh = top_scene.navmesh;
const struct navmesh *cur_navmesh = top_scene.navmesh;
if(player_walk_script->currentNavmeshTri == -1) {
// something weird happened. just teleport player and end movement.
@ -501,6 +514,13 @@ bool deliver_script_wakeup(int wakeupMode, int wakeupArg1, int wakeupType, int a
}
void standard_scene_render(scene *s) {
if(s->dim_background) {
uint32_t *ptr = curfb;
for(int i = 0; i < 1280*800; i++, ptr++) {
*ptr = (*ptr >> 2) & 0x3f3f3f;
}
}
struct object *objects = s->objects;
for(int i = 0; i < MAX_OBJECTS_PER_SCENE; i++) {
if(objects[i].id != 0 && objects[i].pixels) {

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.2" orientation="orthogonal" renderorder="right-down" width="40" height="25" tilewidth="32" tileheight="32" infinite="0" nextlayerid="5" nextobjectid="8">
<map version="1.9" tiledversion="1.9.2" orientation="orthogonal" renderorder="right-down" width="40" height="25" tilewidth="32" tileheight="32" infinite="0" nextlayerid="6" nextobjectid="9">
<imagelayer id="2" name="Image Layer 1">
<image source="../build/default/basement.png" width="1280" height="800"/>
</imagelayer>
@ -18,4 +18,9 @@
<object id="6" name="OBJID_POPCORN_BARREL" x="733" y="293" width="83" height="148"/>
<object id="7" name="OBJID_POPCORN_BARREL" x="835" y="295" width="81" height="146"/>
</objectgroup>
<objectgroup id="5" name="points">
<object id="8" name="OBJID_PLAYER_START_DEFAULT" x="435" y="416">
<point/>
</object>
</objectgroup>
</map>

19
navmesh/cloakroom.tmx Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.2" orientation="orthogonal" renderorder="right-down" width="34" height="25" tilewidth="32" tileheight="32" infinite="0" nextlayerid="6" nextobjectid="4">
<imagelayer id="2" name="Image Layer 1">
<image source="../build/default/cloakroom.png" width="1066" height="800"/>
</imagelayer>
<objectgroup id="4" name="navmesh">
<object id="1" x="245" y="418">
<polygon points="0,0 -171,296 753,296 581,0"/>
</object>
</objectgroup>
<objectgroup id="3" name="clickable">
<object id="2" name="OBJID_LEAVE_ROOM" x="283" y="437" width="157" height="276"/>
</objectgroup>
<objectgroup id="5" name="points">
<object id="3" name="OBJID_PLAYER_START_DEFAULT" x="355" y="700">
<point/>
</object>
</objectgroup>
</map>

53
navmesh/hallway1.tmx Normal file
View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.2" orientation="orthogonal" renderorder="right-down" width="34" height="25" tilewidth="32" tileheight="32" infinite="0" nextlayerid="6" nextobjectid="17">
<imagelayer id="2" name="Image Layer 1">
<image source="../build/default/hallway1.png" width="1066" height="800"/>
</imagelayer>
<objectgroup id="4" name="navmesh">
<object id="2" x="346" y="714">
<polygon points="0,0 119,-173 45,-173"/>
</object>
<object id="3" x="600" y="517">
<polygon points="0,0 70,200 46,0"/>
</object>
<object id="4" x="346" y="714">
<polygon points="0,0 324,3 254,-197 119,-173"/>
</object>
<object id="5" x="465" y="541">
<polygon points="0,0 67,-164 107,-158 135,-24"/>
</object>
<object id="6" x="532" y="377">
<polygon points="0,0 0,-108 51,-176 74,-176 91,-41 40,6"/>
</object>
<object id="7" x="572" y="383">
<polygon points="0,0 57,5 51,-47"/>
</object>
<object id="8" x="532" y="269">
<polygon points="0,0 -73,2 -24,-174 39,-168 51,-68"/>
</object>
<object id="9" x="508" y="95">
<polygon points="0,0 5,-21 83,-21 84,-6 63,6"/>
</object>
<object id="10" x="571" y="101">
<polygon points="0,0 23,0 21,-12"/>
</object>
</objectgroup>
<objectgroup id="3" name="clickable">
<object id="1" name="OBJID_LEAVE_ROOM" x="466" y="439" width="155" height="277"/>
<object id="11" name="OBJID_NEXT_ROOM" x="511" y="1" width="80" height="74"/>
<object id="15" name="OBJID_GO_LEFT" x="468" y="142">
<polygon points="5,-18 0,-18 -18,33 -18,128 -5,128 5,87"/>
</object>
</objectgroup>
<objectgroup id="5" name="points">
<object id="12" name="OBJID_PLAYER_START_DEFAULT" x="541" y="713">
<point/>
</object>
<object id="13" name="OBJID_PLAYER_START+SCENE_HALLWAY2" x="552" y="80">
<point/>
</object>
<object id="16" name="OBJID_PLAYER_START+SCENE_STAIRWAY1" x="467" y="257">
<point/>
</object>
</objectgroup>
</map>

50
navmesh/hallway2.tmx Normal file
View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.2" orientation="orthogonal" renderorder="right-down" width="34" height="25" tilewidth="32" tileheight="32" infinite="0" nextlayerid="6" nextobjectid="15">
<imagelayer id="2" name="Image Layer 1">
<image source="../build/default/hallway2.png" width="1066" height="800"/>
</imagelayer>
<objectgroup id="4" name="navmesh">
<object id="3" x="513" y="76">
<polygon points="0,0 14,18 79,16 77,1"/>
</object>
<object id="4" x="513" y="76">
<polygon points="0,0 -6,20 14,18"/>
</object>
<object id="5" x="592" y="92">
<polygon points="0,0 3,23 -25,23 -65,2"/>
</object>
<object id="6" x="527" y="94">
<polygon points="0,0 40,21 10,269 -14,270"/>
</object>
<object id="7" x="513" y="364">
<polygon points="0,0 -46,82 -46,159 132,155 120,56 24,-1"/>
</object>
<object id="8" x="513" y="364">
<polygon points="0,0 -47,5 -46,82"/>
</object>
<object id="9" x="466" y="369">
<polygon points="0,0 -17,-43 -50,78 1,77"/>
</object>
<object id="10" x="467" y="523">
<polygon points="0,0 -14,86 190,87 178,-4"/>
</object>
<object id="11" x="453" y="609">
<polygon points="0,0 -106,105 218,105 204,1"/>
</object>
<object id="12" x="453" y="609">
<polygon points="0,0 -79,1 -106,105"/>
</object>
</objectgroup>
<objectgroup id="3" name="clickable">
<object id="1" name="OBJID_LEAVE_ROOM" x="485" y="654" width="43" height="54"/>
<object id="2" name="OBJID_NEXT_ROOM" x="510" y="1" width="85" height="74"/>
</objectgroup>
<objectgroup id="5" name="points">
<object id="13" name="OBJID_PLAYER_START_DEFAULT" x="509" y="638">
<point/>
</object>
<object id="14" name="OBJID_PLAYER_START+SCENE_HALLWAY3" x="552" y="83">
<point/>
</object>
</objectgroup>
</map>

49
navmesh/hallway3.tmx Normal file
View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.2" orientation="orthogonal" renderorder="right-down" width="34" height="25" tilewidth="32" tileheight="32" infinite="0" nextlayerid="7" nextobjectid="15">
<imagelayer id="2" name="Image Layer 1">
<image source="../build/default/hallway3.png" width="1066" height="800"/>
</imagelayer>
<objectgroup id="4" name="navmesh">
<object id="2" x="483" y="476">
<polygon points="0,0 -91,66 -137,240 189,239 167,69 79,-3"/>
</object>
<object id="3" x="483" y="476">
<polygon points="0,0 -74,-4 -91,66"/>
</object>
<object id="4" x="562" y="473">
<polygon points="0,0 88,72 78,-3"/>
</object>
<object id="5" x="562" y="473">
<polygon points="0,0 -79,3 -67,-144 -9,-146"/>
</object>
<object id="7" x="495" y="329">
<polygon points="0,0 -40,-35 -49,-2"/>
</object>
<object id="8" x="553" y="328">
<polygon points="0,-1 11,-13 68,-15 70,-3"/>
</object>
<object id="9" x="564" y="315">
<polygon points="0,0 -11,-110 -27,-124 -76,-140 -109,-21 -69,14 -11,12"/>
</object>
<object id="10" x="537" y="191">
<polygon points="0,0 33,-3 39,13 16,14"/>
</object>
<object id="11" x="570" y="188">
<polygon points="0,0 35,-1 38,15 6,16"/>
</object>
<object id="12" x="488" y="175">
<polygon points="0,0 49,16 82,13 73,-59 20,-78"/>
</object>
<object id="13" x="508" y="97">
<polygon points="0,0 6,-21 82,-21 88,17 53,19"/>
</object>
</objectgroup>
<objectgroup id="3" name="clickable">
<object id="1" name="OBJID_LEAVE_ROOM" x="486" y="654" width="41" height="57"/>
</objectgroup>
<objectgroup id="6" name="points">
<object id="14" name="OBJID_PLAYER_START_DEFAULT" x="503" y="635">
<point/>
</object>
</objectgroup>
</map>

26
navmesh/hallwayb1.tmx Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.2" orientation="orthogonal" renderorder="right-down" width="34" height="25" tilewidth="32" tileheight="32" infinite="0" nextlayerid="6" nextobjectid="9">
<imagelayer id="2" name="Image Layer 1">
<image source="../build/default/hallwayb1.png" width="1066" height="800"/>
</imagelayer>
<objectgroup id="3" name="clickable">
<object id="2" name="OBJID_HALLWAY2_DOOR2" x="325" y="230" width="116" height="204"/>
<object id="3" name="OBJID_HALLWAY2_DOOR1" x="71" y="213">
<polygon points="0,0 -46,33 -45,295 1,238"/>
</object>
<object id="6" name="OBJID_GO_RIGHT" x="932" y="181">
<polygon points="0,0 0,254 107,346 134,345 135,3"/>
</object>
<object id="7" name="OBJID_GO_RIGHT" x="906" y="461" width="49" height="40"/>
</objectgroup>
<objectgroup id="4" name="navmesh">
<object id="1" x="92" y="435">
<polygon points="0,0 -79,88 945,90 844,0"/>
</object>
</objectgroup>
<objectgroup id="5" name="points">
<object id="8" name="OBJID_PLAYER_START_DEFAULT" x="968" y="483">
<point/>
</object>
</objectgroup>
</map>

34
navmesh/hallwayb2.tmx Normal file
View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.2" orientation="orthogonal" renderorder="right-down" width="34" height="25" tilewidth="32" tileheight="32" infinite="0" nextlayerid="6" nextobjectid="13">
<imagelayer id="2" name="Image Layer 1">
<image source="../build/default/hallwayb2.png" width="1066" height="800"/>
</imagelayer>
<objectgroup id="3" name="clickable">
<object id="2" name="OBJID_HALLWAY2_DOOR3" x="326" y="232" width="116" height="205"/>
<object id="3" name="OBJID_LEAVE_ROOM" x="457" y="245" width="143" height="278"/>
<object id="4" name="OBJID_GO_RIGHT" x="934" y="179">
<polygon points="0,0 0,254 107,346 134,345 135,3"/>
</object>
<object id="6" name="OBJID_GO_LEFT" x="91" y="435">
<polygon points="0,0 -80,90 -92,91 -93,-253 1,-254"/>
</object>
<object id="7" name="OBJID_GO_LEFT" x="83" y="459" width="53" height="39"/>
<object id="8" name="OBJID_GO_RIGHT" x="903" y="462" width="52" height="41"/>
</objectgroup>
<objectgroup id="4" name="navmesh">
<object id="1" x="92" y="437">
<polygon points="0,0 -78,85 943,85 844,-2"/>
</object>
</objectgroup>
<objectgroup id="5" name="points">
<object id="10" name="OBJID_PLAYER_START+SCENE_HALLWAY_B1" x="60" y="485">
<point/>
</object>
<object id="11" name="OBJID_PLAYER_START+SCENE_HALLWAY_B3" x="971" y="476">
<point/>
</object>
<object id="12" name="OBJID_PLAYER_START_DEFAULT" x="530" y="517">
<point/>
</object>
</objectgroup>
</map>

26
navmesh/hallwayb3.tmx Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.2" orientation="orthogonal" renderorder="right-down" width="34" height="25" tilewidth="32" tileheight="32" infinite="0" nextlayerid="6" nextobjectid="9">
<imagelayer id="2" name="Image Layer 1">
<image source="../build/default/hallwayb3.png" width="1066" height="800"/>
</imagelayer>
<objectgroup id="3" name="clickable">
<object id="2" name="OBJID_HALLWAY2_DOOR5" x="953" y="215">
<polygon points="0,0 -3,228 64,291 64,29"/>
</object>
<object id="3" name="OBJID_HALLWAY2_DOOR4" x="327" y="232" width="113" height="203"/>
<object id="4" name="OBJID_GO_LEFT" x="93" y="435">
<polygon points="0,0 -80,90 -92,91 -93,-253 1,-254"/>
</object>
<object id="6" name="OBJID_GO_LEFT" x="78" y="455" width="52" height="43"/>
</objectgroup>
<objectgroup id="4" name="navmesh">
<object id="1" x="93" y="436">
<polygon points="0,0 -80,88 941,88 843,-1"/>
</object>
</objectgroup>
<objectgroup id="5" name="points">
<object id="8" name="OBJID_PLAYER_START_DEFAULT" x="65" y="477">
<point/>
</object>
</objectgroup>
</map>

View File

@ -1,32 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.2" orientation="orthogonal" renderorder="right-down" width="40" height="25" tilewidth="32" tileheight="32" infinite="0" nextlayerid="5" nextobjectid="19">
<map version="1.9" tiledversion="1.9.2" orientation="orthogonal" renderorder="right-down" width="40" height="25" tilewidth="32" tileheight="32" infinite="0" nextlayerid="6" nextobjectid="24">
<imagelayer id="2" name="Image Layer 1">
<image source="../build/default/lobby.png" width="1280" height="800"/>
<image source="../build/default/lobby.png" width="1066" 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"/>
</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>
<objectgroup id="3" name="clickable">
<object id="1" name="OBJID_DOOR_TO_MANAGERS_OFFICE_FROM_LOBBY" x="227" y="312" width="64" height="128"/>
<object id="19" name="OBJID_LEAVE_ROOM" x="468" y="720" width="83" height="79"/>
<object id="20" name="OBJID_LOBBY_TO_CLOAKROOM" x="752" y="319" width="51" height="121"/>
</objectgroup>
<objectgroup id="5" name="points">
<object id="21" name="OBJID_PLAYER_START_DEFAULT" x="352" y="684">
<point/>
</object>
<object id="22" name="OBJID_PLAYER_START+SCENE_MANAGERS_OFFICE" x="256" y="443">
<point/>
</object>
<object id="23" name="OBJID_PLAYER_START+SCENE_CLOAKROOM" x="775" y="443">
<point/>
</object>
</objectgroup>
</map>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.2" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="32" tileheight="32" infinite="0" nextlayerid="5" nextobjectid="24">
<map version="1.9" tiledversion="1.9.2" orientation="orthogonal" renderorder="right-down" width="35" height="25" tilewidth="32" tileheight="32" infinite="0" nextlayerid="6" nextobjectid="28">
<imagelayer id="2" name="Image Layer 1">
<image source="../build/default/managers_office.png" width="1280" height="800"/>
</imagelayer>
@ -46,5 +46,17 @@
<object id="23" name="OBJID_MANAGERS_OFFICE_SAFE" x="784" y="417">
<polygon points="0,0 1,-122 150,-122 193,-79 192,75 40,75"/>
</object>
<object id="24" name="OBJID_MANAGERS_OFFICE_TO_HALLWAY" x="614" y="236" width="105" height="181"/>
</objectgroup>
<objectgroup id="5" name="points">
<object id="25" name="OBJID_PLAYER_START_DEFAULT" x="814" y="715">
<point/>
</object>
<object id="26" name="OBJID_PLAYER_START+SCENE_HALLWAY1" x="665" y="417">
<point/>
</object>
<object id="27" name="OBJID_PLAYER_START+SCENE_BASEMENT" x="405" y="561">
<point/>
</object>
</objectgroup>
</map>

63
navmesh/stairway1.tmx Normal file
View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.9" tiledversion="1.9.2" orientation="orthogonal" renderorder="right-down" width="34" height="25" tilewidth="32" tileheight="32" infinite="0" nextlayerid="6" nextobjectid="18">
<imagelayer id="2" name="Image Layer 1">
<image source="../build/default/stairwayUpLeft.png" width="1066" height="800"/>
</imagelayer>
<objectgroup id="3" name="clickable">
<object id="3" name="OBJID_STAIRWAY1_BOTTOM" x="869" y="344">
<polygon points="0,0 0,251 60,342 61,57"/>
</object>
<object id="4" name="OBJID_STAIRWAY1_TOP" x="94" y="70">
<polygon points="0,0 59,-17 65,207 2,272"/>
</object>
</objectgroup>
<objectgroup id="4" name="navmesh">
<object id="5" x="88" y="355">
<polygon points="0,0 43,-1 105,-74 77,-82"/>
</object>
<object id="6" x="154" y="355">
<polygon points="-23,-1 39,-74 93,-42 42,40"/>
</object>
<object id="7" x="202" y="385">
<polygon points="-6,10 41,41 88,-53 45,-72"/>
</object>
<object id="8" x="247" y="419">
<polygon points="-4,7 61,37 98,-69 43,-87"/>
</object>
<object id="9" x="310" y="452">
<polygon points="-2,4 43,33 69,-77 35,-102"/>
</object>
<object id="10" x="353" y="485">
<polygon points="0,0 47,30 61,-78 26,-110"/>
</object>
<object id="11" x="400" y="515">
<polygon points="0,0 47,33 52,-76 14,-108"/>
</object>
<object id="12" x="447" y="548">
<polygon points="0,0 66,30 57,-89 5,-109"/>
</object>
<object id="13" x="513" y="578">
<polygon points="0,0 46,32 31,-93 -9,-119"/>
</object>
<object id="14" x="559" y="610">
<polygon points="0,0 49,31 21,-102 -15,-125"/>
</object>
<object id="15" x="608" y="641">
<polygon points="0,0 53,34 17,-108 -28,-133"/>
</object>
<object id="16" x="661" y="675">
<polygon points="0,0 65,31 19,-104 -36,-142"/>
</object>
<object id="17" x="726" y="706">
<polygon points="0,0 229,30 125,-135 -46,-135"/>
</object>
</objectgroup>
<objectgroup id="5" name="points">
<object id="1" name="OBJID_PLAYER_START_DEFAULT" x="885" y="642">
<point/>
</object>
<object id="2" name="OBJID_PLAYER_START+SCENE_HALLWAY_B2" x="140" y="307">
<point/>
</object>
</objectgroup>
</map>

55
navmesh/world.world Normal file
View File

@ -0,0 +1,55 @@
{
"maps": [
{
"fileName": "hallway2.tmx",
"height": 800,
"width": 1088,
"x": 0,
"y": 0
},
{
"fileName": "hallway1.tmx",
"height": 800,
"width": 1088,
"x": 0,
"y": 800
},
{
"fileName": "hallway3.tmx",
"height": 800,
"width": 1088,
"x": 0,
"y": -800
},
{
"fileName": "managers_office.tmx",
"height": 640,
"width": 960,
"x": 0,
"y": 1600
},
{
"fileName": "basement.tmx",
"height": 800,
"width": 1280,
"x": -672,
"y": 2400
},
{
"fileName": "lobby.tmx",
"height": 800,
"width": 1280,
"x": 736,
"y": 2400
},
{
"fileName": "cloakroom.tmx",
"height": 800,
"width": 1088,
"x": 1280,
"y": 1600
}
],
"onlyShowAdjacentMaps": false,
"type": "world"
}

View File

@ -11,3 +11,36 @@
#define OBJID_BASEMENT_LADDER 11
#define OBJID_CLOSE_MODAL 12
#define OBJID_POPCORN_BARREL 13
#define OBJID_MENUBAR 14
#define OBJID_LEAVE_ROOM 15
#define OBJID_PAGER 16
#define OBJID_NEXT_ROOM 17
#define OBJID_LOBBY_TO_CLOAKROOM 18
#define OBJID_MANAGERS_OFFICE_TO_HALLWAY 19
#define OBJID_GO_LEFT 20
#define OBJID_GO_RIGHT 21
#define OBJID_HALLWAY2_DOOR1 22
#define OBJID_HALLWAY2_DOOR2 23
#define OBJID_HALLWAY2_DOOR3 24
#define OBJID_HALLWAY2_DOOR4 25
#define OBJID_HALLWAY2_DOOR5 26
#define OBJID_STAIRWAY1_BOTTOM 27
#define OBJID_STAIRWAY1_TOP 28
#define OBJID_INVENTORY_SLOTS 0x01000000 // + slot number
#define OBJID_PLAYER_START 0x02000000 // + previous scene number
#define OBJID_PLAYER_START_DEFAULT 0x02ffffff
#define SCENE_LOBBY 1
#define SCENE_MANAGERS_OFFICE 2
#define SCENE_MANAGERS_OFFICE_SAFE 3
#define SCENE_BASEMENT 4
#define SCENE_TEXTBOX 5
#define SCENE_HALLWAY1 6
#define SCENE_HALLWAY2 7
#define SCENE_HALLWAY3 8
#define SCENE_CLOAKROOM 9
#define SCENE_STAIRWAY1 10
#define SCENE_HALLWAY_B1 11
#define SCENE_HALLWAY_B2 12
#define SCENE_HALLWAY_B3 13

BIN
sprites/cloakroom.xcf Normal file

Binary file not shown.

BIN
sprites/hallway1.xcf Normal file

Binary file not shown.

BIN
sprites/hallway2.xcf Normal file

Binary file not shown.

BIN
sprites/hallway3.xcf Normal file

Binary file not shown.

BIN
sprites/hallwayb1.xcf Normal file

Binary file not shown.

BIN
sprites/hallwayb2.xcf Normal file

Binary file not shown.

BIN
sprites/hallwayb3.xcf Normal file

Binary file not shown.

BIN
sprites/item_pager.xcf Normal file

Binary file not shown.

BIN
sprites/item_popcorn.xcf Normal file

Binary file not shown.

Binary file not shown.

BIN
sprites/menubar.xcf Normal file

Binary file not shown.

BIN
sprites/stairwayUpLeft.xcf Normal file

Binary file not shown.

Binary file not shown.

View File

@ -7,7 +7,7 @@ static const char *textbox_text;
static int tb_width_chars, tb_height_chars;
static int visible_chars = 0;
extern const char _binary_sprite_font_raw_start[];
extern const unsigned char _binary_sprite_font_raw_start[];
@ -16,6 +16,9 @@ extern const char _binary_sprite_font_raw_start[];
#define LINESPACE 8
static void textbox_render_fn(struct scene *s) {
struct sprite *fontsprite = get_decompressed_sprite(_binary_sprite_font_raw_start);
int boxheight = tb_height_chars*(CHARSIZE + LINESPACE) - LINESPACE;
int boxwidth = tb_width_chars*(CHARSIZE + HSPACE) - HSPACE;
int x = (1280 - tb_width_chars*CHARSIZE)/2;
@ -31,7 +34,7 @@ static void textbox_render_fn(struct scene *s) {
x = xleft;
y += CHARSIZE + LINESPACE;
} else {
blit(x, y, CHARSIZE, CHARSIZE, (*str - 32)*(CHARSIZE*CHARSIZE) + (uint32_t*)_binary_sprite_font_raw_start);
blit(x, y, CHARSIZE, CHARSIZE, (*str - 32)*(CHARSIZE*CHARSIZE) + (uint32_t*)fontsprite->pixels);
x += CHARSIZE + HSPACE;
}
}
@ -52,10 +55,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;
}