Add workbench crafting screen

This commit is contained in:
xtreme8000 2023-12-06 22:02:58 +01:00
parent 3fa7ea3938
commit bfe190ed67
15 changed files with 615 additions and 9 deletions

View file

@ -89,6 +89,7 @@ add_executable(cavex
source/game/gui/screen_load_world.c
source/game/gui/screen_select_world.c
source/game/gui/screen_inventory.c
source/game/gui/screen_crafting.c
source/game/gui/screen.c
source/game/camera.c
source/game/game_state.c
@ -107,6 +108,7 @@ add_executable(cavex
source/network/server_local.c
source/network/server_world.c
source/network/inventory_player.c
source/network/inventory_crafting.c
source/graphics/gfx_util.c
source/graphics/gui_util.c

View file

@ -36,7 +36,10 @@ extern struct screen screen_ingame;
extern struct screen screen_load_world;
extern struct screen screen_select_world;
extern struct screen screen_inventory;
extern struct screen screen_crafting;
void screen_set(struct screen* s);
void screen_crafting_set_windowc(uint8_t container);
#endif

View file

@ -0,0 +1,289 @@
/*
Copyright (c) 2023 ByteBit/xtreme8000
This file is part of CavEX.
CavEX is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CavEX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CavEX. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../../graphics/gfx_util.h"
#include "../../graphics/gui_util.h"
#include "../../graphics/render_model.h"
#include "../../network/server_interface.h"
#include "../../platform/gfx.h"
#include "../../platform/input.h"
#include "../../platform/time.h"
#include "../game_state.h"
#include "screen.h"
#define GUI_WIDTH 176
#define GUI_HEIGHT 167
struct inv_slot {
int x, y;
size_t slot;
};
static bool pointer_has_item;
static bool pointer_available;
static float pointer_x, pointer_y, pointer_angle;
static struct inv_slot slots[CRAFTING_SIZE];
static size_t slots_index;
static size_t selected_slot;
static uint8_t crafting_container;
void screen_crafting_set_windowc(uint8_t container) {
crafting_container = container;
}
static void screen_crafting_reset(struct screen* s, int width, int height) {
input_pointer_enable(true);
if(gstate.local_player)
gstate.local_player->data.local_player.capture_input = false;
s->render3D = screen_ingame.render3D;
pointer_available = false;
pointer_has_item = false;
slots_index = 0;
for(int k = 0; k < INVENTORY_SIZE_MAIN; k++) {
slots[slots_index++] = (struct inv_slot) {
.x = (8 + (k % INVENTORY_SIZE_HOTBAR) * 18) * 2,
.y = (84 + (k / INVENTORY_SIZE_HOTBAR) * 18) * 2,
.slot = k + CRAFTING_SLOT_MAIN,
};
}
for(int k = 0; k < INVENTORY_SIZE_HOTBAR; k++) {
if(k
== (int)inventory_get_hotbar(
windowc_get_latest(gstate.windows[WINDOWC_INVENTORY])))
selected_slot = slots_index;
slots[slots_index++] = (struct inv_slot) {
.x = (8 + k * 18) * 2,
.y = (84 + 3 * 18 + 4) * 2,
.slot = k + CRAFTING_SLOT_HOTBAR,
};
}
for(int k = 0; k < CRAFTING_SIZE_INPUT; k++) {
slots[slots_index++] = (struct inv_slot) {
.x = (30 + (k % 3) * 18) * 2,
.y = (17 + (k / 3) * 18) * 2,
.slot = k + CRAFTING_SLOT_INPUT,
};
}
slots[slots_index++] = (struct inv_slot) {
.x = 124 * 2,
.y = 35 * 2,
.slot = CRAFTING_SLOT_OUTPUT,
};
}
static void screen_crafting_update(struct screen* s, float dt) {
if(input_pressed(IB_INVENTORY)) {
svin_rpc_send(&(struct server_rpc) {
.type = SRPC_WINDOW_CLOSE,
.payload.window_close.window = crafting_container,
});
screen_set(&screen_ingame);
}
if(input_pressed(IB_GUI_CLICK)) {
uint16_t action_id;
if(windowc_new_action(gstate.windows[crafting_container], &action_id,
false, slots[selected_slot].slot)) {
svin_rpc_send(&(struct server_rpc) {
.type = SRPC_WINDOW_CLICK,
.payload.window_click.window = crafting_container,
.payload.window_click.action_id = action_id,
.payload.window_click.right_click = false,
.payload.window_click.slot = slots[selected_slot].slot,
});
}
} else if(input_pressed(IB_GUI_CLICK_ALT)) {
uint16_t action_id;
if(windowc_new_action(gstate.windows[crafting_container], &action_id,
true, slots[selected_slot].slot)) {
svin_rpc_send(&(struct server_rpc) {
.type = SRPC_WINDOW_CLICK,
.payload.window_click.window = crafting_container,
.payload.window_click.action_id = action_id,
.payload.window_click.right_click = true,
.payload.window_click.slot = slots[selected_slot].slot,
});
}
}
pointer_available = input_pointer(&pointer_x, &pointer_y, &pointer_angle);
size_t slot_nearest[4]
= {selected_slot, selected_slot, selected_slot, selected_slot};
int slot_dist[4] = {INT_MAX, INT_MAX, INT_MAX, INT_MAX};
int pointer_slot = -1;
int off_x = (gfx_width() - GUI_WIDTH * 2) / 2;
int off_y = (gfx_height() - GUI_HEIGHT * 2) / 2;
for(size_t k = 0; k < slots_index; k++) {
int dx = slots[k].x - slots[selected_slot].x;
int dy = slots[k].y - slots[selected_slot].y;
if(pointer_x >= off_x + slots[k].x
&& pointer_x < off_x + slots[k].x + 16 * 2
&& pointer_y >= off_y + slots[k].y
&& pointer_y < off_y + slots[k].y + 16 * 2)
pointer_slot = k;
int distx = dx * dx + dy * dy * 8;
int disty = dx * dx * 8 + dy * dy;
if(dx < 0 && distx < slot_dist[0]) {
slot_nearest[0] = k;
slot_dist[0] = distx;
}
if(dx > 0 && distx < slot_dist[1]) {
slot_nearest[1] = k;
slot_dist[1] = distx;
}
if(dy < 0 && disty < slot_dist[2]) {
slot_nearest[2] = k;
slot_dist[2] = disty;
}
if(dy > 0 && disty < slot_dist[3]) {
slot_nearest[3] = k;
slot_dist[3] = disty;
}
}
if(pointer_available && pointer_slot >= 0) {
selected_slot = pointer_slot;
pointer_has_item = true;
} else {
if(input_pressed(IB_GUI_LEFT)) {
selected_slot = slot_nearest[0];
pointer_has_item = false;
}
if(input_pressed(IB_GUI_RIGHT)) {
selected_slot = slot_nearest[1];
pointer_has_item = false;
}
if(input_pressed(IB_GUI_UP)) {
selected_slot = slot_nearest[2];
pointer_has_item = false;
}
if(input_pressed(IB_GUI_DOWN)) {
selected_slot = slot_nearest[3];
pointer_has_item = false;
}
}
}
static void screen_crafting_render2D(struct screen* s, int width, int height) {
struct inventory* inv
= windowc_get_latest(gstate.windows[crafting_container]);
// darken background
gfx_texture(false);
gutil_texquad_col(0, 0, 0, 0, 0, 0, width, height, 0, 0, 0, 180);
gfx_texture(true);
int off_x = (width - GUI_WIDTH * 2) / 2;
int off_y = (height - GUI_HEIGHT * 2) / 2;
// draw inventory
gfx_bind_texture(&texture_gui_crafting);
gutil_texquad(off_x, off_y, 0, 0, GUI_WIDTH, GUI_HEIGHT, GUI_WIDTH * 2,
GUI_HEIGHT * 2);
gutil_text(off_x + 28 * 2, off_y + 6 * 2, "\2478Crafting", 16, false);
struct inv_slot* selection = slots + selected_slot;
// draw items
for(size_t k = 0; k < slots_index; k++) {
struct item_data item;
if((selected_slot != k || !inventory_get_picked_item(inv, NULL)
|| (pointer_available && pointer_has_item))
&& inventory_get_slot(inv, slots[k].slot, &item))
gutil_draw_item(&item, off_x + slots[k].x, off_y + slots[k].y, 1);
}
gfx_bind_texture(&texture_gui2);
gutil_texquad(off_x + selection->x - 8, off_y + selection->y - 8, 208, 0,
24, 24, 24 * 2, 24 * 2);
int icon_offset = 32;
icon_offset += gutil_control_icon(icon_offset, IB_GUI_UP, "Move");
if(inventory_get_picked_item(inv, NULL)) {
icon_offset
+= gutil_control_icon(icon_offset, IB_GUI_CLICK, "Swap item");
} else if(inventory_get_slot(inv, selection->slot, NULL)) {
icon_offset
+= gutil_control_icon(icon_offset, IB_GUI_CLICK, "Pickup item");
icon_offset
+= gutil_control_icon(icon_offset, IB_GUI_CLICK_ALT, "Split stack");
}
icon_offset += gutil_control_icon(icon_offset, IB_INVENTORY, "Leave");
struct item_data item;
if(inventory_get_picked_item(inv, &item)) {
if(pointer_available && pointer_has_item) {
gutil_draw_item(&item, pointer_x - 8 * 2, pointer_y - 8 * 2, 0);
} else {
gutil_draw_item(&item, off_x + selection->x, off_y + selection->y,
0);
}
} else if(inventory_get_slot(inv, selection->slot, &item)) {
char* tmp = item_get(&item) ? item_get(&item)->name : "Unknown";
gfx_blending(MODE_BLEND);
gfx_texture(false);
gutil_texquad_col(off_x + selection->x - 4 + 16
- gutil_font_width(tmp, 16) / 2,
off_y + selection->y - 4 + 46, 0, 0, 0, 0,
gutil_font_width(tmp, 16) + 7, 16 + 8, 0, 0, 0, 180);
gfx_texture(true);
gfx_blending(MODE_OFF);
gutil_text(off_x + selection->x + 16 - gutil_font_width(tmp, 16) / 2,
off_y + selection->y + 46, tmp, 16, false);
}
if(pointer_available) {
gfx_bind_texture(&texture_pointer);
gutil_texquad_rt_any(pointer_x, pointer_y, glm_rad(pointer_angle), 0, 0,
256, 256, 96, 96);
}
}
struct screen screen_crafting = {
.reset = screen_crafting_reset,
.update = screen_crafting_update,
.render2D = screen_crafting_render2D,
.render3D = NULL,
.render_world = true,
};

View file

@ -57,10 +57,15 @@ void inventory_copy(struct inventory* inv, struct inventory* from) {
void inventory_destroy(struct inventory* inv) {
assert(inv && inv->items);
bool free_mem = false;
if(inv->logic && inv->logic->on_destroy)
inv->logic->on_destroy(inv);
free_mem = inv->logic->on_destroy(inv);
free(inv->items);
if(free_mem)
free(inv);
}
void inventory_clear(struct inventory* inv) {

View file

@ -39,6 +39,14 @@
#define INVENTORY_SLOT_MAIN 9
#define INVENTORY_SLOT_HOTBAR 36
#define CRAFTING_SIZE 46
#define CRAFTING_SIZE_INPUT 9
#define CRAFTING_SLOT_OUTPUT 0
#define CRAFTING_SLOT_INPUT 1
#define CRAFTING_SLOT_MAIN 10
#define CRAFTING_SLOT_HOTBAR 37
#define SPECIAL_SLOT_PICKED_ITEM 255
DICT_SET_DEF(set_inv_slot, size_t)
@ -62,7 +70,7 @@ struct inventory {
struct inventory_logic {
void (*on_create)(struct inventory* inv);
void (*on_destroy)(struct inventory* inv);
bool (*on_destroy)(struct inventory* inv);
bool (*pre_action)(struct inventory* inv, size_t slot, bool right,
set_inv_slot_t changes);
void (*post_action)(struct inventory* inv, size_t slot, bool right,

View file

@ -51,7 +51,7 @@ void recipe_add(array_recipe_t recipes, struct item_data result, size_t width,
size_t height, uint8_t* shape, ...) {
assert(recipes && width > 0 && height > 0 && width * height <= 9 && shape);
int count = 0;
size_t count = 0;
for(size_t k = 0; k < width * height; k++) {
if(shape[k] > count)
count = shape[k];

View file

@ -21,11 +21,13 @@
#include "window_container.h"
bool windowc_create(struct window_container* wc, enum window_type type) {
bool windowc_create(struct window_container* wc, enum window_type type,
size_t slot_count) {
assert(wc);
ilist_inventory_init(wc->invs);
wc->slot_count = slot_count;
wc->type = type;
wc->next_action_id = 0;
@ -68,7 +70,7 @@ bool windowc_new_action(struct window_container* wc, uint16_t* action_id,
if(!next)
return false;
if(!inventory_create(next, NULL, NULL, INVENTORY_SIZE)) // TODO
if(!inventory_create(next, NULL, NULL, wc->slot_count))
return false;
if(!ilist_inventory_empty_p(wc->invs))

View file

@ -26,6 +26,7 @@
#include "inventory.h"
#define WINDOWC_INVENTORY 0
#define WINDOWC_CRAFTING 1 // local server use only
enum window_type {
WINDOW_TYPE_CHEST = 0,
@ -37,11 +38,13 @@ enum window_type {
struct window_container {
enum window_type type;
size_t slot_count;
uint16_t next_action_id;
ilist_inventory_t invs;
};
bool windowc_create(struct window_container* wc, enum window_type type);
bool windowc_create(struct window_container* wc, enum window_type type,
size_t slot_count);
void windowc_destroy(struct window_container* wc);
struct inventory* windowc_get_latest(struct window_container* wc);

View file

@ -122,7 +122,7 @@ void clin_process(struct client_rpc* call) {
= malloc(sizeof(struct window_container));
assert(gstate.windows[WINDOWC_INVENTORY]);
windowc_create(gstate.windows[WINDOWC_INVENTORY],
WINDOW_TYPE_INVENTORY);
WINDOW_TYPE_INVENTORY, INVENTORY_SIZE);
gstate.world_loaded = false;
gstate.world.dimension = call->payload.world_reset.dimension;
@ -152,6 +152,29 @@ void clin_process(struct client_rpc* call) {
call->payload.window_transaction.accepted);
break;
}
case CRPC_OPEN_WINDOW: {
uint8_t window = call->payload.window_open.window;
if(gstate.windows[window]) {
windowc_destroy(gstate.windows[window]);
free(gstate.windows[window]);
}
gstate.windows[window] = malloc(sizeof(struct window_container));
if(gstate.windows[window]) {
windowc_create(gstate.windows[window],
call->payload.window_open.type,
call->payload.window_open.slot_count);
if(call->payload.window_open.type == WINDOW_TYPE_WORKBENCH) {
screen_crafting_set_windowc(window);
screen_set(&screen_crafting);
}
}
break;
}
case CRPC_TIME_SET:
gstate.world_time = call->payload.time_set;
gstate.world_time_start = time_get();

View file

@ -21,6 +21,7 @@
#define CLIENT_INTERFACE_H
#include "../item/items.h"
#include "../item/window_container.h"
#include "../world.h"
#include "../cglm/cglm.h"
@ -38,6 +39,7 @@ enum client_rpc_type {
CRPC_PICKUP_ITEM,
CRPC_ENTITY_DESTROY,
CRPC_ENTITY_MOVE,
CRPC_OPEN_WINDOW,
};
struct client_rpc {
@ -77,6 +79,11 @@ struct client_rpc {
uint16_t action_id;
bool accepted;
} window_transaction;
struct {
uint8_t window;
enum window_type type;
uint8_t slot_count;
} window_open;
struct {
uint32_t entity_id;
struct item_data item;

View file

@ -0,0 +1,258 @@
/*
Copyright (c) 2023 ByteBit/xtreme8000
This file is part of CavEX.
CavEX is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CavEX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CavEX. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../item/recipe.h"
#include "../item/window_container.h"
#include "server_local.h"
static bool inv_match_crafting(struct inventory* inv,
struct item_data* result) {
struct item_data slots[9];
bool slot_empty[9];
memset(slot_empty, true, sizeof(slot_empty));
for(size_t k = 0; k < CRAFTING_SIZE_INPUT; k++)
slot_empty[k]
= !inventory_get_slot(inv, CRAFTING_SLOT_INPUT + k, slots + k);
return recipe_match(recipes_crafting, slots, slot_empty, result);
}
static bool inv_pre_action(struct inventory* inv, size_t slot, bool right,
set_inv_slot_t changes) {
if(slot == CRAFTING_SLOT_OUTPUT) {
struct item_data output;
if(!right && inventory_get_slot(inv, CRAFTING_SLOT_OUTPUT, &output)) {
for(size_t k = CRAFTING_SLOT_INPUT;
k < CRAFTING_SLOT_INPUT + CRAFTING_SIZE_INPUT; k++) {
struct item_data it;
if(inventory_get_slot(inv, k, &it) && it.count > 1) {
it.count--;
inventory_set_slot(inv, k, it);
} else {
inventory_clear_slot(inv, k);
}
set_inv_slot_push(changes, k);
}
struct item_data picked;
if(inventory_get_picked_item(inv, &picked)) {
struct item* it_type = item_get(&picked);
if(it_type && picked.id == output.id
&& picked.durability == output.durability
&& picked.count + output.count <= it_type->max_stack) {
picked.count += output.count;
inventory_set_picked_item(inv, picked);
set_inv_slot_push(changes, SPECIAL_SLOT_PICKED_ITEM);
return false;
}
} else {
return true;
}
}
return false;
}
return true;
}
static void inv_post_action(struct inventory* inv, size_t slot, bool right,
bool accepted, set_inv_slot_t changes) {
if((slot >= CRAFTING_SLOT_INPUT
&& slot < CRAFTING_SLOT_INPUT + CRAFTING_SIZE_INPUT)
|| slot == CRAFTING_SLOT_OUTPUT) {
struct item_data result;
if(inv_match_crafting(inv, &result)) {
inventory_set_slot(inv, CRAFTING_SLOT_OUTPUT, result);
} else {
inventory_clear_slot(inv, CRAFTING_SLOT_OUTPUT);
}
set_inv_slot_push(changes, CRAFTING_SLOT_OUTPUT);
}
}
static void inv_on_close(struct inventory* inv) {
struct server_local* s = inv->user;
set_inv_slot_t changes;
set_inv_slot_init(changes);
inventory_clear_slot(inv, CRAFTING_SLOT_OUTPUT);
set_inv_slot_push(changes, CRAFTING_SLOT_OUTPUT);
for(size_t k = CRAFTING_SLOT_INPUT;
k < CRAFTING_SLOT_INPUT + CRAFTING_SIZE_INPUT; k++) {
struct item_data item;
inventory_get_slot(inv, k, &item);
if(item.id != 0) {
inventory_clear_slot(inv, k);
set_inv_slot_push(changes, k);
server_local_spawn_item(
(vec3) {s->player.x, s->player.y, s->player.z}, &item, true, s);
}
}
struct item_data picked_item;
if(inventory_get_picked_item(inv, &picked_item)) {
inventory_clear_picked_item(inv);
set_inv_slot_push(changes, SPECIAL_SLOT_PICKED_ITEM);
server_local_spawn_item((vec3) {s->player.x, s->player.y, s->player.z},
&picked_item, true, s);
}
server_local_send_inv_changes(changes, inv, WINDOWC_CRAFTING);
set_inv_slot_clear(changes);
inventory_destroy(inv);
}
#define min(a, b) ((a) < (b) ? (a) : (b))
static bool inventory_collect(struct inventory* inv, struct item_data* item,
uint8_t* slot_priority, size_t slot_length,
set_inv_slot_t changes) {
assert(inv && item && item->id != 0 && changes);
struct item* it = item_get(item);
if(!it)
return false;
while(item->count > 0) {
bool has_canidate_equal = false;
size_t candidate_equal = 0;
bool has_canidate_empty = false;
size_t candidate_empty = 0;
for(size_t k = 0; k < slot_length; k++) {
uint8_t slot = slot_priority[k];
if(inv->items[slot].id == item->id
&& inv->items[slot].durability == item->durability
&& inv->items[slot].count < it->max_stack) {
has_canidate_equal = true;
candidate_equal = slot;
break;
}
if(!has_canidate_empty && inv->items[slot].id == 0) {
has_canidate_empty = true;
candidate_empty = slot;
}
}
if(has_canidate_equal || has_canidate_empty) {
size_t candidate
= has_canidate_equal ? candidate_equal : candidate_empty;
size_t additional
= min(it->max_stack - inv->items[candidate].count, item->count);
inv->items[candidate].id = item->id;
inv->items[candidate].durability = item->durability;
inv->items[candidate].count += additional;
item->count -= additional;
set_inv_slot_push(changes, candidate);
} else {
return false;
}
}
return true;
}
static bool inv_on_collect(struct inventory* inv, struct item_data* item) {
uint8_t priorities[INVENTORY_SIZE_HOTBAR + INVENTORY_SIZE_MAIN];
for(size_t k = 0; k < INVENTORY_SIZE_HOTBAR; k++)
priorities[k] = k + CRAFTING_SLOT_HOTBAR;
for(size_t k = 0; k < INVENTORY_SIZE_MAIN; k++)
priorities[k + INVENTORY_SIZE_HOTBAR] = k + CRAFTING_SLOT_MAIN;
set_inv_slot_t changes;
set_inv_slot_init(changes);
bool success
= inventory_collect(inv, item, priorities,
sizeof(priorities) / sizeof(*priorities), changes);
server_local_send_inv_changes(changes, inv, WINDOWC_CRAFTING);
set_inv_slot_clear(changes);
return success;
}
static void inv_on_create(struct inventory* inv) {
struct server_local* s = inv->user;
set_inv_slot_t changes;
set_inv_slot_init(changes);
for(size_t k = 0; k < INVENTORY_SIZE_HOTBAR; k++) {
inv->items[k + CRAFTING_SLOT_HOTBAR]
= s->player.inventory.items[k + INVENTORY_SLOT_HOTBAR];
set_inv_slot_push(changes, k + CRAFTING_SLOT_HOTBAR);
}
for(size_t k = 0; k < INVENTORY_SIZE_MAIN; k++) {
inv->items[k + CRAFTING_SLOT_MAIN]
= s->player.inventory.items[k + INVENTORY_SLOT_MAIN];
set_inv_slot_push(changes, k + CRAFTING_SLOT_MAIN);
}
server_local_send_inv_changes(changes, inv, WINDOWC_CRAFTING);
set_inv_slot_clear(changes);
}
static bool inv_on_destroy(struct inventory* inv) {
struct server_local* s = inv->user;
set_inv_slot_t changes;
set_inv_slot_init(changes);
for(size_t k = 0; k < INVENTORY_SIZE_HOTBAR; k++) {
s->player.inventory.items[k + INVENTORY_SLOT_HOTBAR]
= inv->items[k + CRAFTING_SLOT_HOTBAR];
set_inv_slot_push(changes, k + INVENTORY_SLOT_HOTBAR);
}
for(size_t k = 0; k < INVENTORY_SIZE_MAIN; k++) {
s->player.inventory.items[k + INVENTORY_SLOT_MAIN]
= inv->items[k + CRAFTING_SLOT_MAIN];
set_inv_slot_push(changes, k + INVENTORY_SLOT_MAIN);
}
server_local_send_inv_changes(changes, &s->player.inventory,
WINDOWC_INVENTORY);
set_inv_slot_clear(changes);
return true;
}
struct inventory_logic inventory_logic_crafting = {
.pre_action = inv_pre_action,
.post_action = inv_post_action,
.on_collect = inv_on_collect,
.on_create = inv_on_create,
.on_destroy = inv_on_destroy,
.on_close = inv_on_close,
};

View file

@ -19,4 +19,5 @@
#include "../item/inventory.h"
extern struct inventory_logic inventory_logic_player;
extern struct inventory_logic inventory_logic_player;
extern struct inventory_logic inventory_logic_crafting;

View file

@ -160,10 +160,11 @@ static void server_local_process(struct server_rpc* call, void* user) {
break;
}
case SRPC_WINDOW_CLOSE: {
if(s->player.active_inventory && s->player.active_inventory->logic
if(s->player.active_inventory->logic
&& s->player.active_inventory->logic->on_close)
s->player.active_inventory->logic->on_close(
s->player.active_inventory);
s->player.active_inventory = &s->player.inventory;
break;
}

View file

@ -33,6 +33,7 @@ struct tex_gfx texture_items;
struct tex_gfx texture_font;
struct tex_gfx texture_anim;
struct tex_gfx texture_gui_inventory;
struct tex_gfx texture_gui_crafting;
struct tex_gfx texture_gui2;
struct tex_gfx texture_controls;
struct tex_gfx texture_pointer;
@ -88,6 +89,8 @@ void tex_init() {
tex_gfx_load_file(&texture_anim, "anim.png", TEX_FMT_RGBA32, false);
tex_gfx_load_file(&texture_gui_inventory, "gui/inventory.png",
TEX_FMT_RGBA16, false);
tex_gfx_load_file(&texture_gui_crafting, "gui/crafting.png", TEX_FMT_RGBA16,
false);
tex_gfx_load_file(&texture_gui2, "gui_2.png", TEX_FMT_RGBA16, false);
tex_gfx_load_file(&texture_items, "items.png", TEX_FMT_RGBA16, false);
tex_gfx_load_file(&texture_controls, "controls.png", TEX_FMT_RGBA16, false);

View file

@ -58,6 +58,7 @@ extern struct tex_gfx texture_items;
extern struct tex_gfx texture_font;
extern struct tex_gfx texture_anim;
extern struct tex_gfx texture_gui_inventory;
extern struct tex_gfx texture_gui_crafting;
extern struct tex_gfx texture_gui2;
extern struct tex_gfx texture_controls;
extern struct tex_gfx texture_pointer;