2021-08-30 15:50:05 +00:00
|
|
|
#include "items.h"
|
|
|
|
|
|
|
|
#define ITEM_PICK_RADIUS 25.0f
|
2021-09-09 07:46:22 +00:00
|
|
|
#define ITEM_MERGER_RADIUS 75.0f
|
2021-08-30 15:50:05 +00:00
|
|
|
#define ITEM_ATTRACT_RADIUS 75.0f
|
|
|
|
#define ITEM_ATTRACT_FORCE 0.63f
|
|
|
|
|
2022-08-09 14:46:23 +00:00
|
|
|
#define ITEM_CONTAINER_REACH_RADIUS 105.0f
|
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
void PickItem(ecs_iter_t *it) {
|
2022-07-31 14:34:47 +00:00
|
|
|
Position *p = ecs_field(it, Position, 2);
|
|
|
|
Inventory *inv = ecs_field(it, Inventory, 3);
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
for (int i = 0; i < it->count; i++) {
|
|
|
|
if (inv[i].pickup_time > game_time()) continue;
|
|
|
|
size_t ents_count;
|
|
|
|
int64_t *ents = world_chunk_query_entities(it->entities[i], &ents_count, 2);
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
for (size_t j = 0; j < ents_count; j++) {
|
|
|
|
ItemDrop *drop = 0;
|
|
|
|
if ((drop = ecs_get_mut_if(it->world, ents[j], ItemDrop))) {
|
2022-07-31 14:34:47 +00:00
|
|
|
Position *p2 = ecs_get_mut(it->world, ents[j], Position);
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
float dx = p2->x - p[i].x;
|
|
|
|
float dy = p2->y - p[i].y;
|
|
|
|
float range = zpl_sqrt(dx*dx + dy*dy);
|
|
|
|
if (range <= ITEM_PICK_RADIUS) {
|
2021-11-02 10:48:32 +00:00
|
|
|
uint16_t drop_id = item_find(drop->kind);
|
2021-08-30 15:50:05 +00:00
|
|
|
for (size_t k = 0; k < ITEMS_INVENTORY_SIZE; k += 1) {
|
|
|
|
ItemDrop *item = &inv[i].items[k];
|
|
|
|
uint16_t item_id = item_find(item->kind);
|
2021-11-02 10:48:32 +00:00
|
|
|
if (item_id != ASSET_INVALID && (item->quantity == 0 || (item->quantity != 0 && item->kind == drop->kind)) && item->quantity < item_max_quantity(drop_id)) {
|
2021-08-30 15:50:05 +00:00
|
|
|
uint32_t picked_count = zpl_max(0, drop->quantity);
|
2021-11-02 10:48:32 +00:00
|
|
|
picked_count = zpl_clamp(picked_count, 0, item_max_quantity(drop_id) - item->quantity);
|
2021-08-30 15:50:05 +00:00
|
|
|
item->quantity += picked_count;
|
|
|
|
drop->quantity -= picked_count;
|
2021-11-02 10:48:32 +00:00
|
|
|
item->kind = drop->kind;
|
2022-08-01 09:19:52 +00:00
|
|
|
entity_wake(ents[j]);
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
if (drop->quantity == 0)
|
|
|
|
item_despawn(ents[j]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (range <= ITEM_ATTRACT_RADIUS) {
|
2022-08-01 09:28:54 +00:00
|
|
|
entity_set_position(ents[j],
|
|
|
|
zpl_lerp(p2->x, p[i].x, ITEM_ATTRACT_FORCE*it->delta_time),
|
|
|
|
zpl_lerp(p2->y, p[i].y, ITEM_ATTRACT_FORCE*it->delta_time));
|
2021-08-30 15:50:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ITEM_DROP_PICKUP_TIME 2.5f
|
2021-09-09 07:46:22 +00:00
|
|
|
#define ITEM_DROP_MERGER_TIME 6.5f
|
2021-08-30 15:50:05 +00:00
|
|
|
|
|
|
|
void DropItem(ecs_iter_t *it) {
|
2022-07-31 14:34:47 +00:00
|
|
|
Input *in = ecs_field(it, Input, 1);
|
|
|
|
Position *p = ecs_field(it, Position, 2);
|
|
|
|
Inventory *inv = ecs_field(it, Inventory, 3);
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
for (int i = 0; i < it->count; i++) {
|
|
|
|
if (!in[i].drop) continue;
|
2022-08-09 14:46:23 +00:00
|
|
|
|
|
|
|
ItemDrop *items = inv[i].items;
|
|
|
|
|
|
|
|
if (in[i].storage_action){
|
|
|
|
if (world_entity_valid(in[i].storage_ent)){
|
|
|
|
ItemContainer *ic = 0;
|
|
|
|
if ((ic = ecs_get_mut_if(it->world, in[i].storage_ent, ItemContainer))){
|
|
|
|
items = ic->items;
|
|
|
|
}else{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ItemDrop *item = &items[in[i].storage_action ? in[i].storage_selected_item : in[i].selected_item];
|
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
if (item->quantity <= 0)
|
|
|
|
continue;
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-09-09 07:46:22 +00:00
|
|
|
uint32_t dropped_count = item->quantity;
|
|
|
|
if (in[i].sprint) {
|
|
|
|
dropped_count /= 2;
|
|
|
|
} else if (in[i].ctrl) {
|
|
|
|
dropped_count = dropped_count > 0 ? 1 : 0;
|
|
|
|
}
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-09-09 07:46:22 +00:00
|
|
|
if (dropped_count == 0)
|
|
|
|
continue;
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-09-09 07:46:22 +00:00
|
|
|
ecs_entity_t te = item_spawn(item->kind, dropped_count);
|
|
|
|
item->quantity -= dropped_count;
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2022-07-31 14:34:47 +00:00
|
|
|
ItemDrop *d = ecs_get_mut(world_ecs(), te, ItemDrop);
|
2021-09-09 07:46:22 +00:00
|
|
|
*d = (ItemDrop){
|
|
|
|
.kind = item->kind,
|
|
|
|
.quantity = dropped_count,
|
|
|
|
.merger_time = game_time() + ITEM_DROP_MERGER_TIME,
|
|
|
|
};
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2022-07-31 14:34:47 +00:00
|
|
|
Position *ipos = ecs_get_mut(it->world, te, Position);
|
2021-09-09 07:46:22 +00:00
|
|
|
*ipos = p[i];
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2022-07-31 14:34:47 +00:00
|
|
|
Velocity *v = ecs_get_mut(it->world, te, Velocity);
|
2021-09-09 07:46:22 +00:00
|
|
|
v->x = in[i].mx * 800.0f;
|
|
|
|
v->y = in[i].my * 800.0f;
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-09-09 07:46:22 +00:00
|
|
|
inv[i].pickup_time = game_time() + ITEM_DROP_PICKUP_TIME;
|
|
|
|
in[i].drop = false;
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-11-02 10:48:32 +00:00
|
|
|
if (item->quantity == 0) {
|
|
|
|
item->kind = 0;
|
|
|
|
}
|
2021-09-09 07:46:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MergeItems(ecs_iter_t *it) {
|
2022-07-31 14:34:47 +00:00
|
|
|
Position *p = ecs_field(it, Position, 1);
|
|
|
|
ItemDrop *id = ecs_field(it, ItemDrop, 2);
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-09-09 07:46:22 +00:00
|
|
|
for (int i = 0; i < it->count; i += 1) {
|
|
|
|
ItemDrop *item = &id[i];
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-09-09 07:46:22 +00:00
|
|
|
if (item->merger_time < game_time())
|
|
|
|
continue;
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
size_t ents_count;
|
2021-09-09 07:46:22 +00:00
|
|
|
int64_t *ents = world_chunk_query_entities(it->entities[i], &ents_count, 1);
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
for (size_t j = 0; j < ents_count; j++) {
|
|
|
|
ItemDrop *drop = 0;
|
|
|
|
if ((drop = ecs_get_mut_if(it->world, ents[j], ItemDrop))) {
|
2021-09-09 07:46:22 +00:00
|
|
|
if (drop->kind != item->kind || (ecs_entity_t)ents[j] == it->entities[i] || drop->quantity == 0 || item->quantity == 0)
|
|
|
|
continue;
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
Position const* p2 = ecs_get(it->world, ents[j], Position);
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-09-09 07:46:22 +00:00
|
|
|
float dx = p2->x - (p[i].x);
|
|
|
|
float dy = p2->y - (p[i].y);
|
2021-08-30 15:50:05 +00:00
|
|
|
float range = zpl_sqrt(dx*dx + dy*dy);
|
2021-09-09 07:46:22 +00:00
|
|
|
if (range <= ITEM_MERGER_RADIUS) {
|
|
|
|
drop->quantity += item->quantity;
|
|
|
|
item_despawn(it->entities[i]);
|
|
|
|
break;
|
2021-08-30 15:50:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwapItems(ecs_iter_t *it) {
|
2022-07-31 14:34:47 +00:00
|
|
|
Input *in = ecs_field(it, Input, 1);
|
|
|
|
Inventory *inv = ecs_field(it, Inventory, 2);
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
for (int i = 0; i < it->count; i++) {
|
|
|
|
if (!in[i].swap) continue;
|
2022-08-09 14:46:23 +00:00
|
|
|
|
|
|
|
ItemDrop *items = inv[i].items;
|
|
|
|
|
|
|
|
if (in[i].storage_action){
|
|
|
|
if (world_entity_valid(in[i].storage_ent)){
|
|
|
|
ItemContainer *ic = 0;
|
|
|
|
if ((ic = ecs_get_mut_if(it->world, in[i].storage_ent, ItemContainer))){
|
|
|
|
items = ic->items;
|
|
|
|
}else{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ItemDrop *to = 0;
|
|
|
|
ItemDrop *from = 0;
|
|
|
|
|
|
|
|
if (in[i].swap_storage){
|
|
|
|
in[i].swap_storage = false;
|
|
|
|
|
|
|
|
if (in[i].storage_action){
|
|
|
|
from = &inv[i].items[in[i].swap_from];
|
|
|
|
to = &items[in[i].swap_to];
|
|
|
|
}else{
|
|
|
|
if (world_entity_valid(in[i].storage_ent)){
|
|
|
|
ItemContainer *ic = 0;
|
|
|
|
if ((ic = ecs_get_mut_if(it->world, in[i].storage_ent, ItemContainer))){
|
|
|
|
from = &ic->items[in[i].swap_from];
|
|
|
|
}else{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
to = &items[in[i].swap_to];
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
from = &items[in[i].swap_from];
|
|
|
|
to = &items[in[i].swap_to];
|
|
|
|
}
|
|
|
|
|
|
|
|
ZPL_ASSERT(from && to);
|
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
uint16_t to_id = item_find(to->kind);
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
if (to == from) {
|
|
|
|
// NOTE(zaklaus): do nothing
|
|
|
|
} else if (to->kind == from->kind && to->quantity > 0) {
|
|
|
|
uint32_t swapped_count = from->quantity;
|
|
|
|
if (in[i].sprint) {
|
|
|
|
swapped_count /= 2;
|
|
|
|
} else if (in[i].ctrl) {
|
|
|
|
swapped_count = 1;
|
|
|
|
}
|
|
|
|
swapped_count = zpl_clamp(swapped_count, 0, item_max_quantity(to_id) - to->quantity);
|
|
|
|
to->quantity += swapped_count;
|
|
|
|
from->quantity -= swapped_count;
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
if (swapped_count == 0) {
|
|
|
|
ItemDrop tmp = *to;
|
|
|
|
*to = *from;
|
|
|
|
*from = tmp;
|
|
|
|
}
|
|
|
|
} else if ((in[i].ctrl || in[i].sprint) && to->quantity == 0 && from->quantity > 0) {
|
|
|
|
// NOTE(zaklaus): item split
|
|
|
|
uint32_t split_count = from->quantity / 2;
|
|
|
|
if (in[i].ctrl) {
|
|
|
|
split_count = 1;
|
|
|
|
}
|
|
|
|
to->quantity = split_count;
|
|
|
|
from->quantity -= split_count;
|
|
|
|
to->kind = from->kind;
|
|
|
|
} else {
|
|
|
|
ItemDrop tmp = *to;
|
|
|
|
*to = *from;
|
|
|
|
*from = tmp;
|
|
|
|
}
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
in[i].swap = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void UseItem(ecs_iter_t *it) {
|
2022-07-31 14:34:47 +00:00
|
|
|
Input *in = ecs_field(it, Input, 1);
|
|
|
|
Position *p = ecs_field(it, Position, 2);
|
|
|
|
Inventory *inv = ecs_field(it, Inventory, 3);
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
for (int i = 0; i < it->count; i++) {
|
2021-11-01 17:35:33 +00:00
|
|
|
if (!in[i].use && !in[i].num_placements) continue;
|
2022-08-09 14:46:23 +00:00
|
|
|
|
|
|
|
if (in[i].storage_action){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-08-30 15:50:05 +00:00
|
|
|
ItemDrop *item = &inv[i].items[in[i].selected_item];
|
2022-08-11 10:41:36 +00:00
|
|
|
uint16_t item_id = 0;
|
|
|
|
item_usage usage = UKIND_DELETE;
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2022-08-11 10:41:36 +00:00
|
|
|
if (!in[i].deletion_mode){
|
|
|
|
item_id = item_find(item->kind);
|
|
|
|
usage = item_get_usage(item_id);
|
|
|
|
if (!item || item->quantity <= 0) continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!in[i].use && usage == UKIND_DELETE){
|
|
|
|
for (size_t j = 0; j < in[i].num_placements; j++) {
|
|
|
|
world_chunk_destroy_block(in[i].placements_x[j], in[i].placements_y[j], true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (in[i].use && usage > UKIND_END_PLACE)
|
2021-11-02 17:58:55 +00:00
|
|
|
item_use(it->world, item, p[i], 0);
|
2021-11-01 17:35:33 +00:00
|
|
|
else if (in[i].num_placements > 0 && usage < UKIND_END_PLACE) {
|
2021-11-02 17:58:55 +00:00
|
|
|
asset_id ofs = 0;
|
|
|
|
if (item_get_place_directional(item_id) && in[i].num_placements >= 2) {
|
|
|
|
float p1x = in[i].placements_x[0];
|
|
|
|
float p1y = in[i].placements_y[0];
|
|
|
|
float p2x = in[i].placements_x[1];
|
|
|
|
float p2y = in[i].placements_y[1];
|
2021-11-03 14:31:10 +00:00
|
|
|
float sx = zpl_sign0(p2x-p1x);
|
|
|
|
float sy = zpl_sign0(p2y-p1y);
|
2021-11-02 17:58:55 +00:00
|
|
|
ofs = (sx < 0.0f) ? 1 : 2;
|
|
|
|
if (sx == 0.0f) {
|
|
|
|
ofs = (sy < 0.0f) ? 3 : 4;
|
|
|
|
}
|
|
|
|
} else if(item_get_place_directional(item_id)) {
|
|
|
|
// NOTE(zaklaus): ensure we pick the first variant
|
|
|
|
ofs = 1;
|
|
|
|
}
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-11-01 17:35:33 +00:00
|
|
|
for (size_t j = 0; j < in[i].num_placements; j++) {
|
|
|
|
Position pos = {.x = in[i].placements_x[j], .y = in[i].placements_y[j]};
|
2021-11-02 17:58:55 +00:00
|
|
|
item_use(it->world, item, pos, ofs);
|
2021-11-01 17:35:33 +00:00
|
|
|
}
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2021-11-02 09:22:04 +00:00
|
|
|
in[i].num_placements = 0;
|
2021-11-01 17:35:33 +00:00
|
|
|
}
|
2022-08-09 14:46:23 +00:00
|
|
|
|
2022-08-01 09:19:52 +00:00
|
|
|
entity_wake(it->entities[i]);
|
2021-08-30 15:50:05 +00:00
|
|
|
}
|
2022-07-31 14:34:47 +00:00
|
|
|
}
|
2022-08-09 14:46:23 +00:00
|
|
|
|
|
|
|
void InspectContainers(ecs_iter_t *it) {
|
|
|
|
Input *in = ecs_field(it, Input, 1);
|
|
|
|
|
|
|
|
for (int i = 0; i < it->count; ++i) {
|
|
|
|
if (!in[i].pick) continue;
|
2022-08-09 15:54:00 +00:00
|
|
|
|
|
|
|
if ((in[i].sel_ent && ecs_get(it->world, in[i].sel_ent, ItemContainer)) || !in[i].sel_ent)
|
|
|
|
in[i].storage_ent = in[i].sel_ent;
|
2022-08-09 14:46:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HarvestIntoContainers(ecs_iter_t *it) {
|
|
|
|
ItemContainer *in = ecs_field(it, ItemContainer, 1);
|
|
|
|
Position *p = ecs_field(it, Position, 2);
|
|
|
|
|
|
|
|
for (int i = 0; i < it->count; ++i) {
|
|
|
|
// NOTE(zaklaus): find any item
|
|
|
|
size_t ents_count;
|
2022-08-09 16:11:02 +00:00
|
|
|
int64_t *ents = world_chunk_query_entities(it->entities[i], &ents_count, 0);
|
2022-08-09 14:46:23 +00:00
|
|
|
|
|
|
|
for (size_t j = 0; j < ents_count; j++) {
|
|
|
|
ItemDrop *drop = 0;
|
|
|
|
if ((drop = ecs_get_mut_if(it->world, ents[j], ItemDrop))) {
|
|
|
|
const Position *p2 = ecs_get(it->world, ents[j], Position);
|
|
|
|
|
|
|
|
float dx = p2->x - p[i].x;
|
|
|
|
float dy = p2->y - p[i].y;
|
|
|
|
float range = zpl_sqrt(dx*dx + dy*dy);
|
|
|
|
if (range <= ITEM_PICK_RADIUS) {
|
|
|
|
uint16_t drop_id = item_find(drop->kind);
|
|
|
|
for (size_t k = 0; k < ITEMS_CONTAINER_SIZE; k += 1) {
|
|
|
|
ItemDrop *item = &in->items[k];
|
|
|
|
uint16_t item_id = item_find(item->kind);
|
|
|
|
if (item_id != ASSET_INVALID && (item->quantity == 0 || (item->quantity != 0 && item->kind == drop->kind)) && item->quantity < item_max_quantity(drop_id)) {
|
|
|
|
uint32_t picked_count = zpl_max(0, drop->quantity);
|
|
|
|
picked_count = zpl_clamp(picked_count, 0, item_max_quantity(drop_id) - item->quantity);
|
|
|
|
item->quantity += picked_count;
|
|
|
|
drop->quantity -= picked_count;
|
|
|
|
item->kind = drop->kind;
|
|
|
|
entity_wake(ents[j]);
|
|
|
|
entity_wake(it->entities[i]);
|
|
|
|
|
|
|
|
if (drop->quantity == 0)
|
|
|
|
item_despawn(ents[j]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|