diff options
Diffstat (limited to 'src/map/storage.c')
-rw-r--r-- | src/map/storage.c | 693 |
1 files changed, 693 insertions, 0 deletions
diff --git a/src/map/storage.c b/src/map/storage.c new file mode 100644 index 000000000..b90d2d306 --- /dev/null +++ b/src/map/storage.c @@ -0,0 +1,693 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../common/nullpo.h"
+#include "../common/malloc.h"
+#include "../common/showmsg.h"
+
+#include "storage.h"
+#include "chrif.h"
+#include "itemdb.h"
+#include "clif.h"
+#include "intif.h"
+#include "pc.h"
+#include "guild.h"
+#include "battle.h"
+#include "atcommand.h"
+
+static struct dbt *storage_db;
+static struct dbt *guild_storage_db;
+
+/*==========================================
+ * 倉庫内アイテムソート
+ *------------------------------------------
+ */
+int storage_comp_item(const void *_i1, const void *_i2)
+{
+ struct item *i1 = (struct item *)_i1;
+ struct item *i2 = (struct item *)_i2;
+
+ if (i1->nameid == i2->nameid)
+ return 0;
+ else if (!(i1->nameid) || !(i1->amount))
+ return 1;
+ else if (!(i2->nameid) || !(i2->amount))
+ return -1;
+ return i1->nameid - i2->nameid;
+}
+
+void sortage_sortitem (struct storage *stor)
+{
+ nullpo_retv(stor);
+ qsort(stor->storage_, MAX_STORAGE, sizeof(struct item), storage_comp_item);
+}
+
+void sortage_gsortitem (struct guild_storage* gstor)
+{
+ nullpo_retv(gstor);
+ qsort(gstor->storage_, MAX_GUILD_STORAGE, sizeof(struct item), storage_comp_item);
+}
+
+/*==========================================
+ * 初期化とか
+ *------------------------------------------
+ */
+int do_init_storage(void) // map.c::do_init()から呼ばれる
+{
+ storage_db=db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
+ guild_storage_db=db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
+ return 1;
+}
+void do_final_storage(void) // by [MC Cameri]
+{
+ storage_db->destroy(storage_db,NULL);
+ guild_storage_db->destroy(guild_storage_db,NULL);
+}
+
+
+static int storage_reconnect_sub(DBKey key,void *data,va_list ap)
+{ //Parses storage and saves 'dirty' ones upon reconnect. [Skotlex]
+ int type = va_arg(ap, int);
+ if (type)
+ { //Guild Storage
+ struct guild_storage* stor = (struct guild_storage*) data;
+ if (stor->dirty && stor->storage_status == 0) //Save closed storages.
+ storage_guild_storagesave(0, stor->guild_id);
+ }
+ else
+ { //Account Storage
+ struct storage* stor = (struct storage*) data;
+ if (stor->dirty && stor->storage_status == 0) //Save closed storages.
+ storage_storage_save(stor->account_id);
+ }
+ return 0;
+}
+
+//Function to be invoked upon server reconnection to char. To save all 'dirty' storages [Skotlex
+void do_reconnect_storage(void)
+{
+ storage_db->foreach(storage_db, storage_reconnect_sub, 0);
+ guild_storage_db->foreach(guild_storage_db, storage_reconnect_sub, 1);
+}
+
+static void* create_storage(DBKey key, va_list args) {
+ struct storage *stor;
+ stor = (struct storage *) aCallocA (sizeof(struct storage), 1);
+ stor->account_id = key.i;
+ return stor;
+}
+struct storage *account2storage(int account_id)
+{
+ return idb_ensure(storage_db,account_id,create_storage);
+}
+
+// Just to ask storage, without creation
+struct storage *account2storage2(int account_id)
+{
+ return idb_get(storage_db, account_id);
+}
+
+int storage_delete(int account_id)
+{
+ idb_remove(storage_db,account_id);
+ return 0;
+}
+
+/*==========================================
+ * カプラ倉庫を開く
+ *------------------------------------------
+ */
+int storage_storageopen(struct map_session_data *sd)
+{
+//#ifdef TXT_ONLY
+ struct storage *stor;
+//#endif
+ nullpo_retr(0, sd);
+
+ if(sd->state.finalsave) //Refuse to open storage when you had your last save done.
+ return 1;
+
+ if( pc_can_give_items(pc_isGM(sd)) ) { //check is this GM level is allowed to put items to storage
+ clif_displaymessage(sd->fd, msg_txt(246));
+ return 1;
+ }
+//Storage loading always from sql idea from Komurka [Skotlex] - removed as it opens exploits when server lags.
+//#ifdef TXT_ONLY
+ if((stor = idb_get(storage_db,sd->status.account_id)) != NULL) {
+ if (stor->storage_status == 0 && sd->state.storage_flag == 0) {
+ stor->storage_status = 1;
+ sd->state.storage_flag = 1;
+ clif_storageitemlist(sd,stor);
+ clif_storageequiplist(sd,stor);
+ clif_updatestorageamount(sd,stor);
+ return 0;
+ }
+ } else
+//#endif
+ intif_request_storage(sd->status.account_id);
+
+ return 1;
+}
+
+/*==========================================
+ * カプラ倉庫へアイテム追加
+ *------------------------------------------
+ */
+int storage_additem(struct map_session_data *sd,struct storage *stor,struct item *item_data,int amount)
+{
+ struct item_data *data;
+ int i;
+
+ nullpo_retr(1, sd);
+ nullpo_retr(1, stor);
+ nullpo_retr(1, item_data);
+
+ if(item_data->nameid <= 0 || amount <= 0)
+ return 1;
+ nullpo_retr(1, data = itemdb_search(item_data->nameid));
+
+ if (!itemdb_canstore(item_data->nameid, pc_isGM(sd)))
+ { //Check if item is storable. [Skotlex]
+ clif_displaymessage (sd->fd, msg_txt(264));
+ return 1;
+ }
+
+ i=MAX_STORAGE;
+ if(!itemdb_isequip2(data)){
+ // 装備品ではないので、既所有品なら個数のみ変化させる
+ for(i=0;i<MAX_STORAGE;i++){
+ if( compare_item (&stor->storage_[i], item_data)) {
+ if(stor->storage_[i].amount+amount > MAX_AMOUNT)
+ return 1;
+ stor->storage_[i].amount+=amount;
+ clif_storageitemadded(sd,stor,i,amount);
+ break;
+ }
+ }
+ }
+ if(i>=MAX_STORAGE){
+ // 装備品か未所有品だったので空き欄へ追加
+ for(i=0;i<MAX_STORAGE;i++){
+ if(stor->storage_[i].nameid==0){
+ memcpy(&stor->storage_[i],item_data,sizeof(stor->storage_[0]));
+ stor->storage_[i].amount=amount;
+ stor->storage_amount++;
+ clif_storageitemadded(sd,stor,i,amount);
+ clif_updatestorageamount(sd,stor);
+ break;
+ }
+ }
+ if(i>=MAX_STORAGE)
+ return 1;
+ }
+
+ stor->dirty = 1;
+ return 0;
+}
+/*==========================================
+ * カプラ倉庫アイテムを減らす
+ *------------------------------------------
+ */
+int storage_delitem(struct map_session_data *sd,struct storage *stor,int n,int amount)
+{
+ nullpo_retr(1, sd);
+ nullpo_retr(1, stor);
+
+ if(stor->storage_[n].nameid==0 || stor->storage_[n].amount<amount)
+ return 1;
+
+ stor->storage_[n].amount-=amount;
+ if(stor->storage_[n].amount==0){
+ memset(&stor->storage_[n],0,sizeof(stor->storage_[0]));
+ stor->storage_amount--;
+ clif_updatestorageamount(sd,stor);
+ }
+ clif_storageitemremoved(sd,n,amount);
+
+ stor->dirty = 1;
+ return 0;
+}
+/*==========================================
+ * カプラ倉庫へ入れる
+ *------------------------------------------
+ */
+int storage_storageadd(struct map_session_data *sd,int index,int amount)
+{
+ struct storage *stor;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor=account2storage2(sd->status.account_id));
+
+ if( (stor->storage_amount <= MAX_STORAGE) && (stor->storage_status == 1) ) { // storage not full & storage open
+ if(index>=0 && index<MAX_INVENTORY) { // valid index
+ if( (amount <= sd->status.inventory[index].amount) && (amount > 0) ) { //valid amount
+// log_tostorage(sd, index, 0);
+ if(storage_additem(sd,stor,&sd->status.inventory[index],amount)==0)
+ // remove item from inventory
+ pc_delitem(sd,index,amount,0);
+ } // valid amount
+ }// valid index
+ }// storage not full & storage open
+
+ return 0;
+}
+
+/*==========================================
+ * カプラ倉庫から出す
+ *------------------------------------------
+ */
+int storage_storageget(struct map_session_data *sd,int index,int amount)
+{
+ struct storage *stor;
+ int flag;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor=account2storage2(sd->status.account_id));
+
+ if(stor->storage_status == 1) { // storage open
+ if(index>=0 && index<MAX_STORAGE) { // valid index
+ if( (amount <= stor->storage_[index].amount) && (amount > 0) ) { //valid amount
+ if((flag = pc_additem(sd,&stor->storage_[index],amount)) == 0)
+ storage_delitem(sd,stor,index,amount);
+ //else //taken out because it can dupe items if the above fails somehow :) [Kevin]
+ //clif_additem(sd,0,0,flag);
+// log_fromstorage(sd, index, 0);
+ } // valid amount
+ }// valid index
+ }// storage open
+
+ return 0;
+}
+/*==========================================
+ * カプラ倉庫へカートから入れる
+ *------------------------------------------
+ */
+int storage_storageaddfromcart(struct map_session_data *sd,int index,int amount)
+{
+ struct storage *stor;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor=account2storage2(sd->status.account_id));
+
+ if( (stor->storage_amount <= MAX_STORAGE) && (stor->storage_status == 1) ) { // storage not full & storage open
+ if(index>=0 && index<MAX_INVENTORY) { // valid index
+ if( (amount <= sd->status.cart[index].amount) && (amount > 0) ) { //valid amount
+ if(storage_additem(sd,stor,&sd->status.cart[index],amount)==0)
+ pc_cart_delitem(sd,index,amount,0);
+ } // valid amount
+ }// valid index
+ }// storage not full & storage open
+
+ return 0;
+}
+
+/*==========================================
+ * カプラ倉庫からカートへ出す
+ *------------------------------------------
+ */
+int storage_storagegettocart(struct map_session_data *sd,int index,int amount)
+{
+ struct storage *stor;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor=account2storage2(sd->status.account_id));
+
+ if(stor->storage_status == 1) { // storage open
+ if(index>=0 && index<MAX_STORAGE) { // valid index
+ if( (amount <= stor->storage_[index].amount) && (amount > 0) ) { //valid amount
+ if(pc_cart_additem(sd,&stor->storage_[index],amount)==0){
+ storage_delitem(sd,stor,index,amount);
+ }
+ } // valid amount
+ }// valid index
+ }// storage open
+
+ return 0;
+}
+
+
+/*==========================================
+ * Modified By Valaris to save upon closing [massdriller]
+ *------------------------------------------
+ */
+int storage_storageclose(struct map_session_data *sd)
+{
+ struct storage *stor;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor=account2storage2(sd->status.account_id));
+
+ clif_storageclose(sd);
+ chrif_save(sd, 0); //This will invoke the storage save function as well. [Skotlex]
+
+ stor->storage_status=0;
+ sd->state.storage_flag = 0;
+ return 0;
+}
+
+/*==========================================
+ * ログアウト時開いているカプラ倉庫の保存
+ *------------------------------------------
+ */
+int storage_storage_quit(struct map_session_data *sd, int flag)
+{
+ struct storage *stor;
+
+ nullpo_retr(0, sd);
+
+ stor = account2storage2(sd->status.account_id);
+ if(stor) {
+ chrif_save(sd, flag); //Invokes the storage saving as well.
+ stor->storage_status = 0;
+ sd->state.storage_flag = 0;
+ }
+
+ return 0;
+}
+
+void storage_storage_dirty(struct map_session_data *sd)
+{
+ struct storage *stor;
+
+ stor=account2storage2(sd->status.account_id);
+
+ if(stor)
+ stor->dirty = 1;
+}
+
+int storage_storage_save(int account_id)
+{
+ struct storage *stor;
+
+ stor=account2storage2(account_id);
+ if(stor && stor->dirty)
+ {
+ intif_send_storage(stor);
+ return 1;
+ }
+
+ return 0;
+}
+
+//Ack from Char-server indicating the storage was saved. [Skotlex]
+int storage_storage_saved(int account_id)
+{
+ struct storage *stor;
+
+ if((stor=account2storage2(account_id)) != NULL)
+ { //Only mark it clean if it's not in use. [Skotlex]
+ if (stor->dirty && stor->storage_status == 0)
+ {
+ stor->dirty = 0;
+ sortage_sortitem(stor);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static void* create_guildstorage(DBKey key, va_list args) {
+ struct guild_storage *gs = NULL;
+ gs = (struct guild_storage *) aCallocA(sizeof(struct guild_storage), 1);
+ gs->guild_id=key.i;
+ return gs;
+}
+struct guild_storage *guild2storage(int guild_id)
+{
+ struct guild_storage *gs = NULL;
+ if(guild_search(guild_id) != NULL)
+ gs=(struct guild_storage *) idb_ensure(guild_storage_db,guild_id,create_guildstorage);
+ return gs;
+}
+
+struct guild_storage *guild2storage2(int guild_id)
+{ //For just locating a storage without creating one. [Skotlex]
+ return idb_get(guild_storage_db,guild_id);
+}
+
+int guild_storage_delete(int guild_id)
+{
+ idb_remove(guild_storage_db,guild_id);
+ return 0;
+}
+
+int storage_guild_storageopen(struct map_session_data *sd)
+{
+ struct guild_storage *gstor;
+
+ nullpo_retr(0, sd);
+
+ if(sd->status.guild_id <= 0)
+ return 2;
+
+ if(sd->state.finalsave) //Refuse to open storage when you had your last save done.
+ return 1;
+
+ if( pc_can_give_items(pc_isGM(sd)) ) { //check is this GM level can open guild storage and store items [Lupus]
+ clif_displaymessage(sd->fd, msg_txt(246));
+ return 1;
+ }
+
+ if((gstor = guild2storage2(sd->status.guild_id)) != NULL) {
+ if(gstor->storage_status)
+ return 1;
+ if(sd->state.storage_flag)
+ return 1; //Can't open both storages at a time.
+ gstor->storage_status = 1;
+ sd->state.storage_flag = 2;
+ clif_guildstorageitemlist(sd,gstor);
+ clif_guildstorageequiplist(sd,gstor);
+ clif_updateguildstorageamount(sd,gstor);
+ return 0;
+ }
+ else {
+ gstor = guild2storage(sd->status.guild_id);
+ gstor->storage_status = 1;
+ intif_request_guild_storage(sd->status.account_id,sd->status.guild_id);
+ }
+
+ return 0;
+}
+
+int guild_storage_additem(struct map_session_data *sd,struct guild_storage *stor,struct item *item_data,int amount)
+{
+ struct item_data *data;
+ int i;
+
+ nullpo_retr(1, sd);
+ nullpo_retr(1, stor);
+ nullpo_retr(1, item_data);
+ nullpo_retr(1, data = itemdb_search(item_data->nameid));
+
+ if(item_data->nameid <= 0 || amount <= 0)
+ return 1;
+
+ if (!itemdb_canguildstore(item_data->nameid, pc_isGM(sd)))
+ { //Check if item is storable. [Skotlex]
+ clif_displaymessage (sd->fd, msg_txt(264));
+ return 1;
+ }
+
+ i=MAX_GUILD_STORAGE;
+ if(!itemdb_isequip2(data)){
+ // 装備品ではないので、既所有品なら個数のみ変化させる
+ for(i=0;i<MAX_GUILD_STORAGE;i++){
+ if(compare_item(&stor->storage_[i], item_data)) {
+ if(stor->storage_[i].amount+amount > MAX_AMOUNT)
+ return 1;
+ stor->storage_[i].amount+=amount;
+ clif_guildstorageitemadded(sd,stor,i,amount);
+ break;
+ }
+ }
+ }
+ if(i>=MAX_GUILD_STORAGE){
+ // 装備品か未所有品だったので空き欄へ追加
+ for(i=0;i<MAX_GUILD_STORAGE;i++){
+ if(stor->storage_[i].nameid==0){
+ memcpy(&stor->storage_[i],item_data,sizeof(stor->storage_[0]));
+ stor->storage_[i].amount=amount;
+ stor->storage_amount++;
+ clif_guildstorageitemadded(sd,stor,i,amount);
+ clif_updateguildstorageamount(sd,stor);
+ break;
+ }
+ }
+ if(i>=MAX_GUILD_STORAGE)
+ return 1;
+ }
+ stor->dirty = 1;
+ return 0;
+}
+
+int guild_storage_delitem(struct map_session_data *sd,struct guild_storage *stor,int n,int amount)
+{
+ nullpo_retr(1, sd);
+ nullpo_retr(1, stor);
+
+ if(stor->storage_[n].nameid==0 || stor->storage_[n].amount<amount)
+ return 1;
+
+ stor->storage_[n].amount-=amount;
+ if(stor->storage_[n].amount==0){
+ memset(&stor->storage_[n],0,sizeof(stor->storage_[0]));
+ stor->storage_amount--;
+ clif_updateguildstorageamount(sd,stor);
+ }
+ clif_storageitemremoved(sd,n,amount);
+ stor->dirty = 1;
+ return 0;
+}
+
+int storage_guild_storageadd(struct map_session_data *sd,int index,int amount)
+{
+ struct guild_storage *stor;
+
+ nullpo_retr(0, sd);
+
+ if((stor=guild2storage2(sd->status.guild_id)) != NULL) {
+ if( (stor->storage_amount <= MAX_GUILD_STORAGE) && (stor->storage_status == 1) ) { // storage not full & storage open
+ if(index>=0 && index<MAX_INVENTORY) { // valid index
+ if( (amount <= sd->status.inventory[index].amount) && (amount > 0) ) { //valid amount
+// log_tostorage(sd, index, 1);
+ if(guild_storage_additem(sd,stor,&sd->status.inventory[index],amount)==0)
+ // remove item from inventory
+ pc_delitem(sd,index,amount,0);
+ } // valid amount
+ }// valid index
+ }// storage not full & storage open
+ }
+
+ return 0;
+}
+
+int storage_guild_storageget(struct map_session_data *sd,int index,int amount)
+{
+ struct guild_storage *stor;
+ int flag;
+
+ nullpo_retr(0, sd);
+
+ if((stor=guild2storage2(sd->status.guild_id)) != NULL) {
+ if(stor->storage_status == 1) { // storage open
+ if(index>=0 && index<MAX_GUILD_STORAGE) { // valid index
+ if( (amount <= stor->storage_[index].amount) && (amount > 0) ) { //valid amount
+ if((flag = pc_additem(sd,&stor->storage_[index],amount)) == 0)
+ guild_storage_delitem(sd,stor,index,amount);
+ else
+ clif_additem(sd,0,0,flag);
+// log_fromstorage(sd, index, 1);
+ } // valid amount
+ }// valid index
+ }// storage open
+ }
+
+ return 0;
+}
+
+int storage_guild_storageaddfromcart(struct map_session_data *sd,int index,int amount)
+{
+ struct guild_storage *stor;
+
+ nullpo_retr(0, sd);
+
+ if((stor=guild2storage2(sd->status.guild_id)) != NULL) {
+ if( (stor->storage_amount <= MAX_GUILD_STORAGE) && (stor->storage_status == 1) ) { // storage not full & storage open
+ if(index>=0 && index<MAX_INVENTORY) { // valid index
+ if( (amount <= sd->status.cart[index].amount) && (amount > 0) ) { //valid amount
+ if(guild_storage_additem(sd,stor,&sd->status.cart[index],amount)==0)
+ pc_cart_delitem(sd,index,amount,0);
+ } // valid amount
+ }// valid index
+ }// storage not full & storage open
+ }
+
+ return 0;
+}
+
+int storage_guild_storagegettocart(struct map_session_data *sd,int index,int amount)
+{
+ struct guild_storage *stor;
+
+ nullpo_retr(0, sd);
+
+ if((stor=guild2storage2(sd->status.guild_id)) != NULL) {
+ if(stor->storage_status == 1) { // storage open
+ if(index>=0 && index<MAX_GUILD_STORAGE) { // valid index
+ if( (amount <= stor->storage_[index].amount) && (amount > 0) ) { //valid amount
+ if(pc_cart_additem(sd,&stor->storage_[index],amount)==0){
+ guild_storage_delitem(sd,stor,index,amount);
+ }
+ } // valid amount
+ }// valid index
+ }// storage open
+ }
+
+ return 0;
+}
+
+int storage_guild_storagesave(int account_id, int guild_id)
+{
+ struct guild_storage *stor = guild2storage2(guild_id);
+
+ if(stor && stor->dirty)
+ {
+ intif_send_guild_storage(account_id,stor);
+ return 1;
+ }
+ return 0;
+}
+
+int storage_guild_storagesaved(int account_id, int guild_id)
+{
+ struct guild_storage *stor;
+
+ if((stor=guild2storage2(guild_id)) != NULL) {
+ if (stor->dirty && stor->storage_status == 0)
+ { //Storage has been correctly saved.
+ stor->dirty = 0;
+ sortage_gsortitem(stor);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int storage_guild_storageclose(struct map_session_data *sd)
+{
+ struct guild_storage *stor;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor=guild2storage2(sd->status.guild_id));
+
+ clif_storageclose(sd);
+ chrif_save(sd, 0); //This one also saves the storage. [Skotlex]
+
+ stor->storage_status=0;
+ sd->state.storage_flag = 0;
+
+ return 0;
+}
+
+int storage_guild_storage_quit(struct map_session_data *sd,int flag)
+{
+ struct guild_storage *stor;
+
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor=guild2storage2(sd->status.guild_id));
+
+ sd->state.storage_flag = 0;
+ stor->storage_status = 0;
+
+ chrif_save(sd,flag);
+ if(!flag) //Only during a guild break flag is 1.
+ storage_guild_storagesave(sd->status.account_id,sd->status.guild_id);
+ else //When the guild was broken, close the storage of he who has it open.
+ clif_storageclose(sd);
+
+ return 0;
+}
|