Added Guild Storage Expansion Skill (#3244)

* Fixes #499 and part of #1303.
* Implements Guild Storage Expansion Skill which requires client 2013-12-23 or newer (enable by default depending on client date in src/config/packets.hpp).
* Implements guild storage permission which requires client 2014-02-05 or newer.
* Expanded script command guildopenstorage return values.
This commit is contained in:
Aleos 2018-07-03 08:49:34 -04:00 committed by GitHub
parent e4eddc3e61
commit e13ca63cc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 187 additions and 83 deletions

View File

@ -839,7 +839,11 @@
784: Baby Star Emperor 784: Baby Star Emperor
785: Baby Soul Reaper 785: Baby Soul Reaper
//786-899 free // Guild Storage Expansion Skill
786: The guild does not have a guild storage.
787: You do not have permission to use the guild storage.
//788-899 free
//------------------------------------ //------------------------------------
// More atcommands message // More atcommands message

View File

@ -27,3 +27,4 @@
10012,1,10011,1,0,0,0,0,0,0,0,0 //GD_RESTORE#Restoration# 10012,1,10011,1,0,0,0,0,0,0,0,0 //GD_RESTORE#Restoration#
10013,1,10000,1,10002,1,10004,5,10010,1,10011,1 //GD_EMERGENCYCALL#Urgent Call# 10013,1,10000,1,10002,1,10004,5,10010,1,10011,1 //GD_EMERGENCYCALL#Urgent Call#
10014,1,0,0,0,0,0,0,0,0,0,0 //GD_DEVELOPMENT#Permanent Development# 10014,1,0,0,0,0,0,0,0,0,0,0 //GD_DEVELOPMENT#Permanent Development#
10016,5,0,0,0,0,0,0,0,0,0,0 //GD_GUILD_STORAGE#Guild Storage Expansion#

View File

@ -1553,3 +1553,4 @@
10013,0,0,4,0,0x3,0,1,0,yes,0,0x10,0,none,0,0x40, GD_EMERGENCYCALL,Urgent Call 10013,0,0,4,0,0x3,0,1,0,yes,0,0x10,0,none,0,0x40, GD_EMERGENCYCALL,Urgent Call
10014,0,0,0,0,0,0,1,0,no,0,0x10,0,none,0,0x0, GD_DEVELOPMENT,Permanent Development 10014,0,0,0,0,0,0,1,0,no,0,0x10,0,none,0,0x0, GD_DEVELOPMENT,Permanent Development
10015,0,0,4,0,0x3,0,3,0,yes,0,0x10,0,none,0,0x40, GD_ITEMEMERGENCYCALL,Item Emergency Call 10015,0,0,4,0,0x3,0,3,0,yes,0,0x10,0,none,0,0x40, GD_ITEMEMERGENCYCALL,Item Emergency Call
10016,0,0,0,0,0,0,5,0,no,0,0x10,0,none,0,0x0, GD_GUILD_STORAGE,Guild Storage Expansion

View File

@ -1611,3 +1611,4 @@
10013,0,0,4,0,0x3,0,1,0,yes,0,0x10,0,none,0,0x40, GD_EMERGENCYCALL,Urgent Call 10013,0,0,4,0,0x3,0,1,0,yes,0,0x10,0,none,0,0x40, GD_EMERGENCYCALL,Urgent Call
10014,0,0,0,0,0,0,1,0,no,0,0x10,0,none,0,0x0, GD_DEVELOPMENT,Permanent Development 10014,0,0,0,0,0,0,1,0,no,0,0x10,0,none,0,0x0, GD_DEVELOPMENT,Permanent Development
10015,0,0,4,0,0x3,0,3,0,yes,0,0x10,0,none,0,0x40, GD_ITEMEMERGENCYCALL,Item Emergency Call 10015,0,0,4,0,0x3,0,3,0,yes,0,0x10,0,none,0,0x40, GD_ITEMEMERGENCYCALL,Item Emergency Call
10016,0,0,0,0,0,0,5,0,no,0,0x10,0,none,0,0x0, GD_GUILD_STORAGE,Guild Storage Expansion

View File

@ -5416,12 +5416,15 @@ This will open the Auction window on the client connected to the invoking charac
This function works the same as 'openstorage' but will open a guild storage This function works the same as 'openstorage' but will open a guild storage
window instead for the guild storage of the guild the invoking character belongs window instead for the guild storage of the guild the invoking character belongs
to. This is a function because it returns a value - 0 if the guild storage was to.
opened successfully and 1 if it wasn't. (Notice, it's a ZERO upon success.)
Since guild storage is only accessible to one character at one time, it may fail
if another character is accessing the guild storage at the same time.
This will also fail and return 2 if the character does not belong to any guild. Return values:
GSTORAGE_OPEN - Successfully opened.
GSTORAGE_STORAGE_ALREADY_OPEN - Player storage is already open.
GSTORAGE_ALREADY_OPEN - Guild storage is already open.
GSTORAGE_NO_GUILD - Player is not in a guild.
GSTORAGE_NO_STORAGE - Guild hasn't invested in the Guild Storage Expansion skill (only if OFFICIAL_GUILD_STORAGE is enabled).
GSTORAGE_NO_PERMISSION - Player doesn't have permission to use the guild storage.
--------------------------------------- ---------------------------------------

