mirror of
https://github.com/xtreme8000/CavEX.git
synced 2025-01-22 09:11:55 -05:00
Add workbench crafting screen
This commit is contained in:
parent
3fa7ea3938
commit
bfe190ed67
15 changed files with 615 additions and 9 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
289
source/game/gui/screen_crafting.c
Normal file
289
source/game/gui/screen_crafting.c
Normal 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,
|
||||
};
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
258
source/network/inventory_crafting.c
Normal file
258
source/network/inventory_crafting.c
Normal 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,
|
||||
};
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue