Changed Guild/Party Bound Item Retrieval Methods:

* Bug Fixes bug:9338
* Now resend the list to map-server from char/inter-server to avoid "weird" item allocation on guild storage. Example, previously you will meet stacked item like GUID does, but it shouldn't!
* Also will check the maximum amount that can be store in guild store. If guild storage is full (the slots or item stack limit is reach) the rest value/item will be dropped.
* Account of kicked guild member won't be kicked from server anymore if the player idle on character select window (just prevents player to login when retriving items are in progress)
* Delete guild bound items from guild master when guild is disbanded! Previously, the bound type just changed to NONE. Also for party bound item.
* If kicked guild/party member is trading bound item when be kicked, the trade will be canceled!
* If the guild member is being kicked when open guild storage, storage will be closed first waiting for next item retrieval.
* Now when guild storage is opened, storage_status (changed the var to 'opened') will be used to hold char_id who opens it.
Misc:
* Cleanup guild storage prefix functions, changed them to "gstorage_*"
* Added `picklog` type 'B' for logging deleted bound item because of kicked from guild/party.
* Updated documentation for new used packet 0x3857

NOTE: Please import upgrade-20150103_log.sql
Signed-off-by: Cydh Ramdh <house.bad@gmail.com>
This commit is contained in:
Cydh Ramdh 2015-01-03 20:37:38 +07:00
parent d98f99b2de
commit 022d72891e
27 changed files with 573 additions and 407 deletions

View File