View File

@ -525,7 +525,7 @@ CREATE TABLE IF NOT EXISTS `guild_position` (
`guild_id` int(9) unsigned NOT NULL default '0', `guild_id` int(9) unsigned NOT NULL default '0',
`position` tinyint(6) unsigned NOT NULL default '0', `position` tinyint(6) unsigned NOT NULL default '0',
`name` varchar(24) NOT NULL default '', `name` varchar(24) NOT NULL default '',
`mode` tinyint(11) unsigned NOT NULL default '0', `mode` smallint(11) unsigned NOT NULL default '0',
`exp_mode` tinyint(11) unsigned NOT NULL default '0', `exp_mode` tinyint(11) unsigned NOT NULL default '0',
PRIMARY KEY (`guild_id`,`position`) PRIMARY KEY (`guild_id`,`position`)
) ENGINE=MyISAM; ) ENGINE=MyISAM;

View File

@ -0,0 +1 @@
ALTER TABLE `guild_position` MODIFY COLUMN `mode` smallint(11) unsigned NOT NULL default '0';

View File

@ -738,7 +738,7 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, enum sto
bool char_memitemdata_from_sql(struct s_storage* p, int max, int id, enum storage_type tableswitch, uint8 stor_id) { bool char_memitemdata_from_sql(struct s_storage* p, int max, int id, enum storage_type tableswitch, uint8 stor_id) {
StringBuf buf; StringBuf buf;
SqlStmt* stmt; SqlStmt* stmt;
int i,j, offset = 0; int i,j, offset = 0, max2;
struct item item, *storage; struct item item, *storage;
const char *tablename, *selectoption, *printname; const char *tablename, *selectoption, *printname;
@ -748,24 +748,28 @@ bool char_memitemdata_from_sql(struct s_storage* p, int max, int id, enum storag
tablename = schema_config.inventory_db; tablename = schema_config.inventory_db;
selectoption = "char_id"; selectoption = "char_id";
storage = p->u.items_inventory; storage = p->u.items_inventory;
max2 = MAX_INVENTORY;
break; break;
case TABLE_CART: case TABLE_CART:
printname = "Cart"; printname = "Cart";
tablename = schema_config.cart_db; tablename = schema_config.cart_db;
selectoption = "char_id"; selectoption = "char_id";
storage = p->u.items_cart; storage = p->u.items_cart;
max2 = MAX_CART;
break; break;
case TABLE_STORAGE: case TABLE_STORAGE:
printname = "Storage"; printname = "Storage";
tablename = inter_premiumStorage_getTableName(stor_id); tablename = inter_premiumStorage_getTableName(stor_id);
selectoption = "account_id"; selectoption = "account_id";
storage = p->u.items_storage; storage = p->u.items_storage;
max2 = inter_premiumStorage_getMax(p->stor_id);
break; break;
case TABLE_GUILD_STORAGE: case TABLE_GUILD_STORAGE:
printname = "Guild Storage"; printname = "Guild Storage";
tablename = schema_config.guild_storage_db; tablename = schema_config.guild_storage_db;
selectoption = "guild_id"; selectoption = "guild_id";
storage = p->u.items_guild; storage = p->u.items_guild;
max2 = inter_guild_storagemax(id);
break; break;
default: default:
ShowError("Invalid table name!\n"); ShowError("Invalid table name!\n");
@ -776,7 +780,7 @@ bool char_memitemdata_from_sql(struct s_storage* p, int max, int id, enum storag
p->id = id; p->id = id;
p->type = tableswitch; p->type = tableswitch;
p->stor_id = stor_id; p->stor_id = stor_id;
p->max_amount = inter_premiumStorage_getMax(p->stor_id); p->max_amount = max2;
stmt = SqlStmt_Malloc(sql_handle); stmt = SqlStmt_Malloc(sql_handle);
if (stmt == NULL) { if (stmt == NULL) {

View File

@ -46,6 +46,7 @@ int mapif_guild_basicinfochanged(int guild_id,int type,const void *data,int len)
int mapif_guild_info(int fd,struct guild *g); int mapif_guild_info(int fd,struct guild *g);
int guild_break_sub(int key,void *data,va_list ap); int guild_break_sub(int key,void *data,va_list ap);
int inter_guild_tosql(struct guild *g,int flag); int inter_guild_tosql(struct guild *g,int flag);
int guild_checkskill(struct guild *g, int id);
int guild_save_timer(int tid, unsigned int tick, int id, intptr_t data) int guild_save_timer(int tid, unsigned int tick, int id, intptr_t data)
{ {
@ -526,6 +527,32 @@ struct guild * inter_guild_fromsql(int guild_id)
return g; return g;
} }
/**
* Get the max storage size of a guild.
* @param guild_id: Guild ID to search
* @return Guild storage max size
*/
uint16 inter_guild_storagemax(int guild_id)
{
#ifdef OFFICIAL_GUILD_STORAGE
struct guild *g = inter_guild_fromsql(guild_id);
uint16 max = 0;
if (!g) {
ShowError("Guild %d not found!\n", guild_id);
return 0;
}
max = guild_checkskill(g, GD_GUILD_STORAGE);
if (max)
max *= 100;
return max;
#else
return MAX_GUILD_STORAGE;
#endif
}
// `guild_castle` (`castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`) // `guild_castle` (`castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`)
int inter_guildcastle_tosql(struct guild_castle *gc) int inter_guildcastle_tosql(struct guild_castle *gc)
{ {
@ -1164,7 +1191,7 @@ int mapif_parse_CreateGuild(int fd,uint32 account_id,char *name,struct guild_mem
g->member[0].modified = GS_MEMBER_MODIFIED; g->member[0].modified = GS_MEMBER_MODIFIED;
// Set default positions // Set default positions
g->position[0].mode=0x11; g->position[0].mode = GUILD_PERM_DEFAULT;
strcpy(g->position[0].name,"GuildMaster"); strcpy(g->position[0].name,"GuildMaster");
strcpy(g->position[MAX_GUILDPOSITION-1].name,"Newbie"); strcpy(g->position[MAX_GUILDPOSITION-1].name,"Newbie");
g->position[0].modified = g->position[MAX_GUILDPOSITION-1].modified = GS_POSITION_MODIFIED; g->position[0].modified = g->position[MAX_GUILDPOSITION-1].modified = GS_POSITION_MODIFIED;

View File

@ -35,5 +35,6 @@ int inter_guild_sex_changed(int guild_id,uint32 account_id,uint32 char_id, short
int inter_guild_charname_changed(int guild_id,uint32 account_id, uint32 char_id, char *name); int inter_guild_charname_changed(int guild_id,uint32 account_id, uint32 char_id, char *name);
int inter_guild_CharOnline(uint32 char_id, int guild_id); int inter_guild_CharOnline(uint32 char_id, int guild_id);
int inter_guild_CharOffline(uint32 char_id, int guild_id); int inter_guild_CharOffline(uint32 char_id, int guild_id);
uint16 inter_guild_storagemax(int guild_id);
#endif /* _INT_GUILD_HPP_ */ #endif /* _INT_GUILD_HPP_ */

View File

@ -19,18 +19,18 @@
/** /**
* Check if storage ID is valid * Check if storage ID is valid
* @param id Storage ID * @param id: Storage ID
* @return True:Valid, False:Invalid * @return True if success or false on failure
**/ */
bool inter_premiumStorage_exists(uint8 id) { bool inter_premiumStorage_exists(uint8 id) {
return interserv_config.storages.find(id) != interserv_config.storages.end(); return interserv_config.storages.find(id) != interserv_config.storages.end();
} }
/** /**
* Get max storage amount * Get max storage amount
* @param id Storage ID * @param id: Storage ID
* @return Max amount * @return Max amount
**/ */
int inter_premiumStorage_getMax(uint8 id) { int inter_premiumStorage_getMax(uint8 id) {
if (inter_premiumStorage_exists(id)) if (inter_premiumStorage_exists(id))
return interserv_config.storages[id]->max_num; return interserv_config.storages[id]->max_num;
@ -39,9 +39,9 @@ int inter_premiumStorage_getMax(uint8 id) {
/** /**
* Get table name of storage * Get table name of storage
* @param id Storage ID * @param id: Storage ID
* @return Table name * @return Table name
**/ */
const char *inter_premiumStorage_getTableName(uint8 id) { const char *inter_premiumStorage_getTableName(uint8 id) {
if (inter_premiumStorage_exists(id)) if (inter_premiumStorage_exists(id))
return interserv_config.storages[id]->table; return interserv_config.storages[id]->table;
@ -50,9 +50,9 @@ const char *inter_premiumStorage_getTableName(uint8 id) {
/** /**
* Get printable name of storage * Get printable name of storage
* @param id Storage ID * @param id: Storage ID
* @return printable name * @return printable name
**/ */
const char *inter_premiumStorage_getPrintableName(uint8 id) { const char *inter_premiumStorage_getPrintableName(uint8 id) {
if (inter_premiumStorage_exists(id)) if (inter_premiumStorage_exists(id))
return interserv_config.storages[id]->name; return interserv_config.storages[id]->name;
@ -95,7 +95,7 @@ int cart_tosql(uint32 char_id, struct s_storage* p)
/** /**
* Fetch inventory entries from table * Fetch inventory entries from table
* @param char_id: Character ID to fetch * @param char_id: Character ID to fetch
* @param p: Inventory list to save the entries * @param p: Inventory entries
* @return True if success, False if failed * @return True if success, False if failed
*/ */
bool inventory_fromsql(uint32 char_id, struct s_storage* p) bool inventory_fromsql(uint32 char_id, struct s_storage* p)
@ -106,7 +106,7 @@ bool inventory_fromsql(uint32 char_id, struct s_storage* p)
/** /**
* Fetch cart entries from table * Fetch cart entries from table
* @param char_id: Character ID to fetch * @param char_id: Character ID to fetch
* @param p: Cart list to save the entries * @param p: Cart entries
* @return True if success, False if failed * @return True if success, False if failed
*/ */
bool cart_fromsql(uint32 char_id, struct s_storage* p) bool cart_fromsql(uint32 char_id, struct s_storage* p)
@ -116,8 +116,8 @@ bool cart_fromsql(uint32 char_id, struct s_storage* p)
/** /**
* Fetch storage entries from table * Fetch storage entries from table
* @param char_id: Character ID to fetch * @param account_id: Account ID to fetch
* @param p: Storage list to save the entries * @param p: Storage entries
* @param stor_id: Storage ID * @param stor_id: Storage ID
* @return True if success, False if failed * @return True if success, False if failed
*/ */
@ -128,9 +128,9 @@ bool storage_fromsql(uint32 account_id, struct s_storage* p)
/** /**
* Save guild_storage data to sql * Save guild_storage data to sql
* @param guild_id: Character ID to save * @param guild_id: Guild ID to save
* @param p: Guild Storage list to save the entries * @param p: Guild Storage entries
* @return 0 if success, or error count * @return True if success, False if failed
*/ */
bool guild_storage_tosql(int guild_id, struct s_storage* p) bool guild_storage_tosql(int guild_id, struct s_storage* p)
{ {
@ -140,8 +140,8 @@ bool guild_storage_tosql(int guild_id, struct s_storage* p)
/** /**
* Fetch guild_storage entries from table * Fetch guild_storage entries from table
* @param char_id: Character ID to fetch * @param guild_id: Guild ID to fetch
* @param p: Storage list to save the entries * @param p: Guild Storage entries
* @return True if success, False if failed * @return True if success, False if failed
*/ */
bool guild_storage_fromsql(int guild_id, struct s_storage* p) bool guild_storage_fromsql(int guild_id, struct s_storage* p)
@ -181,6 +181,14 @@ void inter_storage_sql_final(void)
//--------------------------------------------------------- //---------------------------------------------------------
// packet from map server // packet from map server
/**
* Send guild storage data to the map server
* @param fd: Map server's fd
* @param account_id: Account ID requesting
* @param guild_id: Guild ID requesting
* @param flag: Additional parameters
* @return True on success or false on failure
*/
bool mapif_load_guild_storage(int fd,uint32 account_id,int guild_id, char flag) bool mapif_load_guild_storage(int fd,uint32 account_id,int guild_id, char flag)
{ {
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", schema_config.guild_db, guild_id) ) if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", schema_config.guild_db, guild_id) )
@ -195,7 +203,7 @@ bool mapif_load_guild_storage(int fd,uint32 account_id,int guild_id, char flag)
WFIFOB(fd,12) = flag; //1 open storage, 0 don't open WFIFOB(fd,12) = flag; //1 open storage, 0 don't open
guild_storage_fromsql(guild_id, (struct s_storage*)WFIFOP(fd,13)); guild_storage_fromsql(guild_id, (struct s_storage*)WFIFOP(fd,13));
WFIFOSET(fd, WFIFOW(fd,2)); WFIFOSET(fd, WFIFOW(fd,2));
return false; return true;
} }
// guild does not exist // guild does not exist
Sql_FreeResult(sql_handle); Sql_FreeResult(sql_handle);
@ -205,7 +213,7 @@ bool mapif_load_guild_storage(int fd,uint32 account_id,int guild_id, char flag)
WFIFOL(fd,4) = account_id; WFIFOL(fd,4) = account_id;
WFIFOL(fd,8) = 0; WFIFOL(fd,8) = 0;
WFIFOSET(fd, 12); WFIFOSET(fd, 12);
return true; return false;
} }
void mapif_save_guild_storage_ack(int fd,uint32 account_id,int guild_id,int fail) void mapif_save_guild_storage_ack(int fd,uint32 account_id,int guild_id,int fail)
@ -227,6 +235,11 @@ void mapif_parse_LoadGuildStorage(int fd)
mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6),1); mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6),1);
} }
/**
* Save guild storage data from map server
* @param fd: Map server's fd
* @return True on success or false on failure
*/
bool mapif_parse_SaveGuildStorage(int fd) bool mapif_parse_SaveGuildStorage(int fd)
{ {
int guild_id; int guild_id;

View File

@ -64,7 +64,7 @@
#define MAX_GUILDPOSITION 20 ///Increased max guild positions to accomodate for all members [Valaris] (removed) [PoW] #define MAX_GUILDPOSITION 20 ///Increased max guild positions to accomodate for all members [Valaris] (removed) [PoW]
#define MAX_GUILDEXPULSION 32 ///Max Guild expulsion #define MAX_GUILDEXPULSION 32 ///Max Guild expulsion
#define MAX_GUILDALLIANCE 16 ///Max Guild alliance #define MAX_GUILDALLIANCE 16 ///Max Guild alliance
#define MAX_GUILDSKILL 15 ///Increased max guild skills because of new skills [Sara-chan] #define MAX_GUILDSKILL 17 ///Max Guild skills
#define MAX_GUILDLEVEL 50 ///Max Guild level #define MAX_GUILDLEVEL 50 ///Max Guild level
#define MAX_GUARDIANS 8 ///Local max per castle. If this value is increased, need to add more fields on MySQL `guild_castle` table [Skotlex] #define MAX_GUARDIANS 8 ///Local max per castle. If this value is increased, need to add more fields on MySQL `guild_castle` table [Skotlex]
#define MAX_QUEST_OBJECTIVES 3 ///Max quest objectives for a quest #define MAX_QUEST_OBJECTIVES 3 ///Max quest objectives for a quest
@ -370,7 +370,7 @@ struct s_storage {
bool lock; ///< If locked, can't use storage when item bound retrieval bool lock; ///< If locked, can't use storage when item bound retrieval
uint32 id; ///< Account ID / Character ID / Guild ID (owner of storage) uint32 id; ///< Account ID / Character ID / Guild ID (owner of storage)
enum storage_type type; ///< Type of storage (inventory, cart, storage, guild storage) enum storage_type type; ///< Type of storage (inventory, cart, storage, guild storage)
uint16 max_amount; uint16 max_amount; ///< Maximum amount of items in storage
uint8 stor_id; ///< Storage ID uint8 stor_id; ///< Storage ID
struct { struct {
unsigned get : 1; unsigned get : 1;
@ -701,6 +701,20 @@ struct guild_castle {
int temp_guardians_max; int temp_guardians_max;
}; };
/// Guild Permissions
enum e_guild_permission {
GUILD_PERM_INVITE = 0x001,
GUILD_PERM_EXPEL = 0x010,
#if PACKETVER >= 20140205
GUILD_PERM_STORAGE = 0x100,
GUILD_PERM_ALL = GUILD_PERM_INVITE|GUILD_PERM_EXPEL|GUILD_PERM_STORAGE,
#else
GUILD_PERM_ALL = GUILD_PERM_INVITE|GUILD_PERM_EXPEL,
#endif
GUILD_PERM_MASK = GUILD_PERM_ALL,
GUILD_PERM_DEFAULT = GUILD_PERM_ALL,
};
struct fame_list { struct fame_list {
int id; int id;
int fame; int fame;
@ -742,6 +756,7 @@ enum e_guild_skill {
GD_EMERGENCYCALL=10013, GD_EMERGENCYCALL=10013,
GD_DEVELOPMENT=10014, GD_DEVELOPMENT=10014,
GD_ITEMEMERGENCYCALL=10015, GD_ITEMEMERGENCYCALL=10015,
GD_GUILD_STORAGE=10016,
GD_MAX, GD_MAX,
}; };

View File

@ -43,6 +43,12 @@
#endif #endif
#endif #endif
/// Comment to disable the official Guild Storage skill.
/// When enabled, this will set the guild storage size to the level of the skill * 100.
#if PACKETVER >= 20131223
#define OFFICIAL_GUILD_STORAGE
#endif
#ifndef DUMP_UNKNOWN_PACKET #ifndef DUMP_UNKNOWN_PACKET
//#define DUMP_UNKNOWN_PACKET //#define DUMP_UNKNOWN_PACKET
#endif #endif

View File

@ -919,31 +919,29 @@ ACMD_FUNC(guildstorage)
{ {
nullpo_retr(-1, sd); nullpo_retr(-1, sd);
if (!sd->status.guild_id) {
clif_displaymessage(fd, msg_txt(sd,252)); // You are not in a guild.
return -1;
}
if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading) if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading)
return -1; return -1;
if (sd->state.storage_flag == 1) { switch (storage_guild_storageopen(sd)) {
case GSTORAGE_OPEN:
clif_displaymessage(fd, msg_txt(sd, 920)); // Guild storage opened.
break;
case GSTORAGE_STORAGE_ALREADY_OPEN:
clif_displaymessage(fd, msg_txt(sd, 250)); // You have already opened your storage. Close it first. clif_displaymessage(fd, msg_txt(sd, 250)); // You have already opened your storage. Close it first.
return -1; return -1;
} case GSTORAGE_ALREADY_OPEN:
if (sd->state.storage_flag == 2) {
clif_displaymessage(fd, msg_txt(sd, 251)); // You have already opened your guild storage. Close it first. clif_displaymessage(fd, msg_txt(sd, 251)); // You have already opened your guild storage. Close it first.
return -1; return -1;
} case GSTORAGE_NO_GUILD:
clif_displaymessage(fd, msg_txt(sd, 252)); // You are not in a guild.
if (sd->state.storage_flag == 3) { return -1;
clif_displaymessage(fd, msg_txt(sd,250)); // You have already opened your storage. Close it first. case GSTORAGE_NO_STORAGE:
clif_displaymessage(fd, msg_txt(sd, 786)); // The guild does not have a guild storage.
return -1;
case GSTORAGE_NO_PERMISSION:
clif_displaymessage(fd, msg_txt(sd, 787)); // You do not have permission to use the guild storage.
return -1; return -1;
} }
storage_guild_storageopen(sd);
clif_displaymessage(fd, msg_txt(sd,920)); // Guild storage opened.
return 0; return 0;
} }

View File

@ -594,7 +594,7 @@ int guild_invite(struct map_session_data *sd, struct map_session_data *tsd) {
if(tsd==NULL || g==NULL) if(tsd==NULL || g==NULL)
return 0; return 0;
if( (i=guild_getposition(sd))<0 || !(g->position[i].mode&0x0001) ) if( (i=guild_getposition(sd))<0 || !(g->position[i].mode&GUILD_PERM_INVITE) )
return 0; //Invite permission. return 0; //Invite permission.
if(!battle_config.invite_request_check) { if(!battle_config.invite_request_check) {
@ -806,7 +806,7 @@ int guild_expulsion(struct map_session_data* sd, int guild_id, uint32 account_id
if(sd->status.guild_id!=guild_id) if(sd->status.guild_id!=guild_id)
return 0; return 0;
if( (ps=guild_getposition(sd))<0 || !(g->position[ps].mode&0x0010) ) if( (ps=guild_getposition(sd))<0 || !(g->position[ps].mode&GUILD_PERM_EXPEL) )
return 0; //Expulsion permission return 0; //Expulsion permission
//Can't leave inside guild castles. //Can't leave inside guild castles.
@ -1092,14 +1092,11 @@ int guild_memberposition_changed(struct guild *g,int idx,int pos) {
/*==================================================== /*====================================================
* Change guild title or member * Change guild title or member
*---------------------------------------------------*/ *---------------------------------------------------*/
int guild_change_position(int guild_id,int idx, int guild_change_position(int guild_id,int idx, int mode, int exp_mode, const char *name) {
int mode,int exp_mode,const char *name) {
struct guild_position p; struct guild_position p;
exp_mode = cap_value(exp_mode, 0, battle_config.guild_exp_limit); exp_mode = cap_value(exp_mode, 0, battle_config.guild_exp_limit);
//Mode 0x01 <- Invite p.mode = mode&GUILD_PERM_ALL;
//Mode 0x10 <- Expel.
p.mode=mode&0x11;
p.exp_mode=exp_mode; p.exp_mode=exp_mode;
safestrncpy(p.name,name,NAME_LENGTH); safestrncpy(p.name,name,NAME_LENGTH);
return intif_guild_position(guild_id,idx,&p); return intif_guild_position(guild_id,idx,&p);

View File

@ -7228,6 +7228,14 @@
export_constant(MD_STATUS_IMMUNE); export_constant(MD_STATUS_IMMUNE);
export_constant(MD_SKILL_IMMUNE); export_constant(MD_SKILL_IMMUNE);
/* guild storage flags */
export_constant(GSTORAGE_OPEN);
export_constant(GSTORAGE_STORAGE_ALREADY_OPEN);
export_constant(GSTORAGE_ALREADY_OPEN);
export_constant(GSTORAGE_NO_GUILD);
export_constant(GSTORAGE_NO_STORAGE);
export_constant(GSTORAGE_NO_PERMISSION);
#undef export_constant #undef export_constant
#undef export_constant2 #undef export_constant2
#undef export_parameter #undef export_parameter

View File

@ -589,34 +589,48 @@ char storage_guild_storageopen(struct map_session_data* sd)
nullpo_ret(sd); nullpo_ret(sd);
if(sd->status.guild_id <= 0) if(sd->status.guild_id <= 0)
return 2; return GSTORAGE_NO_GUILD;
if(sd->state.storage_flag) #ifdef OFFICIAL_GUILD_STORAGE
return 1; //Can't open both storages at a time. if (!guild_checkskill(sd->guild, GD_GUILD_STORAGE))
return GSTORAGE_NO_STORAGE; // Can't open storage if the guild has not learned the skill
#endif
if (sd->state.storage_flag == 2)
return GSTORAGE_ALREADY_OPEN; // Guild storage already open.
else if (sd->state.storage_flag)
return GSTORAGE_STORAGE_ALREADY_OPEN; // Can't open both storages at a time.
#if PACKETVER >= 20140205
int pos;
if ((pos = guild_getposition(sd)) < 0 || !(sd->guild->position[pos].mode&GUILD_PERM_STORAGE))
return GSTORAGE_NO_PERMISSION; // Guild member doesn't have permission
#endif
if( !pc_can_give_items(sd) ) { //check is this GM level can open guild storage and store items [Lupus] if( !pc_can_give_items(sd) ) { //check is this GM level can open guild storage and store items [Lupus]
clif_displaymessage(sd->fd, msg_txt(sd,246)); clif_displaymessage(sd->fd, msg_txt(sd,246));
return 1; return GSTORAGE_ALREADY_OPEN;
} }
if((gstor = guild2storage2(sd->status.guild_id)) == NULL) { if((gstor = guild2storage2(sd->status.guild_id)) == NULL) {
intif_request_guild_storage(sd->status.account_id,sd->status.guild_id); intif_request_guild_storage(sd->status.account_id,sd->status.guild_id);
return 0; return GSTORAGE_OPEN;
} }
if(gstor->status) if(gstor->status)
return 1; return GSTORAGE_ALREADY_OPEN;
if( gstor->lock ) if( gstor->lock )
return 1; return GSTORAGE_ALREADY_OPEN;
gstor->status = true; gstor->status = true;
sd->state.storage_flag = 2; sd->state.storage_flag = 2;
storage_sortitem(gstor->u.items_guild, ARRAYLENGTH(gstor->u.items_guild)); storage_sortitem(gstor->u.items_guild, ARRAYLENGTH(gstor->u.items_guild));
clif_storagelist(sd, gstor->u.items_guild, ARRAYLENGTH(gstor->u.items_guild), "Guild Storage"); clif_storagelist(sd, gstor->u.items_guild, ARRAYLENGTH(gstor->u.items_guild), "Guild Storage");
clif_updatestorageamount(sd, gstor->amount, MAX_GUILD_STORAGE); clif_updatestorageamount(sd, gstor->amount, gstor->max_amount);
return 0; return GSTORAGE_OPEN;
} }
/** /**
@ -655,7 +669,7 @@ bool storage_guild_additem(struct map_session_data* sd, struct s_storage* stor,
} }
if(itemdb_isstackable2(id)) { //Stackable if(itemdb_isstackable2(id)) { //Stackable
for(i = 0; i < MAX_GUILD_STORAGE; i++) { for(i = 0; i < stor->max_amount; i++) {
if(compare_item(&stor->u.items_guild[i], item_data)) { if(compare_item(&stor->u.items_guild[i], item_data)) {
if( amount > MAX_AMOUNT - stor->u.items_guild[i].amount || ( id->stack.guildstorage && amount > id->stack.amount - stor->u.items_guild[i].amount ) ) if( amount > MAX_AMOUNT - stor->u.items_guild[i].amount || ( id->stack.guildstorage && amount > id->stack.amount - stor->u.items_guild[i].amount ) )
return false; return false;
@ -669,15 +683,15 @@ bool storage_guild_additem(struct map_session_data* sd, struct s_storage* stor,
} }
//Add item //Add item
for(i = 0; i < MAX_GUILD_STORAGE && stor->u.items_guild[i].nameid; i++); for(i = 0; i < stor->max_amount && stor->u.items_guild[i].nameid; i++);
if(i >= MAX_GUILD_STORAGE) if(i >= stor->max_amount)
return false; return false;
memcpy(&stor->u.items_guild[i],item_data,sizeof(stor->u.items_guild[0])); memcpy(&stor->u.items_guild[i],item_data,sizeof(stor->u.items_guild[0]));
stor->u.items_guild[i].amount = amount; stor->u.items_guild[i].amount = amount;
stor->amount++; stor->amount++;
clif_storageitemadded(sd,&stor->u.items_guild[i],i,amount); clif_storageitemadded(sd,&stor->u.items_guild[i],i,amount);
clif_updatestorageamount(sd, stor->amount, MAX_GUILD_STORAGE); clif_updatestorageamount(sd, stor->amount, stor->max_amount);
stor->dirty = true; stor->dirty = true;
return true; return true;
} }
@ -703,7 +717,7 @@ bool storage_guild_additem2(struct s_storage* stor, struct item* item, int amoun
return false; return false;
if (itemdb_isstackable2(id)) { // Stackable if (itemdb_isstackable2(id)) { // Stackable
for (i = 0; i < MAX_GUILD_STORAGE; i++) { for (i = 0; i < stor->max_amount; i++) {
if (compare_item(&stor->u.items_guild[i], item)) { if (compare_item(&stor->u.items_guild[i], item)) {
// Set the amount, make it fit with max amount // Set the amount, make it fit with max amount
amount = min(amount, ((id->stack.guildstorage) ? id->stack.amount : MAX_AMOUNT) - stor->u.items_guild[i].amount); amount = min(amount, ((id->stack.guildstorage) ? id->stack.amount : MAX_AMOUNT) - stor->u.items_guild[i].amount);
@ -717,8 +731,8 @@ bool storage_guild_additem2(struct s_storage* stor, struct item* item, int amoun
} }
// Add the item // Add the item
for (i = 0; i < MAX_GUILD_STORAGE && stor->u.items_guild[i].nameid; i++); for (i = 0; i < stor->max_amount && stor->u.items_guild[i].nameid; i++);
if (i >= MAX_GUILD_STORAGE) if (i >= stor->max_amount)
return false; return false;
memcpy(&stor->u.items_guild[i], item, sizeof(stor->u.items_guild[0])); memcpy(&stor->u.items_guild[i], item, sizeof(stor->u.items_guild[0]));
@ -749,7 +763,7 @@ bool storage_guild_delitem(struct map_session_data* sd, struct s_storage* stor,
if(!stor->u.items_guild[n].amount) { if(!stor->u.items_guild[n].amount) {
memset(&stor->u.items_guild[n],0,sizeof(stor->u.items_guild[0])); memset(&stor->u.items_guild[n],0,sizeof(stor->u.items_guild[0]));
stor->amount--; stor->amount--;
clif_updatestorageamount(sd, stor->amount, MAX_GUILD_STORAGE); clif_updatestorageamount(sd, stor->amount, stor->max_amount);
} }
clif_storageitemremoved(sd,n,amount); clif_storageitemremoved(sd,n,amount);
@ -769,7 +783,7 @@ void storage_guild_storageadd(struct map_session_data* sd, int index, int amount
nullpo_retv(sd); nullpo_retv(sd);
nullpo_retv(stor = guild2storage2(sd->status.guild_id)); nullpo_retv(stor = guild2storage2(sd->status.guild_id));
if( !stor->status || stor->amount > MAX_GUILD_STORAGE ) if( !stor->status || stor->amount > stor->max_amount )
return; return;
if( index < 0 || index >= MAX_INVENTORY ) if( index < 0 || index >= MAX_INVENTORY )
@ -812,7 +826,7 @@ void storage_guild_storageget(struct map_session_data* sd, int index, int amount
if(!stor->status) if(!stor->status)
return; return;
if(index < 0 || index >= MAX_GUILD_STORAGE) if(index < 0 || index >= stor->max_amount)
return; return;
if(stor->u.items_guild[index].nameid == 0) if(stor->u.items_guild[index].nameid == 0)
@ -847,7 +861,7 @@ void storage_guild_storageaddfromcart(struct map_session_data* sd, int index, in
nullpo_retv(sd); nullpo_retv(sd);
nullpo_retv(stor = guild2storage2(sd->status.guild_id)); nullpo_retv(stor = guild2storage2(sd->status.guild_id));
if( !stor->status || stor->amount > MAX_GUILD_STORAGE ) if( !stor->status || stor->amount > stor->max_amount )
return; return;
if( index < 0 || index >= MAX_CART ) if( index < 0 || index >= MAX_CART )
@ -885,7 +899,7 @@ void storage_guild_storagegettocart(struct map_session_data* sd, int index, int
if(!stor->status) if(!stor->status)
return; return;
if(index < 0 || index >= MAX_GUILD_STORAGE) if(index < 0 || index >= stor->max_amount)
return; return;
if(stor->u.items_guild[index].nameid == 0) if(stor->u.items_guild[index].nameid == 0)

View File

@ -20,6 +20,16 @@ enum e_storage_add {
STORAGE_ADD_INVALID, STORAGE_ADD_INVALID,
}; };
/// Guild storage flags
enum e_guild_storage_flags : uint8 {
GSTORAGE_OPEN = 0,
GSTORAGE_STORAGE_ALREADY_OPEN,
GSTORAGE_ALREADY_OPEN,
GSTORAGE_NO_GUILD,
GSTORAGE_NO_STORAGE,
GSTORAGE_NO_PERMISSION
};
const char *storage_getName(uint8 id); const char *storage_getName(uint8 id);
bool storage_exists(uint8 id); bool storage_exists(uint8 id);