basin/src/inventory.c

230 lines
7.4 KiB
C
Raw Normal View History

2016-06-24 04:41:14 +00:00
/*
* inventory.c
*
* Created on: Mar 25, 2016
* Author: root
*/
2016-12-30 03:18:53 +00:00
#include "packet.h"
#include <basin/network.h>
#include <basin/globals.h>
#include <basin/item.h>
#include <basin/game.h>
#include <basin/queue.h>
#include <basin/player.h>
#include <basin/smelting.h>
#include <basin/nbt.h>
#include <basin/tileentity.h>
#include <basin/inventory.h>
#include <avuna/hash.h>
2016-06-24 04:41:14 +00:00
#include <string.h>
#include <math.h>
2016-12-30 03:18:53 +00:00
#include <stdint.h>
2017-01-03 19:18:52 +00:00
#include <unistd.h>
2016-06-24 04:41:14 +00:00
2016-12-25 04:59:02 +00:00
void newInventory(struct inventory* inv, int type, int id, int slots) {
2016-06-24 04:41:14 +00:00
inv->title = NULL;
2016-12-25 04:59:02 +00:00
inv->slot_count = slots;
inv->slots = xcalloc(sizeof(struct slot*) * inv->slot_count);
2016-06-24 04:41:14 +00:00
inv->props = NULL;
inv->prop_count = 0;
inv->type = type;
inv->windowID = id;
2017-01-03 19:18:52 +00:00
inv->players = new_hashmap(1, 1);
2016-12-26 08:31:26 +00:00
inv->dragSlot = xcalloc(2 * inv->slot_count);
inv->dragSlot_count = 0;
inv->te = NULL;
2017-01-03 19:18:52 +00:00
pthread_mutex_init(&inv->mut, NULL);
}
2017-01-03 19:18:52 +00:00
void setSlot(struct player* player, struct inventory* inv, int index, struct slot* slot, int broadcast, int frx) {
if (inv == NULL) return;
if (inv->type != INVTYPE_PLAYERINVENTORY && player != NULL && index >= inv->slot_count) {
index -= inv->slot_count;
index += 9;
inv = player->inventory;
}
if (index >= inv->slot_count || index < 0) return;
2017-01-03 19:18:52 +00:00
if (inv->slots[index] != slot && inv->slots[index] != NULL && frx) {
freeSlot(inv->slots[index]);
xfree(inv->slots[index]);
}
if (slot == NULL || slot->item == -1) inv->slots[index] = NULL;
else if (slot == inv->slots[index]) ;
else {
inv->slots[index] = xmalloc(sizeof(struct slot));
duplicateSlot(slot, inv->slots[index]);
}
onInventoryUpdate(player, inv, index);
if (broadcast) {
BEGIN_BROADCAST(inv->players)
struct packet* pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_SETSLOT;
pkt->data.play_client.setslot.window_id = inv->windowID;
pkt->data.play_client.setslot.slot = index;
duplicateSlot(inv->slots[index], &pkt->data.play_client.setslot.slot_data);
add_queue(bc_player->outgoingPacket, pkt);
2017-01-01 09:39:37 +00:00
END_BROADCAST(inv->players)
} else {
BEGIN_BROADCAST_EXCEPT(inv->players, player)
struct packet* pkt = xmalloc(sizeof(struct packet));
pkt->id = PKT_PLAY_CLIENT_SETSLOT;
pkt->data.play_client.setslot.window_id = inv->windowID;
pkt->data.play_client.setslot.slot = index;
duplicateSlot(inv->slots[index], &pkt->data.play_client.setslot.slot_data);
add_queue(bc_player->outgoingPacket, pkt);
2017-01-01 09:39:37 +00:00
END_BROADCAST(inv->players)
}
2016-12-30 03:18:53 +00:00
//printf("set %i = %i broadcast=%i pc=%i\n", index, slot == NULL ? -1 : slot->item, broadcast, inv->players->count);
}
struct slot* getSlot(struct player* player, struct inventory* inv, int index) {
if (inv == NULL) return NULL;
if (inv->type != INVTYPE_PLAYERINVENTORY && player != NULL && index >= inv->slot_count) {
index -= inv->slot_count;
index += 9;
inv = player->inventory;
}
if (index >= inv->slot_count || index < 0) return NULL;
return inv->slots[index];
2016-06-24 04:41:14 +00:00
}
2016-12-27 04:47:45 +00:00
void copyInventory(struct slot** from, struct slot** to, int size) {
for (int i = 0; i < size; i++) {
if (to[i] != NULL) {
freeSlot(to[i]);
xfree(to[i]);
to[i] = NULL;
}
if (from[i] != NULL) {
to[i] = xmalloc(sizeof(struct slot*));
duplicateSlot(from[i], to[i]);
}
}
}
2016-06-24 04:41:14 +00:00
void _freeInventorySlots(struct inventory* inv) {
if (inv->slots != NULL) {
for (size_t i = 0; i < inv->slot_count; i++) {
if (inv->slots[i] == NULL) continue;
2016-12-26 08:31:26 +00:00
freeSlot(inv->slots[i]);
2016-12-25 04:59:02 +00:00
xfree(inv->slots[i]);
2016-06-24 04:41:14 +00:00
}
2016-12-25 04:59:02 +00:00
xfree(inv->slots);
2016-06-24 04:41:14 +00:00
inv->slots = NULL;
}
}
void freeInventory(struct inventory* inv) {
2016-12-25 04:59:02 +00:00
if (inv->title != NULL) xfree(inv->title);
2016-06-24 04:41:14 +00:00
if (inv->props != NULL) {
for (size_t i = 0; i < inv->prop_count; i++) {
2016-12-25 04:59:02 +00:00
xfree(inv->props[i]);
2016-06-24 04:41:14 +00:00
}
2016-12-25 04:59:02 +00:00
xfree(inv->props);
2016-06-24 04:41:14 +00:00
}
2017-01-01 09:39:37 +00:00
del_hashmap(inv->players);
2016-06-24 04:41:14 +00:00
_freeInventorySlots(inv);
2016-12-26 08:31:26 +00:00
xfree(inv->dragSlot);
2017-01-03 19:18:52 +00:00
pthread_mutex_destroy(&inv->mut);
2016-12-26 08:31:26 +00:00
}
void freeSlot(struct slot* slot) {
if (slot->nbt != NULL) {
freeNBT(slot->nbt);
xfree(slot->nbt);
}
2016-06-24 04:41:14 +00:00
}
int validItemForSlot(int invtype, int si, struct slot* slot) {
2016-06-24 04:41:14 +00:00
if (invtype == INVTYPE_PLAYERINVENTORY) {
if (si == 0) return 0;
if (si == 5) return getItemInfo(slot->item)->armorType == ARMOR_HELMET;
else if (si == 6) return getItemInfo(slot->item)->armorType == ARMOR_CHESTPLATE;
else if (si == 7) return getItemInfo(slot->item)->armorType == ARMOR_LEGGINGS;
else if (si == 8) return getItemInfo(slot->item)->armorType == ARMOR_BOOTS;
} else if (invtype == INVTYPE_WORKBENCH) {
if (si == 0) return 0;
} else if (invtype == INVTYPE_FURNACE) {
if (si == 2) return 0;
else if (si == 1) return getSmeltingFuelBurnTime(slot) > 0;
2016-06-24 04:41:14 +00:00
}
return 1;
}
2016-12-26 08:31:26 +00:00
int itemsStackable(struct slot* s1, struct slot* s2) {
return s1 != NULL && s2 != NULL && s1->item != -1 && s2->item != -1 && s1->item == s2->item && s1->damage == s2->damage && (s1->nbt == NULL || s1->nbt->id == 0) && (s2->nbt == NULL || s2->nbt->id == 0);
}
2016-12-27 04:47:45 +00:00
int itemsStackable2(struct slot* s1, struct slot* s2) {
return s1 != NULL && s2 != NULL && s1->item != -1 && s2->item != -1 && s1->item == s2->item && (s1->damage == s2->damage || s1->damage == -1 || s2->damage == -1) && (s1->nbt == NULL || s1->nbt->id == 0) && (s2->nbt == NULL || s2->nbt->id == 0);
}
void swapSlots(struct player* player, struct inventory* inv, int i1, int i2, int broadcast) {
struct slot* s1 = getSlot(player, inv, i1);
struct slot* s2 = getSlot(player, inv, i2);
if (!validItemForSlot(inv->type, i2, s1) || !validItemForSlot(inv->type, i1, s2)) return;
setSlot(player, inv, i1, s2, broadcast, 0);
setSlot(player, inv, i2, s1, broadcast, 0);
2016-12-26 08:31:26 +00:00
}
2016-06-24 04:41:14 +00:00
int maxStackSize(struct slot* slot) {
2016-12-29 04:51:14 +00:00
struct item_info* ii = getItemInfo(slot->item);
return ii == NULL ? 64 : ii->maxStackSize;
2016-06-24 04:41:14 +00:00
}
int addInventoryItem_PI(struct player* player, struct inventory* inv, struct slot* slot, int broadcast) {
int r = addInventoryItem(player, inv, slot, 36, 45, broadcast);
if (r > 0) r = addInventoryItem(player, inv, slot, 9, 36, broadcast);
2016-12-26 08:31:26 +00:00
return r;
}
int addInventoryItem(struct player* player, struct inventory* inv, struct slot* slot, int start, int end, int broadcast) {
size_t cap = inv->slot_count;
if (inv->type != INVTYPE_PLAYERINVENTORY && player != NULL) cap += 36;
if (start < 0 || end < 0 || start > cap || end > cap || slot == NULL) return -1;
2016-12-26 08:31:26 +00:00
int mss = maxStackSize(slot);
2016-12-27 04:47:45 +00:00
if (mss > 1) for (size_t i = start; start < end ? (i < end) : (i > end); start < end ? i++ : i--) {
struct slot* invi = getSlot(player, inv, i);
if (itemsStackable(invi, slot) && invi->itemCount < mss) {
int t = (invi->itemCount + slot->itemCount);
invi->itemCount = t <= mss ? t : mss;
int s = t - invi->itemCount;
2016-12-26 08:31:26 +00:00
if (s <= 0) {
slot = NULL;
} else slot->itemCount -= s;
setSlot(player, inv, i, invi, broadcast, 1);
2016-12-26 08:31:26 +00:00
}
}
2016-12-27 04:47:45 +00:00
for (size_t i = start; start < end ? (i < end) : (i > end); start < end ? i++ : i--) {
struct slot* invi = getSlot(player, inv, i);
if (invi == NULL) {
invi = xmalloc(sizeof(struct slot));
duplicateSlot(slot, invi);
setSlot(player, inv, i, invi, broadcast, 1);
2016-12-26 08:31:26 +00:00
return 0;
}
}
return slot == NULL ? 0 : slot->itemCount;
}
2016-06-24 04:41:14 +00:00
void setInventoryProperty(struct inventory* inv, int16_t name, int16_t value) {
if (inv->props != NULL) {
for (size_t i = 0; i < inv->prop_count; i++) {
if (inv->props[i][0] == name) {
inv->props[i][1] = value;
return;
}
}
2016-12-25 04:59:02 +00:00
inv->props = xrealloc(inv->props, sizeof(int16_t*) * (inv->prop_count + 1));
2016-06-24 04:41:14 +00:00
} else {
2016-12-25 04:59:02 +00:00
inv->props = xmalloc(sizeof(int16_t*));
2016-06-24 04:41:14 +00:00
inv->prop_count = 0;
}
2016-12-25 04:59:02 +00:00
int16_t* dm = xmalloc(sizeof(int16_t) * 2);
2016-06-24 04:41:14 +00:00
dm[0] = name;
dm[1] = value;
inv->props[inv->prop_count++] = dm;
}