@ -2021,6 +2021,20 @@ Currently the max packet size is 0xFFFF (see 'WFIFOSET()' in 'src/common/socket.
desc:
- Acknowledge the good deletion of the bound item
0x3857
Type: IZ
Structure: <cmd>.W <size>.W <count>.W <guild_id>.W { <items>.?B }*MAX_INVENTORY
index: 0,2,4,6,8
len: variable: 8+items
parameter:
- cmd : packet identification (0x3856)
- size
- count : number of item retrieved
- guild_id
- items: retreived guild bound items
desc:
- Ask map-server to process the retreived guild bound items from expelled member
0x3860
Type: IZ
Structure: <cmd>.W <size>.W <char_id>.L <quest>.?B

View File

@ -0,0 +1 @@
ALTER TABLE `picklog` MODIFY `type` ENUM('M','P','L','T','V','S','N','C','A','R','G','E','B','O','I','X','D','U','$') NOT NULL DEFAULT 'S';

View File

@ -1809,7 +1809,24 @@ void char_disconnect_player(uint32 account_id)
set_eof(i);
}
/**
* Set 'flag' value of char_session_data
* @param account_id
* @param value
* @param set True: set the value by using '|= val', False: unset the value by using '&= ~val'
**/
void char_set_session_flag_(int account_id, int val, bool set) {
int i;
struct char_session_data* sd;
ARR_FIND(0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == account_id);
if (i < fd_max) {
if (set)
sd->flag |= val;
else
sd->flag &= ~val;
}
}
void char_auth_ok(int fd, struct char_session_data *sd) {
struct online_char_data* character;

View File

@ -199,6 +199,7 @@ struct char_session_data {
uint8 isvip;
time_t unban_time[MAX_CHARS];
int charblock_timer;
uint8 flag; // &1 - Retrieving guild bound items
};
@ -263,6 +264,10 @@ int char_make_new_char_sql(struct char_session_data* sd, char* name_, int slot,
int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style);
#endif
void char_set_session_flag_(int account_id, int val, bool set);
#define char_set_session_flag(account_id, val) ( char_set_session_flag_((account_id), (val), true) )
#define char_unset_session_flag(account_id, val) ( char_set_session_flag_((account_id), (val), false) )
//For use in packets that depend on an sd being present [Skotlex]
#define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } }

View File

@ -704,6 +704,15 @@ int chclif_parse_charselect(int fd, struct char_session_data* sd,uint32 ipl){
char_id = atoi(data);
Sql_FreeResult(sql_handle);
// Prevent select a char while retrieving guild bound items
if (sd->flag&1) {
WFIFOHEAD(fd,3);
WFIFOW(fd,0) = 0x6c;
WFIFOB(fd,2) = 0; // rejected from server
WFIFOSET(fd,3);
return 1;
}
/* client doesn't let it get to this point if you're banned, so its a forged packet */
if( sd->found_char[slot] == char_id && sd->unban_time[slot] > time(NULL) ) {
WFIFOHEAD(fd,3);

View File

@ -229,47 +229,81 @@ int mapif_parse_SaveGuildStorage(int fd)
mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 1);
return 0;
}
#ifdef BOUND_ITEMS
int mapif_itembound_ack(int fd, int aid, int guild_id)
/**
* IZ 0x3856 <account_id>.L <guild_id>.W
* Tells map-server if the process if complete, unlock the guild storage
*/
static void mapif_itembound_ack(int fd, int account_id, int guild_id)
{
WFIFOHEAD(fd,8);
WFIFOW(fd,0) = 0x3856;
WFIFOL(fd,2) = aid;
WFIFOL(fd,2) = account_id;
WFIFOW(fd,6) = guild_id;
WFIFOSET(fd,8);
return 0;
char_unset_session_flag(account_id, 1);
}
//------------------------------------------------
//Guild bound items pull for offline characters [Akinari]
//------------------------------------------------
/**
* IZ 0x3857 <size>.W <count>.W <guild_id>.W { <item>.?B }.*MAX_INVENTORY
* Send the retrieved guild bound items to map-server, store them to guild storage.
* By using this method, stackable items will looks how it should be, and overflowed
* item's stack won't disturbs the guild storage table and the leftover items (when
* storage is full) will be discarded.
* @param fd
* @param guild_id
* @param items[]
* @param count
* @author [Cydh]
*/
static void mapif_itembound_store2gstorage(int fd, int guild_id, struct item items[], unsigned short count) {
int size = 8 + sizeof(struct item) * MAX_INVENTORY, i;
WFIFOHEAD(fd, size);
WFIFOW(fd, 0) = 0x3857;
WFIFOW(fd, 2) = size;
WFIFOW(fd, 6) = guild_id;
for (i = 0; i < count && i < MAX_INVENTORY; i++) {
if (!&items[i])
continue;
memcpy(WFIFOP(fd, 8 + (i * sizeof(struct item))), &items[i], sizeof(struct item));
}
WFIFOW(fd, 4) = i;
WFIFOSET(fd, size);
}
/**
* ZI 0x3056 <char_id>.L <account_id>.L <guild_id>.W
* Pulls guild bound items for offline characters
* @author [Akinari]
*/
int mapif_parse_itembound_retrieve(int fd)
{
StringBuf buf;
SqlStmt* stmt;
struct item item;
int j, i = 0, s = 0, bound_qt = 0;
bool found = false;
struct item items[MAX_INVENTORY];
unsigned int bound_item[MAX_INVENTORY] = { 0 };
uint32 char_id = RFIFOL(fd,2);
int aid = RFIFOL(fd,6);
int guild_id = RFIFOW(fd,10);
unsigned short i = 0, count = 0, size = 0;
struct item item, items[MAX_INVENTORY] = { 0 };
int j, guild_id = RFIFOW(fd,10);
uint32 char_id = RFIFOL(fd,2), account_id = RFIFOL(fd,6);
StringBuf_Init(&buf);
// Get bound items from player's inventory
StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`");
for( j = 0; j < MAX_SLOTS; ++j )
StringBuf_Printf(&buf, ", `card%d`", j);
StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'",schema_config.inventory_db,char_id);
StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d' AND `bound` = %d", schema_config.inventory_db,char_id, BOUND_GUILD);
stmt = SqlStmt_Malloc(sql_handle);
if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
|| SQL_ERROR == SqlStmt_Execute(stmt) )
if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) ||
SQL_ERROR == SqlStmt_Execute(stmt) )
{
SqlStmt_ShowDebug(stmt);
SqlStmt_Free(stmt);
StringBuf_Destroy(&buf);
mapif_itembound_ack(fd,aid,guild_id);
mapif_itembound_ack(fd,account_id,guild_id);
return 1;
}
@ -285,83 +319,67 @@ int mapif_parse_itembound_retrieve(int fd)
for( j = 0; j < MAX_SLOTS; ++j )
SqlStmt_BindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) {
if(item.bound == BOUND_GUILD) {
memcpy(&items[i],&item,sizeof(struct item));
i++;
}
}
while( SQL_SUCCESS == SqlStmt_NextRow(stmt) )
memcpy(&items[count++], &item, sizeof(struct item));
Sql_FreeResult(sql_handle);
if(!i) { //No items found - No need to continue
ShowInfo("Found '"CL_WHITE"%d"CL_RESET"' guild bound item(s) from CID = "CL_WHITE"%d"CL_RESET", AID = %d, Guild ID = "CL_WHITE"%d"CL_RESET".\n", count, char_id, account_id, guild_id);
if (!count) { //No items found - No need to continue
StringBuf_Destroy(&buf);
SqlStmt_Free(stmt);
mapif_itembound_ack(fd,aid,guild_id);
return 0;
mapif_itembound_ack(fd,account_id,guild_id);
return 1;
}
//First we delete the character's items
char_set_session_flag(account_id, 1);
// Delete bound items from player's inventory
StringBuf_Clear(&buf);
StringBuf_Printf(&buf, "DELETE FROM `%s` WHERE",schema_config.inventory_db);
for(j=0; j<i; j++) {
if( found )
StringBuf_AppendStr(&buf, " OR");
else
found = true;
StringBuf_Printf(&buf, " `id`=%d",items[j].id);
if( items[j].bound && items[j].equip ) {
//Only the items that are also stored in `char` `equip`
if( (items[j].equip&EQP_HAND_R) ||
(items[j].equip&EQP_HAND_L) ||
(items[j].equip&EQP_HEAD_TOP) ||
(items[j].equip&EQP_HEAD_MID) ||
(items[j].equip&EQP_HEAD_LOW) ||
(items[j].equip&EQP_GARMENT) ||
(items[j].equip&EQP_COSTUME_HEAD_TOP) ||
(items[j].equip&EQP_COSTUME_HEAD_MID) ||
(items[j].equip&EQP_COSTUME_HEAD_LOW) ||
(items[j].equip&EQP_COSTUME_GARMENT) )
{
bound_item[bound_qt] = items[j].equip;
bound_qt++;
}
}
}
if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
|| SQL_ERROR == SqlStmt_Execute(stmt) )
StringBuf_Printf(&buf, "DELETE FROM `%s` WHERE `bound` = %d",schema_config.inventory_db, BOUND_GUILD);
if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) ||
SQL_ERROR == SqlStmt_Execute(stmt) )
{
SqlStmt_ShowDebug(stmt);
SqlStmt_Free(stmt);
StringBuf_Destroy(&buf);
mapif_itembound_ack(fd,aid,guild_id);
mapif_itembound_ack(fd,account_id,guild_id);
return 1;
}
if( bound_qt ) { //Removes any view id that was set by an item that was removed
/* Verifies equip bitmasks (see item.equip) and handles the sql statement */
#define CHECK_REMOVE(var,mask,token) do { \
if( (var)&(mask) ) { \
if( (var) != (mask) && s ) StringBuf_AppendStr(&buf, ","); \
StringBuf_AppendStr(&buf, "`"#token"`='0'"); \
(var) &= ~(mask); \
s++; \
} \
} while( 0 )
// Send the deleted items to map-server to store them in guild storage [Cydh]
mapif_itembound_store2gstorage(fd, guild_id, items, count);
StringBuf_Clear(&buf);
StringBuf_Printf(&buf, "UPDATE `%s` SET ", schema_config.char_db);
for( j = 0; j < bound_qt; j++ ) {
//Equips can be at more than one slot at the same time
CHECK_REMOVE(bound_item[j],EQP_HAND_R,weapon);
CHECK_REMOVE(bound_item[j],EQP_HAND_L,shield);
CHECK_REMOVE(bound_item[j],EQP_HEAD_TOP|EQP_COSTUME_HEAD_TOP,head_top);
CHECK_REMOVE(bound_item[j],EQP_HEAD_MID|EQP_COSTUME_HEAD_MID,head_mid);
CHECK_REMOVE(bound_item[j],EQP_HEAD_LOW|EQP_COSTUME_HEAD_LOW,head_bottom);
CHECK_REMOVE(bound_item[j],EQP_GARMENT|EQP_COSTUME_GARMENT,robe);
}
StringBuf_Printf(&buf, " WHERE `char_id`='%d'", char_id);
// Verifies equip bitmasks (see item.equip) and handles the sql statement
#define CHECK_REMOVE(var,mask,token,num) {\
if ((var)&(mask) && !(j&(num))) {\
if (j)\
StringBuf_AppendStr(&buf, ",");\
StringBuf_AppendStr(&buf, "`"#token"`='0'");\
j |= (1<<num);\
}\
}
StringBuf_Clear(&buf);
j = 0;
for (i = 0; i < count && i < MAX_INVENTORY; i++) {
if (!&items[i] || !items[i].equip)
continue;
// Equips can be at more than one slot at the same time
CHECK_REMOVE(items[i].equip, EQP_HAND_R, weapon, 0);
CHECK_REMOVE(items[i].equip, EQP_HAND_L, shield, 1);
CHECK_REMOVE(items[i].equip, EQP_HEAD_TOP|EQP_COSTUME_HEAD_TOP, head_top, 2);
CHECK_REMOVE(items[i].equip, EQP_HEAD_MID|EQP_COSTUME_HEAD_MID, head_mid, 3);
CHECK_REMOVE(items[i].equip, EQP_HEAD_LOW|EQP_COSTUME_HEAD_LOW, head_bottom, 4);
CHECK_REMOVE(items[i].equip, EQP_GARMENT|EQP_COSTUME_GARMENT, robe, 5);
}
#undef CHECK_REMOVE
// Update player's view
if (j) {
StringBuf buf2;
StringBuf_Init(&buf2);
StringBuf_Printf(&buf2, "UPDATE `%s` SET %s WHERE `char_id`='%d", schema_config.char_db, StringBuf_Value(&buf), char_id);
if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) ||
SQL_ERROR == SqlStmt_Execute(stmt) )
@ -369,67 +387,17 @@ int mapif_parse_itembound_retrieve(int fd)
SqlStmt_ShowDebug(stmt);
SqlStmt_Free(stmt);
StringBuf_Destroy(&buf);
mapif_itembound_ack(fd,aid,guild_id);
StringBuf_Destroy(&buf2);
mapif_itembound_ack(fd,account_id,guild_id);
return 1;
}
#undef CHECK_REMOVE
}
//Now let's update the guild storage with those deleted items
//@TODO/FIXME:
//This approach is basically the same as the one from memitemdata_to_sql, but
//the latter compares current database values and this is not needed in this case
//maybe sometime separate memitemdata_to_sql into different methods in order to use
//call that function here as well [Panikon]
found = false;
StringBuf_Clear(&buf);
StringBuf_Printf(&buf, "INSERT INTO `%s` (`guild_id`, `nameid`, `amount`, `equip`, `identify`, `refine`,"
"`attribute`, `expire_time`, `bound`", schema_config.guild_storage_db);
for( s = 0; s < MAX_SLOTS; ++s )
StringBuf_Printf(&buf, ", `card%d`", s);
StringBuf_AppendStr(&buf, ") VALUES ");
for( j = 0; j < i; ++j ) {
if( found )
StringBuf_AppendStr(&buf, ",");
else
found = true;
StringBuf_Printf(&buf, "('%d', '%hu', '%d', '%d', '%d', '%d', '%d', '%d', '%d'",
guild_id, items[j].nameid, items[j].amount, items[j].equip, items[j].identify, items[j].refine,
items[j].attribute, items[j].expire_time, items[j].bound);
for( s = 0; s < MAX_SLOTS; ++s )
StringBuf_Printf(&buf, ", '%hu'", items[j].card[s]);
StringBuf_AppendStr(&buf, ")");
}
if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
|| SQL_ERROR == SqlStmt_Execute(stmt) )
{
SqlStmt_ShowDebug(stmt);
SqlStmt_Free(stmt);
StringBuf_Destroy(&buf);
mapif_itembound_ack(fd,aid,guild_id);
return 1;
StringBuf_Destroy(&buf2);
}
StringBuf_Destroy(&buf);
SqlStmt_Free(stmt);
//Finally reload storage and tell map we're done
mapif_load_guild_storage(fd,aid,guild_id,0);
//If character is logged in char, disconnect,
/* @CHECKME [lighta]
* I suppose this was an attempt to avoid item duplication if the expelled user reconnect during the operation.
* well it's kinda ugly to expel someone like this, so I consider this as a hack.
* we better flag them so that they not allowed to reconnect during operation or flag it so we will flush those item on ram with the map ack.
* both way seem nicer for player.
*/
char_disconnect_player(aid);
//Tell map-server the operation is over and it can unlock the storage
mapif_itembound_ack(fd,aid,guild_id);
char_unset_session_flag(account_id, 1);
return 0;
}
#endif

View File

@ -278,12 +278,12 @@ struct storage_data {
};
struct guild_storage {
int dirty;
bool dirty;
int guild_id;
short storage_status;
short storage_amount;
struct item items[MAX_GUILD_STORAGE];
unsigned short lock;
bool locked;
int opened; /// Holds the char_id that open the storage
};
struct s_pet {

View File

@ -920,7 +920,7 @@ ACMD_FUNC(guildstorage)
return -1;
}
storage_guild_storageopen(sd);
gstorage_storageopen(sd);
clif_displaymessage(fd, msg_txt(sd,920)); // Guild storage opened.
return 0;
}
@ -5436,18 +5436,24 @@ ACMD_FUNC(cleargstorage)
return -1;
}
gstorage = guild2storage2(sd->status.guild_id);
gstorage = gstorage_get_storage(sd->status.guild_id);
if (gstorage == NULL) {// Doesn't have opened @gstorage yet, so we skip the deletion since *shouldn't* have any item there.
return -1;
}
j = gstorage->storage_amount;
gstorage->lock = 1; // Lock @gstorage: do not allow any item to be retrieved or stored from any guild member
for (i = 0; i < j; ++i) {
guild_storage_delitem(sd, gstorage, i, gstorage->items[i].amount);
if (gstorage->opened) {
struct map_session_data *tsd = map_charid2sd(gstorage->opened);
if (tsd)
gstorage_storageclose(tsd);
}
storage_guild_storageclose(sd);
gstorage->lock = 0; // Cleaning done, release lock
j = gstorage->storage_amount;
gstorage->locked = true; // Lock @gstorage: do not allow any item to be retrieved or stored from any guild member
for (i = 0; i < j; ++i) {
gstorage_delitem(sd, gstorage, i, gstorage->items[i].amount);
}
gstorage_storageclose(sd);
gstorage->locked = false; // Cleaning done, release lock
clif_displaymessage(fd, msg_txt(sd,1395)); // Your guild storage was cleaned.
return 0;

View File

@ -293,7 +293,7 @@ int chrif_save(struct map_session_data *sd, int flag) {
//For data sync
if (sd->state.storage_flag == 2)
storage_guild_storagesave(sd->status.account_id, sd->status.guild_id, flag);
gstorage_storagesave(sd->status.account_id, sd->status.guild_id, flag);
if (flag)
sd->state.storage_flag = 0; //Force close it.

View File

@ -2198,30 +2198,30 @@ void clif_additem(struct map_session_data *sd, int n, int amount, unsigned char
WFIFOHEAD(fd,packet_len(header));
if( fail )
{
WFIFOW(fd,offs+0)=header;
WFIFOW(fd,offs+2)=n+2;
WFIFOW(fd,offs+4)=amount;
WFIFOW(fd,offs+6)=0;
WFIFOB(fd,offs+8)=0;
WFIFOB(fd,offs+9)=0;
WFIFOB(fd,offs+10)=0;
WFIFOW(fd,offs+11)=0;
WFIFOW(fd,offs+13)=0;
WFIFOW(fd,offs+15)=0;
WFIFOW(fd,offs+17)=0;
WFIFOW(fd,offs+0) = header;
WFIFOW(fd,offs+2) = n+2;
WFIFOW(fd,offs+4) = amount;
WFIFOW(fd,offs+6) = 0;
WFIFOB(fd,offs+8) = 0;
WFIFOB(fd,offs+9) = 0;
WFIFOB(fd,offs+10) = 0;
WFIFOW(fd,offs+11) = 0;
WFIFOW(fd,offs+13) = 0;
WFIFOW(fd,offs+15) = 0;
WFIFOW(fd,offs+17) = 0;
#if PACKETVER < 20120925
WFIFOW(fd,offs+19)=0;
WFIFOW(fd,offs+19) = 0;
#else
WFIFOL(fd,offs+19)=0;
WFIFOL(fd,offs+19) = 0;
offs += 2;
#endif
WFIFOB(fd,offs+21)=0;
WFIFOB(fd,offs+22)=fail;
WFIFOB(fd,offs+21) = 0;
WFIFOB(fd,offs+22) = fail;
#if PACKETVER >= 20061218
WFIFOL(fd,offs+23)=0;
WFIFOL(fd,offs+23) = 0;
#endif
#if PACKETVER >= 20071002
WFIFOW(fd,offs+27)=0; // HireExpireDate
WFIFOW(fd,offs+27) = 0; // HireExpireDate
#endif
}
else
@ -2229,31 +2229,31 @@ void clif_additem(struct map_session_data *sd, int n, int amount, unsigned char
if( n < 0 || n >= MAX_INVENTORY || sd->status.inventory[n].nameid <=0 || sd->inventory_data[n] == NULL )
return;
WFIFOW(fd,offs+0)=header;
WFIFOW(fd,offs+2)=n+2;
WFIFOW(fd,offs+4)=amount;
WFIFOW(fd,offs+0) = header;
WFIFOW(fd,offs+2) = n+2;
WFIFOW(fd,offs+4) = amount;
if (sd->inventory_data[n]->view_id > 0)
WFIFOW(fd,offs+6)=sd->inventory_data[n]->view_id;
WFIFOW(fd,offs+6) = sd->inventory_data[n]->view_id;
else
WFIFOW(fd,offs+6)=sd->status.inventory[n].nameid;
WFIFOB(fd,offs+8)=sd->status.inventory[n].identify;
WFIFOB(fd,offs+9)=sd->status.inventory[n].attribute;
WFIFOB(fd,offs+10)=sd->status.inventory[n].refine;
WFIFOW(fd,offs+6) = sd->status.inventory[n].nameid;
WFIFOB(fd,offs+8) = sd->status.inventory[n].identify;
WFIFOB(fd,offs+9) = sd->status.inventory[n].attribute;
WFIFOB(fd,offs+10) = sd->status.inventory[n].refine;
clif_addcards(WFIFOP(fd,offs+11), &sd->status.inventory[n]);
#if PACKETVER < 20120925
WFIFOW(fd,offs+19)=pc_equippoint(sd,n);
WFIFOW(fd,offs+19) = pc_equippoint(sd,n);
#else
WFIFOL(fd,offs+19)=pc_equippoint(sd,n);
WFIFOL(fd,offs+19) = pc_equippoint(sd,n);
offs += 2;
#endif
WFIFOB(fd,offs+21)=itemtype(sd->inventory_data[n]->nameid);
WFIFOB(fd,offs+22)=fail;
WFIFOB(fd,offs+21) = itemtype(sd->inventory_data[n]->nameid);
WFIFOB(fd,offs+22) = fail;
#if PACKETVER >= 20061218
WFIFOL(fd,offs+23)=sd->status.inventory[n].expire_time;
WFIFOL(fd,offs+23) = sd->status.inventory[n].expire_time;
#endif
#if PACKETVER >= 20071002
/* Yellow color only for non-stackable item */
WFIFOW(fd,offs+27)=(sd->status.inventory[n].bound && !itemdb_isstackable(sd->status.inventory[n].nameid)) ? BOUND_DISPYELLOW : 0;
WFIFOW(fd,offs+27) = (sd->status.inventory[n].bound && !itemdb_isstackable(sd->status.inventory[n].nameid)) ? BOUND_DISPYELLOW : 0;
#endif
}
@ -8676,7 +8676,7 @@ void clif_refresh_storagewindow(struct map_session_data *sd) {
// Notify the client that the gstorage is open otherwise it will
// remain locked forever and nobody will be able to access it
if( sd->state.storage_flag == 2 ) {
struct guild_storage *gstor = guild2storage2(sd->status.guild_id);
struct guild_storage *gstor = gstorage_get_storage(sd->status.guild_id);
if( !gstor ) // Shouldn't happen. The information should already be at the map-server
intif_request_guild_storage(sd->status.account_id, sd->status.guild_id);
@ -11915,7 +11915,7 @@ void clif_parse_MoveToKafra(int fd, struct map_session_data *sd)
storage_storageadd(sd, item_index, item_amount);
else
if (sd->state.storage_flag == 2)
storage_guild_storageadd(sd, item_index, item_amount);
gstorage_storageadd(sd, item_index, item_amount);
}
@ -11934,7 +11934,7 @@ void clif_parse_MoveFromKafra(int fd,struct map_session_data *sd)
if (sd->state.storage_flag == 1)
storage_storageget(sd, item_index, item_amount);
else if(sd->state.storage_flag == 2)
storage_guild_storageget(sd, item_index, item_amount);
gstorage_storageget(sd, item_index, item_amount);
}
@ -11954,7 +11954,7 @@ void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd){
if (sd->state.storage_flag == 1)
storage_storageaddfromcart(sd, idx, amount);
else if (sd->state.storage_flag == 2)
storage_guild_storageaddfromcart(sd, idx, amount);
gstorage_storageaddfromcart(sd, idx, amount);
}
@ -11974,7 +11974,7 @@ void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd){
storage_storagegettocart(sd, idx, amount);
else
if (sd->state.storage_flag == 2)
storage_guild_storagegettocart(sd, idx, amount);
gstorage_storagegettocart(sd, idx, amount);
}
@ -11986,7 +11986,7 @@ void clif_parse_CloseKafra(int fd, struct map_session_data *sd)
storage_storageclose(sd);
else
if( sd->state.storage_flag == 2 )
storage_guild_storageclose(sd);
gstorage_storageclose(sd);
}

View File

@ -19,6 +19,8 @@
#include "pc.h"
#include "intif.h"
#include "channel.h"
#include "log.h"
#include "trade.h"
#include <stdlib.h>
@ -39,7 +41,6 @@ struct eventlist {
#define GUILD_PAYEXP_LIST 8192 //The maximum number of cache
//Guild EXP cache
struct guild_expcache {
int guild_id, account_id, char_id;
uint64 exp;
@ -408,6 +409,20 @@ int guild_npc_request_info(int guild_id,const char *event) {
return guild_request_info(guild_id);
}
/**
* Close trade window if party member is kicked when trade a party bound item
* @param sd
**/
static void guild_trade_bound_cancel(struct map_session_data *sd) {
#ifdef BOUND_ITEMS
nullpo_retv(sd);
if (sd->state.isBoundTrading&(1<<BOUND_GUILD))
trade_tradecancel(sd);
#else
;
#endif
}
//Confirmation of the character belongs to guild
int guild_check_member(struct guild *g) {
int i;
@ -740,6 +755,7 @@ int guild_leave(struct map_session_data* sd, int guild_id, uint32 account_id, ui
((agit_flag || agit2_flag) && map[sd->bl.m].flag.gvg_castle))
return 0;
guild_trade_bound_cancel(sd);
intif_guild_leave(sd->status.guild_id, sd->status.account_id, sd->status.char_id,0,mes);
return 0;
}
@ -773,12 +789,24 @@ int guild_expulsion(struct map_session_data* sd, int guild_id, uint32 account_id
// find the member and perform expulsion
i = guild_getindex(g, account_id, char_id);
if( i != -1 && strcmp(g->member[i].name,g->master) != 0 ) //Can't expel the GL!
if( i != -1 && strcmp(g->member[i].name,g->master) != 0 ) { //Can't expel the GL!
if (tsd)
guild_trade_bound_cancel(tsd);
intif_guild_leave(g->guild_id,account_id,char_id,1,mes);
}
return 0;
}
/**
* A confirmation from inter-serv that player is kicked successfully
* @param guild_Id
* @param account_id
* @param char_id
* @param flag
* @param name
* @param mes
*/
int guild_member_withdraw(int guild_id, uint32 account_id, uint32 char_id, int flag, const char* name, const char* mes) {
int i;
struct guild* g = guild_search(guild_id);
@ -815,7 +843,7 @@ int guild_member_withdraw(int guild_id, uint32 account_id, uint32 char_id, int f
if(sd != NULL && sd->status.guild_id == guild_id) {
// do stuff that needs the guild_id first, BEFORE we wipe it
if (sd->state.storage_flag == 2) //Close the guild storage.
storage_guild_storageclose(sd);
gstorage_storageclose(sd);
guild_send_dot_remove(sd);
channel_pcquit(sd,3); //leave guild and ally chan
sd->status.guild_id = 0;
@ -833,35 +861,44 @@ int guild_member_withdraw(int guild_id, uint32 account_id, uint32 char_id, int f
}
#ifdef BOUND_ITEMS
void guild_retrieveitembound(uint32 char_id,int aid,int guild_id) {
TBL_PC *sd = map_id2sd(aid);
if(sd){ //Character is online
/**
* Retrieve guild bound items from kicked member
* @param char_id
* @param account_id
* @param guild_id
*/
void guild_retrieveitembound(uint32 char_id, uint32 account_id, int guild_id) {
TBL_PC *sd = map_charid2sd(char_id);
if (sd) { //Character is online
int idxlist[MAX_INVENTORY];
int j;
j = pc_bound_chk(sd,BOUND_GUILD,idxlist);
if(j) {
struct guild_storage* stor = guild2storage(sd->status.guild_id);
if (j) {
struct guild_storage* stor = gstorage_guild2storage(sd->status.guild_id);
int i;
for(i=0;i<j;i++) { //Loop the matching items, guild_storage_additem takes care of opening storage
if(stor)
guild_storage_additem(sd,stor,&sd->status.inventory[idxlist[i]],sd->status.inventory[idxlist[i]].amount);
// Close the storage first if someone open it
if (stor && stor->opened) {
struct map_session_data *tsd = map_charid2sd(stor->opened);
if (tsd)
gstorage_storageclose(tsd);
}
for (i = 0; i < j; i++) { //Loop the matching items, gstorage_additem takes care of opening storage
if (stor)
gstorage_additem(sd,stor,&sd->status.inventory[idxlist[i]],sd->status.inventory[idxlist[i]].amount);
pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,4,LOG_TYPE_GSTORAGE);
}
storage_guild_storageclose(sd); //Close and save the storage
gstorage_storageclose(sd); //Close and save the storage
}
} else { //Character is offline, ask char server to do the job
struct guild_storage* stor = guild2storage2(guild_id);
struct guild_storage* stor = gstorage_get_storage(guild_id);
struct guild *g = guild_search(guild_id);
nullpo_retv(g);
if(stor && stor->storage_status == 1) { //Someone is in guild storage, close them
int i;
for(i=0; i<g->max_member; i++){
TBL_PC *pl_sd = g->member[i].sd;
if(pl_sd && pl_sd->state.storage_flag == 2)
storage_guild_storageclose(pl_sd);
}
if(stor && stor->opened) { //Someone is in guild storage, close them
struct map_session_data *tsd = map_charid2sd(stor->opened);
if (tsd)
gstorage_storageclose(tsd);
}
intif_itembound_req(char_id,aid,guild_id);
intif_itembound_guild_retrieve(char_id,account_id,guild_id);
}
}
#endif
@ -1643,14 +1680,14 @@ int guild_broken(int guild_id,int flag) {
struct guild *g = guild_search(guild_id);
int i;
if(flag!=0 || g==NULL)
if (flag != 0 || g == NULL)
return 0;
for(i=0;i<g->max_member;i++){ // Destroy all relationships
for (i = 0; i < g->max_member; i++){ // Destroy all relationships
struct map_session_data *sd = g->member[i].sd;
if(sd != NULL){
if(sd->state.storage_flag == 2)
storage_guild_storage_quit(sd,1);
gstorage_storage_quit(sd,1);
sd->status.guild_id=0;
sd->guild = NULL;
sd->state.gmaster_flag = 0;
@ -1665,7 +1702,7 @@ int guild_broken(int guild_id,int flag) {
guild_db->foreach(guild_db,guild_broken_sub,guild_id);
castle_db->foreach(castle_db,castle_guild_broken_sub,guild_id);
guild_storage_delete(guild_id);
gstorage_delete(guild_id);
if( channel_config.ally_enable ) {
channel_delete(g->channel);
}
@ -1673,7 +1710,10 @@ int guild_broken(int guild_id,int flag) {
return 0;
}
//Changes the Guild Master to the specified player. [Skotlex]
/** Changes the Guild Master to the specified player. [Skotlex]
* @param guild_id
* @param sd New guild master
*/
int guild_gm_change(int guild_id, struct map_session_data *sd) {
struct guild *g;
nullpo_ret(sd);
@ -1681,7 +1721,7 @@ int guild_gm_change(int guild_id, struct map_session_data *sd) {
if (sd->status.guild_id != guild_id)
return 0;
g=guild_search(guild_id);
g = guild_search(guild_id);
nullpo_ret(g);
@ -1693,7 +1733,11 @@ int guild_gm_change(int guild_id, struct map_session_data *sd) {
return 1;
}
//Notification from Char server that a guild's master has changed. [Skotlex]
/** Notification from Char server that a guild's master has changed. [Skotlex]
* @param guild_id
* @param account_id
* @param char_id
*/
int guild_gm_changed(int guild_id, uint32 account_id, uint32 char_id) {
struct guild *g;
struct guild_member gm;
@ -1743,9 +1787,10 @@ int guild_gm_changed(int guild_id, uint32 account_id, uint32 char_id) {
return 1;
}
/*====================================================
* Guild disbanded
*---------------------------------------------------*/
/** Disband a guild
* @param sd Player who breaks the guild
* @param name Guild name
*/
int guild_break(struct map_session_data *sd,char *name) {
struct guild *g;
struct unit_data *ud;
@ -1757,25 +1802,25 @@ int guild_break(struct map_session_data *sd,char *name) {
nullpo_ret(sd);
if( (g=sd->guild)==NULL )
if ((g=sd->guild)==NULL)
return 0;
if(strcmp(g->name,name)!=0)
if (strcmp(g->name,name) != 0)
return 0;
if(!sd->state.gmaster_flag)
if (!sd->state.gmaster_flag)
return 0;
for(i=0;i<g->max_member;i++){
for (i = 0; i < g->max_member; i++) {
if( g->member[i].account_id>0 && (
g->member[i].account_id!=sd->status.account_id ||
g->member[i].char_id!=sd->status.char_id ))
break;
}
if(i<g->max_member){
if (i < g->max_member) {
clif_guild_broken(sd,2);
return 0;
}
/* Regardless of char server allowing it, we clear the guild master's auras */
if((ud = unit_bl2ud(&sd->bl))) {
if ((ud = unit_bl2ud(&sd->bl))) {
int count = 0;
struct skill_unit_group *group[4];
@ -1792,15 +1837,15 @@ int guild_break(struct map_session_data *sd,char *name) {
break;
}
}
for(i = 0; i < count; i++)
for (i = 0; i < count; i++)
skill_delunitgroup(group[i]);
}
#ifdef BOUND_ITEMS
//Guild bound item check - Removes the bound flag
j = pc_bound_chk(sd,BOUND_GUILD,idxlist);
for(i=0;i<j;i++)
sd->status.inventory[idxlist[i]].bound = BOUND_NONE;
for(i = 0; i < j; i++)
pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_BOUND_REMOVAL);
#endif
intif_guild_break(g->guild_id);
@ -1911,6 +1956,9 @@ void guild_castle_reconnect_sub(void *key, void *data, va_list ap) {
* Saves pending guild castle data changes when char-server is
* disconnected.
* On reconnect pushes all changes to char-server for saving.
* @param castle_id
* @param index
* @param value
*/
void guild_castle_reconnect(int castle_id, int index, int value) {
static struct linkdb_node *gc_save_pending = NULL;
@ -1926,7 +1974,10 @@ void guild_castle_reconnect(int castle_id, int index, int value) {
}
}
// Load castle data then invoke OnAgitInit* on last
/** Load castle data then invoke OnAgitInit* on last
* @param len
* @param gc Guild Castle data
*/
int guild_castledataloadack(int len, struct guild_castle *gc) {
int i;
int n = (len-4) / sizeof(struct guild_castle);

View File

@ -107,7 +107,7 @@ void guild_flags_clear(void);
void guild_guildaura_refresh(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv);
#ifdef BOUND_ITEMS
void guild_retrieveitembound(uint32 char_id,int aid,int guild_id);
void guild_retrieveitembound(uint32 char_id,uint32 account_id,int guild_id);
#endif
void do_final_guild(void);

View File

@ -30,7 +30,7 @@ static const int packet_len_table[]={
39,-1,15,15, 14,19, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0, //0x3820
10,-1,15, 0, 79,19, 7,-1, 0,-1,-1,-1, 14,67,186,-1, //0x3830
-1, 0, 0,14, 0, 0, 0, 0, -1,74,-1,11, 11,-1, 0, 0, //0x3840
-1,-1, 7, 7, 7,11, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3850 Auctions [Zephyrus] itembound[Akinari]
-1,-1, 7, 7, 7,11, 8,-1, 0, 0, 0, 0, 0, 0, 0, 0, //0x3850 Auctions [Zephyrus] itembound[Akinari]
-1, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3860 Quests [Kevin] [Inkfish]
-1, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 3, 3, 0, //0x3870 Mercenaries [Zephyrus] / Elemental [pakpil]
12,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3880
@ -1333,22 +1333,22 @@ int intif_parse_LoadGuildStorage(int fd)
guild_id = RFIFOL(fd,8);
flag = RFIFOL(fd,12);
if(guild_id <= 0)
if (guild_id <= 0)
return 0;
sd=map_id2sd( RFIFOL(fd,4) );
if( flag ){ //If flag != 0, we attach a player and open the storage
if(sd==NULL){
ShowError("intif_parse_LoadGuildStorage: user not found %d\n",RFIFOL(fd,4));
sd = map_id2sd( RFIFOL(fd,4) );
if (flag){ //If flag != 0, we attach a player and open the storage
if(sd == NULL){
ShowError("intif_parse_LoadGuildStorage: user not found (AID: %d)\n",RFIFOL(fd,4));
return 0;
}
}
gstor=guild2storage(guild_id);
if(!gstor) {
gstor = gstorage_guild2storage(guild_id);
if (!gstor) {
ShowWarning("intif_parse_LoadGuildStorage: error guild_id %d not exist\n",guild_id);
return 0;
}
if (gstor->storage_status == 1) { // Already open.. lets ignore this update
if (gstor->opened) { // Already open.. lets ignore this update
ShowWarning("intif_parse_LoadGuildStorage: storage received for a client already open (User %d:%d)\n", flag?sd->status.account_id:1, flag?sd->status.char_id:1);
return 0;
}
@ -1358,13 +1358,13 @@ int intif_parse_LoadGuildStorage(int fd)
}
if( RFIFOW(fd,2)-13 != sizeof(struct guild_storage) ){
ShowError("intif_parse_LoadGuildStorage: data size error %d %d\n",RFIFOW(fd,2)-13 , sizeof(struct guild_storage));
gstor->storage_status = 0;
gstor->opened = 0;
return 0;
}
memcpy(gstor,RFIFOP(fd,13),sizeof(struct guild_storage));
if( flag )
storage_guild_storageopen(sd);
gstorage_storageopen(sd);
return 1;
}
@ -1376,7 +1376,7 @@ int intif_parse_LoadGuildStorage(int fd)
*/
int intif_parse_SaveGuildStorage(int fd)
{
storage_guild_storagesaved(/*RFIFOL(fd,2), */RFIFOL(fd,6));
gstorage_storagesaved(/*RFIFOL(fd,2), */RFIFOL(fd,6));
return 1;
}
@ -2875,13 +2875,14 @@ void intif_parse_MessageToFD(int fd) {
#ifdef BOUND_ITEMS
/**
* Request char-serv to delete some bound item, for non connected cid
* ZI 0x3056 <char_id>.L <account_id>.L <guild_id>.W
* Request inter-serv to delete some bound item, for non connected cid
* @param char_id : Char to delete item ID
* @param aid : Account to delete item ID
* @param guild_id : Guild of char
*/
void intif_itembound_req(uint32 char_id, uint32 aid,int guild_id) {
struct guild_storage *gstor = guild2storage2(guild_id);
void intif_itembound_guild_retrieve(uint32 char_id,uint32 account_id,int guild_id) {
struct guild_storage *gstor = gstorage_get_storage(guild_id);
if( CheckForCharServer() )
return;
@ -2889,10 +2890,12 @@ void intif_itembound_req(uint32 char_id, uint32 aid,int guild_id) {
WFIFOHEAD(inter_fd,12);
WFIFOW(inter_fd,0) = 0x3056;
WFIFOL(inter_fd,2) = char_id;
WFIFOL(inter_fd,6) = aid;
WFIFOL(inter_fd,6) = account_id;
WFIFOW(inter_fd,10) = guild_id;
WFIFOSET(inter_fd,12);
if(gstor) gstor->lock = 1; //Lock for retrieval process
if (gstor)
gstor->locked = true; //Lock for retrieval process
ShowInfo("Request guild bound item(s) retrieval for CID = "CL_WHITE"%d"CL_RESET", AID = %d, Guild ID = "CL_WHITE"%d"CL_RESET".\n", char_id, account_id, guild_id);
}
/**
@ -2903,8 +2906,38 @@ void intif_itembound_req(uint32 char_id, uint32 aid,int guild_id) {
*/
void intif_parse_itembound_ack(int fd) {
int guild_id = RFIFOW(fd,6);
struct guild_storage *gstor = guild2storage2(guild_id);
if(gstor) gstor->lock = 0; //Unlock now that operation is completed
struct guild_storage *gstor = gstorage_get_storage(guild_id);
if (gstor)
gstor->locked = false; //Unlock now that operation is completed
}
/**
* IZ 0x3857 <size>.W <count>.W <guild_id>.W { <item>.?B }.*MAX_INVENTORY
* Received the retrieved guild bound items from inter-server, store them to guild storage.
* @param fd
* @author [Cydh]
*/
void intif_parse_itembound_store2gstorage(int fd) {
unsigned short i, failed = 0;
short count = RFIFOW(fd, 4), guild_id = RFIFOW(fd, 6);
struct guild_storage *gstor = gstorage_guild2storage(guild_id);
if (!gstor) {
ShowError("intif_parse_itembound_store2gstorage: Guild '%d' not found.\n", guild_id);
return;
}
//@TODO: Gives some actions for item(s) that cannot be stored because storage is full or reach the limit of stack amount
for (i = 0; i < count; i++) {
struct item *item = (struct item*)RFIFOP(fd, 8 + i*sizeof(struct item));
if (!item)
continue;
if (!gstorage_additem2(gstor, item, item->amount))
failed++;
}
ShowInfo("Retrieved '"CL_WHITE"%d"CL_RESET"' (failed: %d) guild bound item(s) for Guild ID = "CL_WHITE"%d"CL_RESET".\n", count, failed, guild_id);
gstor->locked = false;
gstor->opened = 0;
}
#endif
@ -2998,6 +3031,7 @@ int intif_parse(int fd)
//Bound items
#ifdef BOUND_ITEMS
case 0x3856: intif_parse_itembound_ack(fd); break;
case 0x3857: intif_parse_itembound_store2gstorage(fd); break;
#endif
//Quest system

View File

@ -60,7 +60,7 @@ int intif_guild_emblem(int guild_id, int len, const char *data);
int intif_guild_castle_dataload(int num, int *castle_ids);
int intif_guild_castle_datasave(int castle_id, int index, int value);
#ifdef BOUND_ITEMS
void intif_itembound_req(uint32 char_id, uint32 aid, int guild_id);
void intif_itembound_guild_retrieve(uint32 char_id, uint32 account_id, int guild_id);
#endif
int intif_create_pet(uint32 account_id, uint32 char_id, short pet_type, short pet_lv, short pet_egg_id,

View File

@ -419,10 +419,9 @@ struct item_data* itemdb_search(unsigned short nameid) {
* @param id Item data
* @return True if item is equip, false otherwise
*/
bool itemdb_isequip2(struct item_data *id)
{
bool itemdb_isequip2(struct item_data *id) {
nullpo_ret(id);
switch(id->type) {
switch (id->type) {
case IT_WEAPON:
case IT_ARMOR:
case IT_AMMO:

View File

@ -74,6 +74,7 @@ static char log_picktype2char(e_log_pick_type type)
case LOG_TYPE_BANK: return 'K'; // Ban(K) Transactions
case LOG_TYPE_OTHER: return 'X'; // Other
case LOG_TYPE_CASH: return '$'; // Cash
case LOG_TYPE_BOUND_REMOVAL: return 'B'; // Removed bound items when guild/party is broken
}
// should not get here, fallback

View File

@ -43,6 +43,7 @@ typedef enum e_log_pick_type
LOG_TYPE_OTHER = 0x10000,
LOG_TYPE_CASH = 0x20000,
LOG_TYPE_BANK = 0x40000,
LOG_TYPE_BOUND_REMOVAL = 0x80000,
// combinations
LOG_TYPE_LOOT = LOG_TYPE_PICKDROP_MONSTER|LOG_TYPE_CONSUME,
// all

View File

@ -1524,16 +1524,16 @@ bool map_closest_freecell(int16 m, int16 *x, int16 *y, int type, int flag)
int map_addflooritem(struct item *item,int amount,int16 m,int16 x,int16 y,int first_charid,int second_charid,int third_charid,int flags)
{
int r;
struct flooritem_data *fitem=NULL;
struct flooritem_data *fitem = NULL;
nullpo_ret(item);
if(!(flags&4) && battle_config.item_onfloor && (itemdb_traderight(item->nameid)&1) )
if (!(flags&4) && battle_config.item_onfloor && (itemdb_traderight(item->nameid)&1))
return 0; //can't be dropped
if(!map_searchrandfreecell(m,&x,&y,flags&2?1:0))
if (!map_searchrandfreecell(m,&x,&y,flags&2?1:0))
return 0;
r=rnd();
r = rnd();
CREATE(fitem, struct flooritem_data, 1);
fitem->bl.type=BL_ITEM;
@ -1542,7 +1542,7 @@ int map_addflooritem(struct item *item,int amount,int16 m,int16 x,int16 y,int fi
fitem->bl.x=x;
fitem->bl.y=y;
fitem->bl.id = map_get_new_object_id();
if(fitem->bl.id==0){
if (fitem->bl.id==0) {
aFree(fitem);
return 0;
}
@ -1555,13 +1555,13 @@ int map_addflooritem(struct item *item,int amount,int16 m,int16 x,int16 y,int fi
fitem->third_get_tick = fitem->second_get_tick + (flags&1 ? battle_config.mvp_item_third_get_time : battle_config.item_third_get_time);
memcpy(&fitem->item,item,sizeof(*item));
fitem->item.amount=amount;
fitem->subx=(r&3)*3+3;
fitem->suby=((r>>2)&3)*3+3;
fitem->cleartimer=add_timer(gettick()+battle_config.flooritem_lifetime,map_clearflooritem_timer,fitem->bl.id,0);
fitem->item.amount = amount;
fitem->subx = (r&3)*3+3;
fitem->suby = ((r>>2)&3)*3+3;
fitem->cleartimer = add_timer(gettick()+battle_config.flooritem_lifetime,map_clearflooritem_timer,fitem->bl.id,0);
map_addiddb(&fitem->bl);
if(map_addblock(&fitem->bl))
if (map_addblock(&fitem->bl))
return 0;
clif_dropflooritem(fitem);

View File

@ -17,6 +17,7 @@
#include "instance.h"
#include "intif.h"
#include "mapreg.h"
#include "trade.h"
#include <stdlib.h>
@ -188,6 +189,20 @@ int party_request_info(int party_id, uint32 char_id)
return intif_request_partyinfo(party_id, char_id);
}
/**
* Close trade window if party member is kicked when trade a party bound item
* @param sd
**/
static void party_trade_bound_cancel(struct map_session_data *sd) {
#ifdef BOUND_ITEMS
nullpo_retv(sd);
if (sd->state.isBoundTrading&(1<<BOUND_PARTY))
trade_tradecancel(sd);
#else
;
#endif
}
/// Invoked (from char-server) when the party info is not found.
int party_recv_noinfo(int party_id, uint32 char_id)
{
@ -531,6 +546,7 @@ int party_removemember(struct map_session_data* sd, uint32 account_id, char* nam
if( i == MAX_PARTY )
return 0; // no such char in party
party_trade_bound_cancel(sd);
intif_party_leave(p->party.party_id,account_id,p->party.member[i].char_id);
return 1;
@ -541,6 +557,8 @@ int party_removemember2(struct map_session_data *sd,uint32 char_id,int party_id)
if( sd ) {
if( !sd->status.party_id )
return -3;
party_trade_bound_cancel(sd);
intif_party_leave(sd->status.party_id,sd->status.account_id,sd->status.char_id);
return 1;
} else {
@ -573,6 +591,7 @@ int party_leave(struct map_session_data *sd)
if( i == MAX_PARTY )
return 0;
party_trade_bound_cancel(sd);
intif_party_leave(p->party.party_id,sd->status.account_id,sd->status.char_id);
return 1;
}
@ -600,10 +619,11 @@ int party_member_withdraw(int party_id, uint32 account_id, uint32 char_id)
int idxlist[MAX_INVENTORY]; //or malloc to reduce consumtion
int j,i;
party_trade_bound_cancel(sd);
j = pc_bound_chk(sd,BOUND_PARTY,idxlist);
for(i = 0; i < j; i++)
pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_OTHER);
pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_BOUND_REMOVAL);
#endif
sd->status.party_id = 0;
@ -1057,7 +1077,7 @@ int party_exp_share(struct party_data* p, struct block_list* src, unsigned int b
}
//Does party loot. first_charid holds the charid of the player who has time priority to take the item.
int party_share_loot(struct party_data* p, struct map_session_data* sd, struct item* item_data, int first_charid)
int party_share_loot(struct party_data* p, struct map_session_data* sd, struct item* item, int first_charid)
{
TBL_PC* target = NULL;
int i;
@ -1077,7 +1097,7 @@ int party_share_loot(struct party_data* p, struct map_session_data* sd, struct i
if( (psd = p->data[i].sd) == NULL || sd->bl.m != psd->bl.m || pc_isdead(psd) || (battle_config.idle_no_share && pc_isidle(psd)) )
continue;
if (pc_additem(psd,item_data,item_data->amount,LOG_TYPE_PICKDROP_PLAYER))
if (pc_additem(psd,item,item->amount,LOG_TYPE_PICKDROP_PLAYER))
continue; //Chosen char can't pick up loot.
//Successful pick.
@ -1100,7 +1120,7 @@ int party_share_loot(struct party_data* p, struct map_session_data* sd, struct i
while (count > 0) { //Pick a random member.
i = rnd()%count;
if (pc_additem(psd[i],item_data,item_data->amount,LOG_TYPE_PICKDROP_PLAYER)) { // Discard this receiver.
if (pc_additem(psd[i],item,item->amount,LOG_TYPE_PICKDROP_PLAYER)) { // Discard this receiver.
psd[i] = psd[count-1];
count--;
} else { // Successful pick.
@ -1114,12 +1134,12 @@ int party_share_loot(struct party_data* p, struct map_session_data* sd, struct i
if (!target) {
target = sd; //Give it to the char that picked it up
if ((i = pc_additem(sd,item_data,item_data->amount,LOG_TYPE_PICKDROP_PLAYER)))
if ((i = pc_additem(sd,item,item->amount,LOG_TYPE_PICKDROP_PLAYER)))
return i;
}
if( p && battle_config.party_show_share_picker && battle_config.show_picker_item_type&(1<<itemdb_type(item_data->nameid)) )
clif_party_show_picker(target, item_data);
if( p && battle_config.party_show_share_picker && battle_config.show_picker_item_type&(1<<itemdb_type(item->nameid)) )
clif_party_show_picker(target, item);
return 0;
}

View File

@ -84,7 +84,7 @@ int party_recv_message(int party_id,uint32 account_id,const char *mes,int len);
int party_skill_check(struct map_session_data *sd, int party_id, uint16 skill_id, uint16 skill_lv);
int party_send_xy_clear(struct party_data *p);
int party_exp_share(struct party_data *p,struct block_list *src,unsigned int base_exp,unsigned int job_exp,int zeny);
int party_share_loot(struct party_data* p, struct map_session_data* sd, struct item* item_data, int first_charid);
int party_share_loot(struct party_data* p, struct map_session_data* sd, struct item* item, int first_charid);
int party_send_dot_remove(struct map_session_data *sd);
int party_sub_count(struct block_list *bl, va_list ap);
int party_sub_count_class(struct block_list *bl, va_list ap);

View File

@ -4430,47 +4430,47 @@ bool pc_dropitem(struct map_session_data *sd,int n,int amount)
*------------------------------------------*/
bool pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem)
{
int flag=0;
int flag = 0;
unsigned int tick = gettick();
struct party_data *p = NULL;
nullpo_ret(sd);
nullpo_ret(fitem);
if(!check_distance_bl(&fitem->bl, &sd->bl, 2) && sd->ud.skill_id!=BS_GREED)
if (!check_distance_bl(&fitem->bl, &sd->bl, 2) && sd->ud.skill_id!=BS_GREED)
return false; // Distance is too far
if( sd->sc.cant.pickup )
if (sd->sc.cant.pickup)
return false;
if (sd->status.party_id)
p = party_search(sd->status.party_id);
if(fitem->first_get_charid > 0 && fitem->first_get_charid != sd->status.char_id) {
if (fitem->first_get_charid > 0 && fitem->first_get_charid != sd->status.char_id) {
struct map_session_data *first_sd = map_charid2sd(fitem->first_get_charid);
if(DIFF_TICK(tick,fitem->first_get_tick) < 0) {
if (DIFF_TICK(tick,fitem->first_get_tick) < 0) {
if (!(p && p->party.item&1 &&
first_sd && first_sd->status.party_id == sd->status.party_id
))
))
return false;
}
else if(fitem->second_get_charid > 0 && fitem->second_get_charid != sd->status.char_id) {
else if (fitem->second_get_charid > 0 && fitem->second_get_charid != sd->status.char_id) {
struct map_session_data *second_sd = map_charid2sd(fitem->second_get_charid);
if(DIFF_TICK(tick, fitem->second_get_tick) < 0) {
if(!(p && p->party.item&1 &&
if (DIFF_TICK(tick, fitem->second_get_tick) < 0) {
if (!(p && p->party.item&1 &&
((first_sd && first_sd->status.party_id == sd->status.party_id) ||
(second_sd && second_sd->status.party_id == sd->status.party_id))
))
))
return false;
}
else if(fitem->third_get_charid > 0 && fitem->third_get_charid != sd->status.char_id){
else if (fitem->third_get_charid > 0 && fitem->third_get_charid != sd->status.char_id){
struct map_session_data *third_sd = map_charid2sd(fitem->third_get_charid);
if(DIFF_TICK(tick,fitem->third_get_tick) < 0) {
if (DIFF_TICK(tick,fitem->third_get_tick) < 0) {
if(!(p && p->party.item&1 &&
((first_sd && first_sd->status.party_id == sd->status.party_id) ||
(second_sd && second_sd->status.party_id == sd->status.party_id) ||
(third_sd && third_sd->status.party_id == sd->status.party_id))
))
))
return false;
}
}

View File

@ -229,6 +229,7 @@ struct map_session_data {
unsigned int banking : 1; //1 when we using the banking system 0 when closed
unsigned int hpmeter_visible : 1;
unsigned disable_atcommand_on_npc : 1; //Prevent to use atcommand while talking with NPC [Kichi]
uint8 isBoundTrading; // Player is currently add bound item to trade list [Cydh]
} state;
struct {
unsigned char no_weapon_damage, no_magic_damage, no_misc_damage;

View File

@ -9232,7 +9232,7 @@ BUILDIN_FUNC(guildopenstorage)
if( sd == NULL )
return 0;
ret = storage_guild_storageopen(sd);
ret = gstorage_storageopen(sd);
script_pushint(st,ret);
return SCRIPT_CMD_SUCCESS;
}

View File

@ -5,6 +5,7 @@
#include "../common/db.h"
#include "../common/nullpo.h"
#include "../common/malloc.h"
#include "../common/showmsg.h"
#include "map.h" // struct map_session_data
#include "storage.h"
@ -85,8 +86,8 @@ static int storage_reconnect_sub(DBKey key, DBData *data, va_list ap)
{
struct guild_storage *stor = db_data2ptr(data);
if (stor->dirty && stor->storage_status == 0) //Save closed storages.
storage_guild_storagesave(0, stor->guild_id,0);
if (stor->dirty && stor->opened == 0) //Save closed storages.
gstorage_storagesave(0, stor->guild_id,0);
return 0;
}
@ -421,12 +422,12 @@ static DBData create_guildstorage(DBKey key, va_list args)
* @param guild_id : id of the guild
* @return guild_storage
*/
struct guild_storage *guild2storage(int guild_id)
struct guild_storage *gstorage_guild2storage(int guild_id)
{
struct guild_storage *gs = NULL;
if(guild_search(guild_id) != NULL)
gs = idb_ensure(guild_storage_db,guild_id,create_guildstorage);
if (guild_search(guild_id) != NULL)
gs = (struct guild_storage *)idb_ensure(guild_storage_db,guild_id,create_guildstorage);
return gs;
}
@ -437,7 +438,7 @@ struct guild_storage *guild2storage(int guild_id)
* @param guild_id : guild_id to search the storage
* @return guild_storage or NULL
*/
struct guild_storage *guild2storage2(int guild_id)
struct guild_storage *gstorage_get_storage(int guild_id)
{
return (struct guild_storage*)idb_get(guild_storage_db,guild_id);
}
@ -447,11 +448,9 @@ struct guild_storage *guild2storage2(int guild_id)
* @param guild_id : guild to remove the storage from
* @return 0
*/
int guild_storage_delete(int guild_id)
void gstorage_delete(int guild_id)
{
idb_remove(guild_storage_db,guild_id);
return 0;
}
/**
@ -459,7 +458,7 @@ int guild_storage_delete(int guild_id)
* @param sd : player
* @return 0 : success, 1 : fail, 2 : no guild found
*/
int storage_guild_storageopen(struct map_session_data* sd)
char gstorage_storageopen(struct map_session_data* sd)
{
struct guild_storage *gstor;
@ -476,18 +475,18 @@ int storage_guild_storageopen(struct map_session_data* sd)
return 1;
}
if((gstor = guild2storage2(sd->status.guild_id)) == NULL) {
if((gstor = gstorage_get_storage(sd->status.guild_id)) == NULL) {
intif_request_guild_storage(sd->status.account_id,sd->status.guild_id);
return 0;
}
if(gstor->storage_status)
if(gstor->opened)
return 1;
if( gstor->lock )
if( gstor->locked )
return 1;
gstor->storage_status = 1;
gstor->opened = sd->status.char_id;
sd->state.storage_flag = 2;
storage_sortitem(gstor->items, ARRAYLENGTH(gstor->items));
clif_storagelist(sd, gstor->items, ARRAYLENGTH(gstor->items));
@ -500,66 +499,109 @@ int storage_guild_storageopen(struct map_session_data* sd)
* Attempt to add an item in guild storage, then refresh it
* @param sd : player attempting to open the guild_storage
* @param stor : guild_storage
* @param item_data : item to add
* @param item : item to add
* @param amount : number of item to add
* @return 0 : success, 1 : fail
* @return True : success, False : fail
*/
char guild_storage_additem(struct map_session_data* sd, struct guild_storage* stor, struct item* item_data, int amount)
bool gstorage_additem(struct map_session_data* sd, struct guild_storage* stor, struct item* item, int amount)
{
struct item_data *data;
struct item_data *id;
int i;
nullpo_retr(1, sd);
nullpo_retr(1, stor);
nullpo_retr(1, item_data);
nullpo_ret(sd);
nullpo_ret(stor);
nullpo_ret(item);
if(item_data->nameid == 0 || amount <= 0)
return 1;
if(item->nameid == 0 || amount <= 0)
return false;
data = itemdb_search(item_data->nameid);
id = itemdb_search(item->nameid);
if( data->stack.guildstorage && amount > data->stack.amount ) // item stack limitation
return 1;
if( id->stack.guildstorage && amount > id->stack.amount ) // item stack limitation
return false;
if( !itemdb_canguildstore(item_data, pc_get_group_level(sd)) || item_data->expire_time ) { // Check if item is storable. [Skotlex]
if( !itemdb_canguildstore(item, pc_get_group_level(sd)) || item->expire_time ) { // Check if item is storable. [Skotlex]
clif_displaymessage (sd->fd, msg_txt(sd,264));
return 1;
return false;
}
if( (item_data->bound == BOUND_ACCOUNT || item_data->bound > BOUND_GUILD) && !pc_can_give_bounded_items(sd) ) {
if( (item->bound == BOUND_ACCOUNT || item->bound > BOUND_GUILD) && !pc_can_give_bounded_items(sd) ) {
clif_displaymessage(sd->fd, msg_txt(sd,294));
return 1;
return false;
}
if(itemdb_isstackable2(data)) { //Stackable
if(itemdb_isstackable2(id)) { //Stackable
for(i = 0; i < MAX_GUILD_STORAGE; i++){
if(compare_item(&stor->items[i], item_data)) {
if( amount > MAX_AMOUNT - stor->items[i].amount || ( data->stack.guildstorage && amount > data->stack.amount - stor->items[i].amount ) )
return 1;
if(compare_item(&stor->items[i], item)) {
if( amount > MAX_AMOUNT - stor->items[i].amount || ( id->stack.guildstorage && amount > id->stack.amount - stor->items[i].amount ) )
return false;
stor->items[i].amount+=amount;
clif_storageitemadded(sd,&stor->items[i],i,amount);
stor->dirty = 1;
return 0;
stor->dirty = true;
return true;
}
}
}
//Add item
for(i = 0; i < MAX_GUILD_STORAGE && stor->items[i].nameid; i++);
if(i >= MAX_GUILD_STORAGE)
return 1;
return false;
memcpy(&stor->items[i],item_data,sizeof(stor->items[0]));
stor->items[i].amount=amount;
memcpy(&stor->items[i],item,sizeof(stor->items[0]));
stor->items[i].amount = amount;
stor->storage_amount++;
clif_storageitemadded(sd,&stor->items[i],i,amount);
clif_updatestorageamount(sd, stor->storage_amount, MAX_GUILD_STORAGE);
stor->dirty = 1;
stor->dirty = true;
return true;
}
return 0;
/**
* Attempt to add an item in guild storage, then refresh i
* @param stor : guild_storage
* @param item : item to add
* @param amount : number of item to add
* @return True : success, False : fail
*/
bool gstorage_additem2(struct guild_storage* stor, struct item* item, int amount) {
struct item_data *id;
int i;
nullpo_ret(stor);
nullpo_ret(item);
if (item->nameid == 0 || amount <= 0 || !(id = itemdb_exists(item->nameid)))
return false;
if (item->expire_time)
return false;
if (itemdb_isstackable2(id)) { // Stackable
for (i = 0; i < MAX_GUILD_STORAGE; i++) {
if (compare_item(&stor->items[i], item)) {
// Set the amount, make it fit with max amount
amount = min(amount, ((id->stack.guildstorage) ? id->stack.amount : MAX_AMOUNT) - stor->items[i].amount);
if (amount != item->amount)
ShowWarning("gstorage_additem2: Stack limit reached! Altered amount of item \""CL_WHITE"%s"CL_RESET"\" (%d). '"CL_WHITE"%d"CL_RESET"' -> '"CL_WHITE"%d"CL_RESET"'.\n", id->name, id->nameid, item->amount, amount);
stor->items[i].amount += amount;
stor->dirty = true;
return true;
}
}
}
// Add the item
for (i = 0; i < MAX_GUILD_STORAGE && stor->items[i].nameid; i++);
if (i >= MAX_GUILD_STORAGE)
return false;
memcpy(&stor->items[i], item, sizeof(stor->items[0]));
stor->items[i].amount = amount;
stor->storage_amount++;
stor->dirty = true;
return true;
}
/**
@ -568,15 +610,15 @@ char guild_storage_additem(struct map_session_data* sd, struct guild_storage* st
* @param stor : guild_storage
* @param n : index of item in guild storage
* @param amount : number of item to delete
* @return 0 : success, 1 : fail
* @return True : success, False : fail
*/
int guild_storage_delitem(struct map_session_data* sd, struct guild_storage* stor, int n, int amount)
bool gstorage_delitem(struct map_session_data* sd, struct guild_storage* stor, int n, int amount)
{
nullpo_retr(1, sd);
nullpo_retr(1, stor);
if(stor->items[n].nameid == 0 || stor->items[n].amount < amount)
return 1;
return false;
stor->items[n].amount -= amount;
@ -587,25 +629,23 @@ int guild_storage_delitem(struct map_session_data* sd, struct guild_storage* sto
}
clif_storageitemremoved(sd,n,amount);
stor->dirty = 1;
return 0;
stor->dirty = true;
return true;
}
/**
* Attempt to add an item in guild storage from inventory, then refresh it
* @param sd : player
* @param amount : number of item to delete
* @return 1:success, 0:fail
*/
void storage_guild_storageadd(struct map_session_data* sd, int index, int amount)
void gstorage_storageadd(struct map_session_data* sd, int index, int amount)
{
struct guild_storage *stor;
nullpo_retv(sd);
nullpo_retv(stor = guild2storage2(sd->status.guild_id));
nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
if( !stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE )
if( !stor->opened || stor->opened != sd->status.char_id || stor->storage_amount > MAX_GUILD_STORAGE )
return;
if( index < 0 || index >= MAX_INVENTORY )
@ -617,12 +657,12 @@ void storage_guild_storageadd(struct map_session_data* sd, int index, int amount
if( amount < 1 || amount > sd->status.inventory[index].amount )
return;
if( stor->lock ) {
storage_guild_storageclose(sd);
if( stor->locked ) {
gstorage_storageclose(sd);
return;
}
if(guild_storage_additem(sd,stor,&sd->status.inventory[index],amount) == 0)
if(gstorage_additem(sd,stor,&sd->status.inventory[index],amount))
pc_delitem(sd,index,amount,0,4,LOG_TYPE_GSTORAGE);
else {
clif_storageitemremoved(sd,index,0);
@ -637,16 +677,16 @@ void storage_guild_storageadd(struct map_session_data* sd, int index, int amount
* @param amount : number of item to get
* @return 1:success, 0:fail
*/
void storage_guild_storageget(struct map_session_data* sd, int index, int amount)
void gstorage_storageget(struct map_session_data* sd, int index, int amount)
{
struct guild_storage *stor;
unsigned char flag = 0;
nullpo_retv(sd);
nullpo_retv(stor = guild2storage2(sd->status.guild_id));
nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
if(!stor->storage_status)
return;
if(!stor->opened || stor->opened != sd->status.char_id)
return;
if(index < 0 || index >= MAX_GUILD_STORAGE)
return;
@ -655,15 +695,15 @@ void storage_guild_storageget(struct map_session_data* sd, int index, int amount
return;
if(amount < 1 || amount > stor->items[index].amount)
return;
return;
if( stor->lock ) {
storage_guild_storageclose(sd);
if( stor->locked ) {
gstorage_storageclose(sd);
return;
}
if((flag = pc_additem(sd,&stor->items[index],amount,LOG_TYPE_GSTORAGE)) == 0)
guild_storage_delitem(sd,stor,index,amount);
gstorage_delitem(sd,stor,index,amount);
else { // inform fail
clif_storageitemremoved(sd,index,0);
clif_additem(sd,0,0,flag);
@ -675,16 +715,15 @@ void storage_guild_storageget(struct map_session_data* sd, int index, int amount
* @param sd : player
* @param index : index of item in cart
* @param amount : number of item to transfer
* @return 1:fail, 0:success
*/
void storage_guild_storageaddfromcart(struct map_session_data* sd, int index, int amount)
void gstorage_storageaddfromcart(struct map_session_data* sd, int index, int amount)
{
struct guild_storage *stor;
nullpo_retv(sd);
nullpo_retv(stor = guild2storage2(sd->status.guild_id));
nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
if( !stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE )
if( !stor->opened || stor->opened != sd->status.char_id || stor->storage_amount > MAX_GUILD_STORAGE )
return;
if( index < 0 || index >= MAX_CART )
@ -696,7 +735,7 @@ void storage_guild_storageaddfromcart(struct map_session_data* sd, int index, in
if( amount < 1 || amount > sd->status.cart[index].amount )
return;
if(guild_storage_additem(sd,stor,&sd->status.cart[index],amount) == 0)
if(gstorage_additem(sd,stor,&sd->status.cart[index],amount))
pc_cart_delitem(sd,index,amount,0,LOG_TYPE_GSTORAGE);
else {
clif_storageitemremoved(sd,index,0);
@ -711,19 +750,19 @@ void storage_guild_storageaddfromcart(struct map_session_data* sd, int index, in
* @param amount : number of item to transfer
* @return 1:fail, 0:success
*/
void storage_guild_storagegettocart(struct map_session_data* sd, int index, int amount)
void gstorage_storagegettocart(struct map_session_data* sd, int index, int amount)
{
short flag;
struct guild_storage *stor;
nullpo_retv(sd);
nullpo_retv(stor = guild2storage2(sd->status.guild_id));
nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
if(!stor->storage_status)
return;
if(!stor->opened || stor->opened != sd->status.char_id)
return;
if(index < 0 || index >= MAX_GUILD_STORAGE)
return;
return;
if(stor->items[index].nameid == 0)
return;
@ -732,7 +771,7 @@ void storage_guild_storagegettocart(struct map_session_data* sd, int index, int
return;
if((flag = pc_cart_additem(sd,&stor->items[index],amount,LOG_TYPE_GSTORAGE)) == 0)
guild_storage_delitem(sd,stor,index,amount);
gstorage_delitem(sd,stor,index,amount);
else {
clif_storageitemremoved(sd,index,0);
clif_cart_additem_ack(sd,(flag == 1) ? ADDITEM_TO_CART_FAIL_WEIGHT:ADDITEM_TO_CART_FAIL_COUNT);
@ -744,104 +783,93 @@ void storage_guild_storagegettocart(struct map_session_data* sd, int index, int
* @param account_id : account requesting the save
* @param guild_id : guild to take the guild_storage
* @param flag : 1=char quitting, close the storage
* @return 0 : fail (no storage), 1 : success (requested)
* @return False : fail (no storage), True : success (requested)
*/
int storage_guild_storagesave(uint32 account_id, int guild_id, int flag)
bool gstorage_storagesave(uint32 account_id, int guild_id, int flag)
{
struct guild_storage *stor = guild2storage2(guild_id);
struct guild_storage *stor = gstorage_get_storage(guild_id);
if(stor) {
if (stor) {
if (flag) //Char quitting, close it.
stor->storage_status = 0;
stor->opened = 0;
if (stor->dirty)
if (stor->dirty)
intif_send_guild_storage(account_id,stor);
return 1;
return true;
}
return 0;
return false;
}
/**
* ACK save of guild storage
* @param guild_id : guild to use the storage
* @return 0 : fail (no storage), 1 : success
*/
int storage_guild_storagesaved(int guild_id)
void gstorage_storagesaved(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;
return 1;
if ((stor = gstorage_get_storage(guild_id)) != NULL) {
if (stor->dirty && stor->opened == 0) // Storage has been correctly saved.
stor->dirty = false;
}
return 0;
}
/**
* Close storage for player then save it
* @param sd : player
* @return 0
*/
int storage_guild_storageclose(struct map_session_data* sd)
void gstorage_storageclose(struct map_session_data* sd)
{
struct guild_storage *stor;
nullpo_ret(sd);
nullpo_ret(stor = guild2storage2(sd->status.guild_id));
nullpo_retv(sd);
nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
clif_storageclose(sd);
if (stor->storage_status) {
if (stor->opened) {
if (save_settings&CHARSAVE_STORAGE)
chrif_save(sd, 0); //This one also saves the storage. [Skotlex]
else
storage_guild_storagesave(sd->status.account_id, sd->status.guild_id,0);
gstorage_storagesave(sd->status.account_id, sd->status.guild_id,0);
stor->storage_status=0;
stor->opened = 0;
}
sd->state.storage_flag = 0;
return 0;
}
/**
* Close storage for player then save it
* @param sd
* @param flag
* @return
*/
int storage_guild_storage_quit(struct map_session_data* sd, int flag)
void gstorage_storage_quit(struct map_session_data* sd, int flag)
{
struct guild_storage *stor;
nullpo_ret(sd);
nullpo_ret(stor=guild2storage2(sd->status.guild_id));
nullpo_retv(sd);
nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
if(flag) { // Only during a guild break flag is 1 (don't save storage)
if (flag) { // Only during a guild break flag is 1 (don't save storage)
sd->state.storage_flag = 0;
stor->storage_status = 0;
stor->opened = 0;
clif_storageclose(sd);
if (save_settings&CHARSAVE_STORAGE)
chrif_save(sd,0);
return 0;
return;
}
if(stor->storage_status) {
if (stor->opened) {
if (save_settings&CHARSAVE_STORAGE)
chrif_save(sd,0);
else
storage_guild_storagesave(sd->status.account_id,sd->status.guild_id,1);
gstorage_storagesave(sd->status.account_id,sd->status.guild_id,1);
}
sd->state.storage_flag = 0;
stor->storage_status = 0;
return 0;
stor->opened = 0;
}

View File

@ -24,20 +24,21 @@ void do_final_storage(void);
void do_reconnect_storage(void);
void storage_storage_quit(struct map_session_data *sd, int flag);
struct guild_storage* guild2storage(int guild_id);
struct guild_storage *guild2storage2(int guild_id);
int guild_storage_delete(int guild_id);
int storage_guild_storageopen(struct map_session_data *sd);
char guild_storage_additem(struct map_session_data *sd,struct guild_storage *stor,struct item *item_data,int amount);
int guild_storage_delitem(struct map_session_data *sd,struct guild_storage *stor,int n,int amount);
void storage_guild_storageadd(struct map_session_data *sd,int index,int amount);
void storage_guild_storageget(struct map_session_data *sd,int index,int amount);
void storage_guild_storageaddfromcart(struct map_session_data *sd,int index,int amount);
void storage_guild_storagegettocart(struct map_session_data *sd,int index,int amount);
int storage_guild_storageclose(struct map_session_data *sd);
int storage_guild_storage_quit(struct map_session_data *sd,int flag);
int storage_guild_storagesave(uint32 account_id, int guild_id, int flag);
int storage_guild_storagesaved(int guild_id); //Ack from char server that guild store was saved.
struct guild_storage* gstorage_guild2storage(int guild_id);
struct guild_storage *gstorage_get_storage(int guild_id);
void gstorage_delete(int guild_id);
char gstorage_storageopen(struct map_session_data *sd);
bool gstorage_additem(struct map_session_data *sd,struct guild_storage *stor,struct item *item,int amount);
bool gstorage_additem2(struct guild_storage *stor, struct item *item, int amount);
bool gstorage_delitem(struct map_session_data *sd,struct guild_storage *stor,int n,int amount);
void gstorage_storageadd(struct map_session_data *sd,int index,int amount);
void gstorage_storageget(struct map_session_data *sd,int index,int amount);
void gstorage_storageaddfromcart(struct map_session_data *sd,int index,int amount);
void gstorage_storagegettocart(struct map_session_data *sd,int index,int amount);
void gstorage_storageclose(struct map_session_data *sd);
void gstorage_storage_quit(struct map_session_data *sd,int flag);
bool gstorage_storagesave(uint32 account_id, int guild_id, int flag);
void gstorage_storagesaved(int guild_id);
int compare_item(struct item *a, struct item *b);

View File

@ -391,6 +391,9 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount)
return;
}
if (item->bound)
sd->state.isBoundTrading |= (1<<item->bound);
// Locate a trade position
ARR_FIND( 0, 10, trade_i, sd->deal.item[trade_i].index == index || sd->deal.item[trade_i].amount == 0 );
if( trade_i == 10 ) { // No space left
@ -483,7 +486,10 @@ void trade_tradecancel(struct map_session_data *sd)
struct map_session_data *target_sd;
int trade_i;
nullpo_retv(sd);
target_sd = map_id2sd(sd->trade_partner);
sd->state.isBoundTrading = 0;
if(!sd->state.trading) { // Not trade accepted
if( target_sd ) {
@ -546,6 +552,8 @@ void trade_tradecommit(struct map_session_data *sd)
struct map_session_data *tsd;
int trade_i;
nullpo_retv(sd);
if (!sd->state.trading || !sd->state.deal_locked) //Locked should be 1 (pressed ok) before you can press trade.
return;
@ -624,10 +632,12 @@ void trade_tradecommit(struct map_session_data *sd)
sd->state.deal_locked = 0;
sd->trade_partner = 0;
sd->state.trading = 0;
sd->state.isBoundTrading = 0;
tsd->state.deal_locked = 0;
tsd->trade_partner = 0;
tsd->state.trading = 0;
tsd->state.isBoundTrading = 0;
clif_tradecompleted(sd, 0);
clif_tradecompleted(tsd, 0);

View File

@ -2855,7 +2855,7 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file,
if (sd->state.storage_flag == 1)
storage_storage_quit(sd,0);
else if (sd->state.storage_flag == 2)
storage_guild_storage_quit(sd,0);
gstorage_storage_quit(sd,0);
sd->state.storage_flag = 0; //Force close it when being warped.
}