From c5c3381b0b8b0b59c669d474acf749db82d7edb1 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Thu, 10 Oct 2013 12:25:22 -0300 Subject: Introducing Bank Support http://hercules.ws/board/topic/2455-introducing-bank-support/ Thanks to Yommy, Haru! Signed-off-by: shennetsind --- sql-files/main.sql | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'sql-files/main.sql') diff --git a/sql-files/main.sql b/sql-files/main.sql index 0e9dc5b67..dcb735129 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -657,6 +657,7 @@ INSERT INTO `sql_updates` (`timestamp`) VALUES (1362794218); INSERT INTO `sql_updates` (`timestamp`) VALUES (1364409316); INSERT INTO `sql_updates` (`timestamp`) VALUES (1366075474); INSERT INTO `sql_updates` (`timestamp`) VALUES (1366078541); +INSERT INTO `sql_updates` (`timestamp`) VALUES (1381354728); -- -- Table structure for table `sstatus` @@ -691,6 +692,10 @@ CREATE TABLE IF NOT EXISTS `storage` ( KEY `account_id` (`account_id`) ) ENGINE=MyISAM; +-- +-- Table structure for table `interreg` +-- + CREATE TABLE IF NOT EXISTS `interreg` ( `varname` varchar(11) NOT NULL, `value` varchar(20) NOT NULL, @@ -698,3 +703,14 @@ CREATE TABLE IF NOT EXISTS `interreg` ( ) ENGINE=InnoDB; INSERT INTO `interreg` (`varname`, `value`) VALUES ('unique_id', '0'); + +-- +-- Table structure for table `account_data` +-- + +CREATE TABLE IF NOT EXISTS `account_data` ( + `account_id` int(11) unsigned NOT NULL default '0', + `bank_vault` int(11) unsigned NOT NULL default '0', + PRIMARY KEY (`account_id`) +) ENGINE=MyISAM; + -- cgit v1.2.3-70-g09d2 From 80dfb11513812c7007f55c4b4b72c7f1cbee47f4 Mon Sep 17 00:00:00 2001 From: Streusel Date: Thu, 10 Oct 2013 11:03:04 -0700 Subject: Follow up c5c3381 Thanks to QQfoolsorellina --- sql-files/main.sql | 1 + 1 file changed, 1 insertion(+) (limited to 'sql-files/main.sql') diff --git a/sql-files/main.sql b/sql-files/main.sql index dcb735129..1f654ed14 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -658,6 +658,7 @@ INSERT INTO `sql_updates` (`timestamp`) VALUES (1364409316); INSERT INTO `sql_updates` (`timestamp`) VALUES (1366075474); INSERT INTO `sql_updates` (`timestamp`) VALUES (1366078541); INSERT INTO `sql_updates` (`timestamp`) VALUES (1381354728); +INSERT INTO `sql_updates` (`timestamp`) VALUES (1381423003); -- -- Table structure for table `sstatus` -- cgit v1.2.3-70-g09d2 From baef78f7954fa4e6fa2449f2c7de92a901c7f5f3 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Sun, 27 Oct 2013 14:58:44 -0200 Subject: Shadows System Base http://hercules.ws/board/topic/581-implement-the-shadows-system/ Special Thanks to Yommy for all the client data, Haru for making it possible to get it out and rosfus for the details on the feature. Shadows Feature requires packetver 20120925 or newer. ---------- Also: Updated all packets related to the shadows system, improved memory/processing of inventory/cart/storage/viewequip packets Signed-off-by: shennetsind --- doc/item_db.txt | 6 + sql-files/main.sql | 9 +- sql-files/upgrades/2013-10-27--16-47.sql | 6 + sql-files/upgrades/index.txt | 3 +- src/char/char.c | 8 +- src/common/mmo.h | 10 +- src/map/clif.c | 614 ++++++++++++------------------- src/map/clif.h | 27 +- src/map/packets_struct.h | 255 ++++++++++++- src/map/pc.c | 22 +- src/map/pc.h | 43 ++- src/map/pet.c | 2 +- 12 files changed, 584 insertions(+), 421 deletions(-) create mode 100644 sql-files/upgrades/2013-10-27--16-47.sql (limited to 'sql-files/main.sql') diff --git a/doc/item_db.txt b/doc/item_db.txt index 1cf92977c..145a17a33 100644 --- a/doc/item_db.txt +++ b/doc/item_db.txt @@ -105,6 +105,12 @@ Loc: Equipment's placement. Values are: 2^11 2048 = Costume Mid Headgear 2^12 4096 = Costume Low Headgear 2^13 8192 = Costume Garment/Robe + 2^16 65536 = Shadow Armor + 2^17 131072 = Shadow Weapon + 2^18 262144 = Shadow Shield + 2^18 524288 = Shadow Shoes + 2^20 1048576 = Shadow Accessory 2 + 2^21 2097152 = Shadow Accessory 1 wLV: Weapon level. diff --git a/sql-files/main.sql b/sql-files/main.sql index 1f654ed14..8bd28c414 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -34,7 +34,7 @@ CREATE TABLE IF NOT EXISTS `cart_inventory` ( `char_id` int(11) NOT NULL default '0', `nameid` int(11) NOT NULL default '0', `amount` int(11) NOT NULL default '0', - `equip` mediumint(8) unsigned NOT NULL default '0', + `equip` int(11) unsigned NOT NULL default '0', `identify` smallint(6) NOT NULL default '0', `refine` tinyint(3) unsigned NOT NULL default '0', `attribute` tinyint(4) NOT NULL default '0', @@ -332,7 +332,7 @@ CREATE TABLE IF NOT EXISTS `guild_storage` ( `guild_id` int(11) unsigned NOT NULL default '0', `nameid` int(11) unsigned NOT NULL default '0', `amount` int(11) unsigned NOT NULL default '0', - `equip` mediumint(8) unsigned NOT NULL default '0', + `equip` int(11) unsigned NOT NULL default '0', `identify` smallint(6) unsigned NOT NULL default '0', `refine` tinyint(3) unsigned NOT NULL default '0', `attribute` tinyint(4) unsigned NOT NULL default '0', @@ -395,7 +395,7 @@ CREATE TABLE IF NOT EXISTS `inventory` ( `char_id` int(11) unsigned NOT NULL default '0', `nameid` int(11) unsigned NOT NULL default '0', `amount` int(11) unsigned NOT NULL default '0', - `equip` mediumint(8) unsigned NOT NULL default '0', + `equip` int(11) unsigned NOT NULL default '0', `identify` smallint(6) NOT NULL default '0', `refine` tinyint(3) unsigned NOT NULL default '0', `attribute` tinyint(4) unsigned NOT NULL default '0', @@ -659,6 +659,7 @@ INSERT INTO `sql_updates` (`timestamp`) VALUES (1366075474); INSERT INTO `sql_updates` (`timestamp`) VALUES (1366078541); INSERT INTO `sql_updates` (`timestamp`) VALUES (1381354728); INSERT INTO `sql_updates` (`timestamp`) VALUES (1381423003); +INSERT INTO `sql_updates` (`timestamp`) VALUES (1382892428); -- -- Table structure for table `sstatus` @@ -679,7 +680,7 @@ CREATE TABLE IF NOT EXISTS `storage` ( `account_id` int(11) unsigned NOT NULL default '0', `nameid` int(11) unsigned NOT NULL default '0', `amount` smallint(11) unsigned NOT NULL default '0', - `equip` mediumint(8) unsigned NOT NULL default '0', + `equip` int(11) unsigned NOT NULL default '0', `identify` smallint(6) unsigned NOT NULL default '0', `refine` tinyint(3) unsigned NOT NULL default '0', `attribute` tinyint(4) unsigned NOT NULL default '0', diff --git a/sql-files/upgrades/2013-10-27--16-47.sql b/sql-files/upgrades/2013-10-27--16-47.sql new file mode 100644 index 000000000..e1a4a28f2 --- /dev/null +++ b/sql-files/upgrades/2013-10-27--16-47.sql @@ -0,0 +1,6 @@ +#1382892428 +ALTER TABLE `inventory` MODIFY `equip` int(11) unsigned NOT NULL default '0'; +ALTER TABLE `storage` MODIFY `equip` int(11) unsigned NOT NULL default '0'; +ALTER TABLE `cart_inventory` MODIFY `equip` int(11) unsigned NOT NULL default '0'; +ALTER TABLE `guild_storage` MODIFY `equip` int(11) unsigned NOT NULL default '0'; +INSERT INTO `sql_updates` (`timestamp`) VALUES (1382892428); \ No newline at end of file diff --git a/sql-files/upgrades/index.txt b/sql-files/upgrades/index.txt index 2996a07f0..4afcc5a0d 100644 --- a/sql-files/upgrades/index.txt +++ b/sql-files/upgrades/index.txt @@ -5,4 +5,5 @@ 2013-03-09--01-56.sql 2013-04-16--01-24.sql 2013-10-09--21-38.sql -2013-10-10--16-36.sql \ No newline at end of file +2013-10-10--16-36.sql +2013-10-27--16-47.sql \ No newline at end of file diff --git a/src/char/char.c b/src/char/char.c index 0b35c0143..950211894 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -742,7 +742,7 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); - SQL->StmtBindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 3, SQLDT_UINT, &item.equip, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); @@ -886,7 +886,7 @@ int inventory_to_sql(const struct item items[], int max, int id) { SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); - SQL->StmtBindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 3, SQLDT_UINT, &item.equip, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); @@ -1241,7 +1241,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything || SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_UINT, &tmp_item.equip, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) @@ -1272,7 +1272,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything || SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_UINT, &tmp_item.equip, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) diff --git a/src/common/mmo.h b/src/common/mmo.h index 7977042d8..9281314dc 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -216,7 +216,7 @@ struct item { int id; short nameid; short amount; - unsigned short equip; // Location(s) where item is equipped (using enum equip_pos for bitmasking). + unsigned int equip; // Location(s) where item is equipped (using enum equip_pos for bitmasking). char identify; char refine; char attribute; @@ -838,6 +838,14 @@ enum ammo_type { A_THROWWEAPON //9 }; +/* packet size constant for itemlist */ +#if MAX_INVENTORY > MAX_STORAGE && MAX_INVENTORY > MAX_CART +#define MAX_ITEMLIST MAX_INVENTORY +#elif MAX_CART > MAX_INVENTORY && MAX_CART > MAX_STORAGE +#define MAX_ITEMLIST MAX_CART +#else +#define MAX_ITEMLIST MAX_STORAGE +#endif // sanity checks... #if MAX_ZENY > INT_MAX diff --git a/src/map/clif.c b/src/map/clif.c index 94fc6f7a7..a5cbbfd22 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -56,6 +56,13 @@ struct clif_interface clif_s; +/* re-usable */ +static struct packet_itemlist_normal itemlist_normal; +static struct packet_itemlist_equip itemlist_equip; +static struct packet_storelist_normal storelist_normal; +static struct packet_storelist_equip storelist_equip; +static struct packet_viewequip_ack viewequip_list; + //#define DUMP_UNKNOWN_PACKET //#define DUMP_INVALID_PACKET @@ -707,7 +714,7 @@ void clif_dropflooritem(struct flooritem_data* fitem) { #if PACKETVER >= 20130000 /* not sure date */ p.type = itemtype(itemdb_type(fitem->item_data.nameid)); #endif - p.IsIdentified = fitem->item_data.identify; + p.IsIdentified = fitem->item_data.identify ? 1 : 0; p.xPos = fitem->bl.x; p.yPos = fitem->bl.y; p.subX = fitem->subx; @@ -900,7 +907,7 @@ void clif_set_unit_idle2(struct block_list* bl, struct map_session_data *tsd, en p.GEmblemVer = status->get_emblem_id(bl); p.honor = (sd) ? sd->status.manner : 0; p.virtue = (sc) ? sc->opt3 : 0; - p.isPKModeON = (sd) ? sd->status.karma : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; p.sex = vd->sex; WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl)); p.xSize = p.ySize = (sd) ? 5 : 0; @@ -965,7 +972,7 @@ void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enu p.GEmblemVer = status->get_emblem_id(bl); p.honor = (sd) ? sd->status.manner : 0; p.virtue = (sc) ? sc->opt3 : 0; - p.isPKModeON = (sd) ? sd->status.karma : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; p.sex = vd->sex; WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl)); p.xSize = p.ySize = (sd) ? 5 : 0; @@ -1034,7 +1041,7 @@ void clif_spawn_unit2(struct block_list* bl, enum send_target target) { p.headpalette = vd->hair_color; p.bodypalette = vd->cloth_color; p.headDir = (sd)? sd->head_dir : 0; - p.isPKModeON = (sd) ? sd->status.karma : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; p.sex = vd->sex; WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl)); p.xSize = p.ySize = (sd) ? 5 : 0; @@ -1094,7 +1101,7 @@ void clif_spawn_unit(struct block_list* bl, enum send_target target) { p.GEmblemVer = status->get_emblem_id(bl); p.honor = (sd) ? sd->status.manner : 0; p.virtue = (sc) ? sc->opt3 : 0; - p.isPKModeON = (sd) ? sd->status.karma : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; p.sex = vd->sex; WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl)); p.xSize = p.ySize = (sd) ? 5 : 0; @@ -1172,7 +1179,7 @@ void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, p.GEmblemVer = status->get_emblem_id(bl); p.honor = (sd) ? sd->status.manner : 0; p.virtue = (sc) ? sc->opt3 : 0; - p.isPKModeON = (sd) ? sd->status.karma : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; p.sex = vd->sex; WBUFPOS2(&p.MoveData[0],0,bl->x,bl->y,ud->to_x,ud->to_y,8,8); p.xSize = p.ySize = (sd) ? 5 : 0; @@ -2198,8 +2205,8 @@ void clif_additem(struct map_session_data *sd, int n, int amount, int fail) { else p.nameid = sd->status.inventory[n].nameid; - p.IsIdentified = sd->status.inventory[n].identify; - p.IsDamaged = sd->status.inventory[n].attribute; + p.IsIdentified = sd->status.inventory[n].identify ? 1 : 0; + p.IsDamaged = sd->status.inventory[n].attribute ? 1 : 0; p.refiningLevel =sd->status.inventory[n].refine; clif->addcards2(&p.slot.card[0], &sd->status.inventory[n]); p.location = pc->equippoint(sd,n); @@ -2290,311 +2297,220 @@ void clif_item_sub(unsigned char *buf, int n, struct item *i, struct item_data * } } -//Unified inventory function which sends all of the inventory (requires two packets, one for equipable items and one for stackable ones. [Skotlex] -void clif_inventorylist(struct map_session_data *sd) { - int i,n,ne,arrow=-1; - unsigned char *buf; - unsigned char *bufe; +void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *i, struct item_data *id, int eqp_pos) { -#if PACKETVER < 5 - const int s = 10; //Entry size. -#elif PACKETVER < 20080102 - const int s = 18; -#else - const int s = 22; -#endif -#if PACKETVER < 20071002 - const int se = 20; -#elif PACKETVER < 20100629 - const int se = 26; -#else - const int se = 28; -#endif + p->index = idx; + + if (id->view_id > 0) + p->ITID = id->view_id; + else + p->ITID = i->nameid; - buf = (unsigned char*)aMalloc(MAX_INVENTORY * s + 4); - bufe = (unsigned char*)aMalloc(MAX_INVENTORY * se + 4); + p->type = itemtype(id->type); - for( i = 0, n = 0, ne = 0; i < MAX_INVENTORY; i++ ) - { - if( sd->status.inventory[i].nameid <=0 || sd->inventory_data[i] == NULL ) - continue; +#if PACKETVER < 20120925 + p->IsIdentified = i->identify ? 1 : 0; +#endif + + p->location = eqp_pos; + p->WearState = i->equip; + +#if PACKETVER < 20120925 + p->IsDamaged = i->attribute ? 1 : 0; +#endif + p->RefiningLevel = i->refine; + + clif->addcards2(&p->slot.card[0], i); - if( !itemdb->isstackable2(sd->inventory_data[i]) ) - { //Non-stackable (Equippable) - WBUFW(bufe,ne*se+4)=i+2; - clif->item_sub(bufe, ne*se+6, &sd->status.inventory[i], sd->inventory_data[i], pc->equippoint(sd,i)); - clif->addcards(WBUFP(bufe, ne*se+16), &sd->status.inventory[i]); #if PACKETVER >= 20071002 - WBUFL(bufe,ne*se+24)=sd->status.inventory[i].expire_time; - WBUFW(bufe,ne*se+28)=0; //Unknown + p->HireExpireDate = i->expire_time; +#endif + +#if PACKETVER >= 20080102 + p->bindOnEquipType = 0; #endif + #if PACKETVER >= 20100629 - if (sd->inventory_data[i]->equip&EQP_VISIBLE) - WBUFW(bufe,ne*se+30)= sd->inventory_data[i]->look; - else - WBUFW(bufe,ne*se+30)=0; + p->wItemSpriteNumber = id->equip&EQP_VISIBLE ? id->look : 0; #endif - ne++; - } - else - { //Stackable. - WBUFW(buf,n*s+4)=i+2; - clif->item_sub(buf, n*s+6, &sd->status.inventory[i], sd->inventory_data[i], -2); - if( sd->inventory_data[i]->equip == EQP_AMMO && sd->status.inventory[i].equip ) - arrow=i; + +#if PACKETVER >= 20120925 + p->Flag.IsIdentified = i->identify ? 1 : 0; + p->Flag.IsDamaged = i->attribute ? 1 : 0; + p->Flag.PlaceETCTab = i->favorite ? 1 : 0; + p->Flag.SpareBits = 0; +#endif +} +void clif_item_normal(short idx, struct NORMALITEM_INFO *p, struct item *i, struct item_data *id) { + p->index = idx; + + if (id->view_id > 0) + p->ITID = id->view_id; + else + p->ITID = i->nameid; + + p->type = itemtype(id->type); + +#if PACKETVER < 20120925 + p->IsIdentified = i->identify ? 1 : 0; +#endif + + p->count = i->amount; + p->WearState = id->equip; + #if PACKETVER >= 5 - clif->addcards(WBUFP(buf, n*s+14), &sd->status.inventory[i]); + clif->addcards2(&p->slot.card[0], i); #endif + #if PACKETVER >= 20080102 - WBUFL(buf,n*s+22)=sd->status.inventory[i].expire_time; + p->HireExpireDate = i->expire_time; #endif - n++; - } - } - if( n ) { -#if PACKETVER < 5 - WBUFW(buf,0)=0xa3; -#elif PACKETVER < 20080102 - WBUFW(buf,0)=0x1ee; -#else - WBUFW(buf,0)=0x2e8; + +#if PACKETVER >= 20120925 + p->Flag.IsIdentified = i->identify ? 1 : 0; + p->Flag.PlaceETCTab = i->favorite ? 1 : 0; + p->Flag.SpareBits = 0; #endif - WBUFW(buf,2)=4+n*s; - clif->send(buf, WBUFW(buf,2), &sd->bl, SELF); +} +void clif_inventorylist(struct map_session_data *sd) { + int i, normal = 0, equip = 0; + + for( i = 0; i < MAX_INVENTORY; i++ ) { + + if( sd->status.inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL ) + continue; + if( !itemdb->isstackable2(sd->inventory_data[i]) ) //Non-stackable (Equippable) + clif_item_equip(i+2,&itemlist_equip.list[equip++],&sd->status.inventory[i],sd->inventory_data[i],pc->equippoint(sd,i)); + else //Stackable (Normal) + clif_item_normal(i+2,&itemlist_normal.list[normal++],&sd->status.inventory[i],sd->inventory_data[i]); + } + + if( normal ) { + itemlist_normal.PacketType = inventorylistnormalType; + itemlist_normal.PacketLength = 4 + (sizeof(struct NORMALITEM_INFO) * normal); + + clif->send(&itemlist_normal, itemlist_normal.PacketLength, &sd->bl, SELF); } - if( arrow >= 0 ) - clif->arrowequip(sd,arrow); + + if( sd->equip_index[EQI_AMMO] >= 0 ) + clif->arrowequip(sd,sd->equip_index[EQI_AMMO]); + + if( equip ) { + itemlist_equip.PacketType = inventorylistequipType; + itemlist_equip.PacketLength = 4 + (sizeof(struct EQUIPITEM_INFO) * equip); - if( ne ) { -#if PACKETVER < 20071002 - WBUFW(bufe,0)=0xa4; -#else - WBUFW(bufe,0)=0x2d0; -#endif - WBUFW(bufe,2)=4+ne*se; - clif->send(bufe, WBUFW(bufe,2), &sd->bl, SELF); + clif->send(&itemlist_equip, itemlist_equip.PacketLength, &sd->bl, SELF); } -#if PACKETVER >= 20111122 +/* on 20120925 onwards this is a field on clif_item_equip/normal */ +#if PACKETVER >= 20111122 && PACKETVER < 20120925 for( i = 0; i < MAX_INVENTORY; i++ ) { if( sd->status.inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL ) continue; - + if ( sd->status.inventory[i].favorite ) clif->favorite_item(sd, i); } #endif - - if( buf ) aFree(buf); - if( bufe ) aFree(bufe); } //Required when items break/get-repaired. Only sends equippable item list. -void clif_equiplist(struct map_session_data *sd) -{ - int i,n,fd = sd->fd; - unsigned char *buf; -#if PACKETVER < 20071002 - const int cmd = 20; -#elif PACKETVER < 20100629 - const int cmd = 26; -#else - const int cmd = 28; -#endif - - WFIFOHEAD(fd, MAX_INVENTORY * cmd + 4); - buf = WFIFOP(fd,0); - - for(i=0,n=0;istatus.inventory[i].nameid <=0 || sd->inventory_data[i] == NULL) +void clif_equiplist(struct map_session_data *sd) { + int i, equip = 0; + + for( i = 0; i < MAX_INVENTORY; i++ ) { + + if( sd->status.inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL ) continue; - - if(itemdb->isstackable2(sd->inventory_data[i])) + if( !itemdb->isstackable2(sd->inventory_data[i]) ) //Non-stackable (Equippable) + clif_item_equip(i+2,&itemlist_equip.list[equip++],&sd->status.inventory[i],sd->inventory_data[i],pc->equippoint(sd,i)); + } + + if( equip ) { + itemlist_equip.PacketType = inventorylistequipType; + itemlist_equip.PacketLength = 4 + (sizeof(struct EQUIPITEM_INFO) * equip); + + clif->send(&itemlist_equip, itemlist_equip.PacketLength, &sd->bl, SELF); + } + + /* on 20120925 onwards this is a field on clif_item_equip */ +#if PACKETVER >= 20111122 && PACKETVER < 20120925 + for( i = 0; i < MAX_INVENTORY; i++ ) { + if( sd->status.inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL ) continue; - //Equippable - WBUFW(buf,n*cmd+4)=i+2; - clif->item_sub(buf, n*cmd+6, &sd->status.inventory[i], sd->inventory_data[i], pc->equippoint(sd,i)); - clif->addcards(WBUFP(buf, n*cmd+16), &sd->status.inventory[i]); -#if PACKETVER >= 20071002 - WBUFL(buf,n*cmd+24)=sd->status.inventory[i].expire_time; - WBUFW(buf,n*cmd+28)=0; //Unknown -#endif -#if PACKETVER >= 20100629 - if (sd->inventory_data[i]->equip&EQP_VISIBLE) - WBUFW(buf,n*cmd+30)= sd->inventory_data[i]->look; - else - WBUFW(buf,n*cmd+30)=0; -#endif - n++; + + if ( sd->status.inventory[i].favorite ) + clif->favorite_item(sd, i); } - if (n) { -#if PACKETVER < 20071002 - WBUFW(buf,0)=0xa4; -#else - WBUFW(buf,0)=0x2d0; #endif - WBUFW(buf,2)=4+n*cmd; - WFIFOSET(fd,WFIFOW(fd,2)); - } } -void clif_storagelist(struct map_session_data* sd, struct item* items, int items_length) -{ +void clif_storagelist(struct map_session_data* sd, struct item* items, int items_length) { + int i, normal = 0, equip = 0; struct item_data *id; - int i,n,ne; - unsigned char *buf; - unsigned char *bufe; -#if PACKETVER < 5 - const int s = 10; //Entry size. -#elif PACKETVER < 20080102 - const int s = 18; -#else - const int s = 22; -#endif -#if PACKETVER < 20071002 - const int cmd = 20; -#elif PACKETVER < 20100629 - const int cmd = 26; -#else - const int cmd = 28; -#endif - - buf = (unsigned char*)aMalloc(items_length * s + 4); - bufe = (unsigned char*)aMalloc(items_length * cmd + 4); - - for( i = 0, n = 0, ne = 0; i < items_length; i++ ) - { + + for( i = 0; i < items_length; i++ ) { + if( items[i].nameid <= 0 ) continue; + id = itemdb->search(items[i].nameid); - if( !itemdb->isstackable2(id) ) - { //Equippable - WBUFW(bufe,ne*cmd+4)=i+1; - clif->item_sub(bufe, ne*cmd+6, &items[i], id, id->equip); - clif->addcards(WBUFP(bufe, ne*cmd+16), &items[i]); -#if PACKETVER >= 20071002 - WBUFL(bufe,ne*cmd+24)=items[i].expire_time; - WBUFW(bufe,ne*cmd+28)=0; //Unknown -#endif - ne++; - } - else - { //Stackable - WBUFW(buf,n*s+4)=i+1; - clif->item_sub(buf, n*s+6, &items[i], id,-1); -#if PACKETVER >= 5 - clif->addcards(WBUFP(buf,n*s+14), &items[i]); -#endif -#if PACKETVER >= 20080102 - WBUFL(buf,n*s+22)=items[i].expire_time; -#endif - n++; - } + if( !itemdb->isstackable2(id) ) //Non-stackable (Equippable) + clif_item_equip(i+1,&storelist_equip.list[equip++],&items[i],id,id->equip); + else //Stackable (Normal) + clif_item_normal(i+1,&storelist_normal.list[normal++],&items[i],id); } - if( n ) - { -#if PACKETVER < 5 - WBUFW(buf,0)=0xa5; -#elif PACKETVER < 20080102 - WBUFW(buf,0)=0x1f0; -#else - WBUFW(buf,0)=0x2ea; -#endif - WBUFW(buf,2)=4+n*s; - clif->send(buf, WBUFW(buf,2), &sd->bl, SELF); + + if( normal ) { + storelist_normal.PacketType = storagelistnormalType; + storelist_normal.PacketLength = ( sizeof( storelist_normal ) - ARRAYLENGTH( storelist_normal.list ) ) + (sizeof(struct NORMALITEM_INFO) * normal); +#if PACKETVER >= 20120925 + safestrncpy(storelist_normal.name, "Storage", NAME_LENGTH); +#endif + clif->send(&storelist_normal, storelist_normal.PacketLength, &sd->bl, SELF); } - if( ne ) - { -#if PACKETVER < 20071002 - WBUFW(bufe,0)=0xa6; -#else - WBUFW(bufe,0)=0x2d1; + + if( equip ) { + storelist_equip.PacketType = storagelistequipType; + storelist_equip.PacketLength = ( sizeof( storelist_equip ) - ARRAYLENGTH( storelist_equip.list ) ) + (sizeof(struct EQUIPITEM_INFO) * equip); + +#if PACKETVER >= 20120925 + safestrncpy(storelist_equip.name, "Storage", NAME_LENGTH); #endif - WBUFW(bufe,2)=4+ne*cmd; - clif->send(bufe, WBUFW(bufe,2), &sd->bl, SELF); + + clif->send(&storelist_equip, storelist_equip.PacketLength, &sd->bl, SELF); } - - if( buf ) aFree(buf); - if( bufe ) aFree(bufe); } -void clif_cartlist(struct map_session_data *sd) -{ +void clif_cartlist(struct map_session_data *sd) { + int i, normal = 0, equip = 0; struct item_data *id; - int i,n,ne; - unsigned char *buf; - unsigned char *bufe; -#if PACKETVER < 5 - const int s = 10; //Entry size. -#elif PACKETVER < 20080102 - const int s = 18; -#else - const int s = 22; -#endif -#if PACKETVER < 20071002 - const int cmd = 20; -#elif PACKETVER < 20100629 - const int cmd = 26; -#else - const int cmd = 28; -#endif - - buf = (unsigned char*)aMalloc(MAX_CART * s + 4); - bufe = (unsigned char*)aMalloc(MAX_CART * cmd + 4); - - for( i = 0, n = 0, ne = 0; i < MAX_CART; i++ ) - { + + for( i = 0; i < MAX_CART; i++ ) { + if( sd->status.cart[i].nameid <= 0 ) continue; + id = itemdb->search(sd->status.cart[i].nameid); - if( !itemdb->isstackable2(id) ) - { //Equippable - WBUFW(bufe,ne*cmd+4)=i+2; - clif->item_sub(bufe, ne*cmd+6, &sd->status.cart[i], id, id->equip); - clif->addcards(WBUFP(bufe, ne*cmd+16), &sd->status.cart[i]); -#if PACKETVER >= 20071002 - WBUFL(bufe,ne*cmd+24)=sd->status.cart[i].expire_time; - WBUFW(bufe,ne*cmd+28)=0; //Unknown -#endif - ne++; - } - else - { //Stackable - WBUFW(buf,n*s+4)=i+2; - clif->item_sub(buf, n*s+6, &sd->status.cart[i], id,-1); -#if PACKETVER >= 5 - clif->addcards(WBUFP(buf,n*s+14), &sd->status.cart[i]); -#endif -#if PACKETVER >= 20080102 - WBUFL(buf,n*s+22)=sd->status.cart[i].expire_time; -#endif - n++; - } + + if( !itemdb->isstackable2(id) ) //Non-stackable (Equippable) + clif_item_equip(i+2,&itemlist_equip.list[equip++],&sd->status.cart[i],id,id->equip); + else //Stackable (Normal) + clif_item_normal(i+2,&itemlist_normal.list[normal++],&sd->status.cart[i],id); } - if( n ) - { -#if PACKETVER < 5 - WBUFW(buf,0)=0x123; -#elif PACKETVER < 20080102 - WBUFW(buf,0)=0x1ef; -#else - WBUFW(buf,0)=0x2e9; -#endif - WBUFW(buf,2)=4+n*s; - clif->send(buf, WBUFW(buf,2), &sd->bl, SELF); + + if( normal ) { + itemlist_normal.PacketType = cartlistnormalType; + itemlist_normal.PacketLength = 4 + (sizeof(struct NORMALITEM_INFO) * normal); + + clif->send(&itemlist_normal, itemlist_normal.PacketLength, &sd->bl, SELF); } - if( ne ) - { -#if PACKETVER < 20071002 - WBUFW(bufe,0)=0x122; -#else - WBUFW(bufe,0)=0x2d2; -#endif - WBUFW(bufe,2)=4+ne*cmd; - clif->send(bufe, WBUFW(bufe,2), &sd->bl, SELF); + + if( equip ) { + itemlist_equip.PacketType = cartlistequipType; + itemlist_equip.PacketLength = 4 + (sizeof(struct EQUIPITEM_INFO) * equip); + + clif->send(&itemlist_equip, itemlist_equip.PacketLength, &sd->bl, SELF); } - - if( buf ) aFree(buf); - if( bufe ) aFree(bufe); } @@ -3528,52 +3444,39 @@ void clif_statusupack(struct map_session_data *sd,int type,int ok,int val) /// Notifies the client about the result of a request to equip an item (ZC_REQ_WEAR_EQUIP_ACK). /// 00aa .W .W .B /// 00aa .W .W .W .B (PACKETVER >= 20100629) -/// result: -/// 0 = failure -/// 1 = success -/// 2 = failure due to low level -void clif_equipitemack(struct map_session_data *sd,int n,int pos,int ok) -{ - int fd; +void clif_equipitemack(struct map_session_data *sd,int n,int pos,enum e_EQUIP_ITEM_ACK result) { + struct packet_equipitem_ack p; nullpo_retv(sd); - fd=sd->fd; - WFIFOHEAD(fd,packet_len(0xaa)); - WFIFOW(fd,0)=0xaa; - WFIFOW(fd,2)=n+2; - WFIFOW(fd,4)=pos; -#if PACKETVER < 20100629 - WFIFOB(fd,6)=ok; -#else - if (ok && sd->inventory_data[n]->equip&EQP_VISIBLE) - WFIFOW(fd,6)=sd->inventory_data[n]->look; + p.PacketType = equipitemackType; + p.index = n+2; + p.wearLocation = pos; +#if PACKETVER >= 20100629 + if (result == EIA_SUCCESS && sd->inventory_data[n]->equip&EQP_VISIBLE) + p.wItemSpriteNumber = sd->inventory_data[n]->look; else - WFIFOW(fd,6)=0; - WFIFOB(fd,8)=ok; + p.wItemSpriteNumber = 0; #endif - WFIFOSET(fd,packet_len(0xaa)); + p.result = (unsigned char)result; + + clif->send(&p, sizeof(p), &sd->bl, SELF); } /// Notifies the client about the result of a request to take off an item (ZC_REQ_TAKEOFF_EQUIP_ACK). /// 00ac .W .W .B -/// result: -/// 0 = failure -/// 1 = success -void clif_unequipitemack(struct map_session_data *sd,int n,int pos,int ok) -{ - int fd; +void clif_unequipitemack(struct map_session_data *sd,int n,int pos,enum e_UNEQUIP_ITEM_ACK result) { + struct packet_unequipitem_ack p; nullpo_retv(sd); - fd=sd->fd; - WFIFOHEAD(fd,packet_len(0xac)); - WFIFOW(fd,0)=0xac; - WFIFOW(fd,2)=n+2; - WFIFOW(fd,4)=pos; - WFIFOB(fd,6)=ok; - WFIFOSET(fd,packet_len(0xac)); + p.PacketType = unequipitemackType; + p.index = n+2; + p.wearLocation = pos; + p.result = (unsigned char)result; + + clif->send(&p, sizeof(p), &sd->bl, SELF); } @@ -8951,69 +8854,41 @@ void clif_equpcheckbox(struct map_session_data* sd) /// 02d7 .W .24B .W .W .W .W .W .W .W .B {equip item}.28B* (ZC_EQUIPWIN_MICROSCOPE, PACKETVER >= 20100629) /// 0859 .W .24B .W .W .W .W .W .W .W .B {equip item}.28B* (ZC_EQUIPWIN_MICROSCOPE2, PACKETVER >= 20101124) /// 0859 .W .24B .W .W .W .W .W .W .W .W .B {equip item}.28B* (ZC_EQUIPWIN_MICROSCOPE2, PACKETVER >= 20110111) -void clif_viewequip_ack(struct map_session_data* sd, struct map_session_data* tsd) -{ - uint8* buf; - int i, n, fd, offset = 0; -#if PACKETVER < 20100629 - const int s = 26; -#else - const int s = 28; -#endif +void clif_viewequip_ack(struct map_session_data* sd, struct map_session_data* tsd) { + int i, k, equip = 0; + nullpo_retv(sd); nullpo_retv(tsd); - fd = sd->fd; - - WFIFOHEAD(fd, MAX_INVENTORY * s + 43); - buf = WFIFOP(fd,0); + + for( i = 0; i < EQI_MAX; i++ ) { + if( (k = tsd->equip_index[i]) >= 0 ) { + + if (tsd->status.inventory[k].nameid <= 0 || tsd->inventory_data[k] == NULL) // Item doesn't exist + continue; + + clif_item_equip(k+2,&viewequip_list.list[equip++],&tsd->status.inventory[k],tsd->inventory_data[k],pc->equippoint(tsd,k)); -#if PACKETVER < 20101124 - WBUFW(buf, 0) = 0x2d7; -#else - WBUFW(buf, 0) = 0x859; -#endif - safestrncpy((char*)WBUFP(buf, 4), tsd->status.name, NAME_LENGTH); - WBUFW(buf,28) = tsd->status.class_; - WBUFW(buf,30) = tsd->vd.hair_style; - WBUFW(buf,32) = tsd->vd.head_bottom; - WBUFW(buf,34) = tsd->vd.head_mid; - WBUFW(buf,36) = tsd->vd.head_top; + } + } + + viewequip_list.PacketType = viewequipackType; + viewequip_list.PacketLength = ( sizeof( viewequip_list ) - ARRAYLENGTH( viewequip_list.list ) ) + ( sizeof(struct EQUIPITEM_INFO) * equip ); + + safestrncpy(viewequip_list.characterName, tsd->status.name, NAME_LENGTH); + + viewequip_list.job = tsd->status.class_; + viewequip_list.head = tsd->vd.hair_style; + viewequip_list.accessory = tsd->vd.head_bottom; + viewequip_list.accessory2 = tsd->vd.head_mid; + viewequip_list.accessory3 = tsd->vd.head_top; #if PACKETVER >= 20110111 - WBUFW(buf,38) = tsd->vd.robe; - offset+= 2; - buf = WBUFP(buf,2); + viewequip_list.robe = tsd->vd.robe; #endif - WBUFW(buf,38) = tsd->vd.hair_color; - WBUFW(buf,40) = tsd->vd.cloth_color; - WBUFB(buf,42) = tsd->vd.sex; - - for(i=0,n=0; i < MAX_INVENTORY; i++) - { - if (tsd->status.inventory[i].nameid <= 0 || tsd->inventory_data[i] == NULL) // Item doesn't exist - continue; - if (!itemdb->isequip2(tsd->inventory_data[i])) // Is not equippable - continue; - - // Inventory position - WBUFW(buf, n*s+43) = i + 2; - // Add refine, identify flag, element, etc. - clif->item_sub(WBUFP(buf,0), n*s+45, &tsd->status.inventory[i], tsd->inventory_data[i], pc->equippoint(tsd, i)); - // Add cards - clif->addcards(WBUFP(buf, n*s+55), &tsd->status.inventory[i]); - // Expiration date stuff, if all of those are set to 0 then the client doesn't show anything related (6 bytes) - WBUFL(buf, n*s+63) = tsd->status.inventory[i].expire_time; - WBUFW(buf, n*s+67) = 0; -#if PACKETVER >= 20100629 - if (tsd->inventory_data[i]->equip&EQP_VISIBLE) - WBUFW(buf, n*s+69) = tsd->inventory_data[i]->look; - else - WBUFW(buf, n*s+69) = 0; -#endif - n++; - } - - WFIFOW(fd, 2) = 43+offset+n*s; // Set length - WFIFOSET(fd, WFIFOW(fd, 2)); + viewequip_list.headpalette = tsd->vd.hair_color; + viewequip_list.bodypalette = tsd->vd.cloth_color; + viewequip_list.sex = tsd->vd.sex; + + clif->send(&viewequip_list, viewequip_list.PacketLength, &sd->bl, SELF); } @@ -10653,18 +10528,19 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd) /// Request to equip an item (CZ_REQ_WEAR_EQUIP). /// 00a9 .W .W -void clif_parse_EquipItem(int fd,struct map_session_data *sd) -{ - int index; +/// 0998 .W .L +void clif_parse_EquipItem(int fd,struct map_session_data *sd) { + struct packet_equip_item *p = P2PTR(fd); if(pc_isdead(sd)) { clif->clearunit_area(&sd->bl,CLR_DEAD); return; } - index = RFIFOW(fd,2)-2; - if (index < 0 || index >= MAX_INVENTORY) - return; //Out of bounds check. + p->index = p->index - 2; + if (p->index >= MAX_INVENTORY) + return; //Out of bounds check. + if( sd->npc_id ) { if ( !sd->npc_item_flag ) return; @@ -10673,16 +10549,16 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd) else if ( pc_cant_act2(sd) || sd->state.prerefining ) return; - if(!sd->status.inventory[index].identify) { - clif->equipitemack(sd,index,0,0); // fail + if(!sd->status.inventory[p->index].identify) { + clif->equipitemack(sd,p->index,0,EIA_FAIL);// fail return; } - if(!sd->inventory_data[index]) + if(!sd->inventory_data[p->index]) return; - if(sd->inventory_data[index]->type == IT_PETARMOR){ - pet->equipitem(sd,index); + if(sd->inventory_data[p->index]->type == IT_PETARMOR){ + pet->equipitem(sd,p->index); return; } @@ -10690,10 +10566,10 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd) sd->idletime = last_tick; //Client doesn't send the position for ammo. - if(sd->inventory_data[index]->type == IT_AMMO) - pc->equipitem(sd,index,EQP_AMMO); + if(sd->inventory_data[p->index]->type == IT_AMMO) + pc->equipitem(sd,p->index,EQP_AMMO); else - pc->equipitem(sd,index,RFIFOW(fd,4)); + pc->equipitem(sd,p->index,p->wearLocation); } void clif_hercules_chsys_delete(struct hChSysCh *channel) { diff --git a/src/map/clif.h b/src/map/clif.h index 6d0fc0fc1..57e55c3f7 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -426,6 +426,29 @@ enum e_BANKING_WITHDRAW_ACK { BWA_UNKNOWN_ERROR = 0x2, }; +/* because the client devs were replaced by monkeys. */ +enum e_EQUIP_ITEM_ACK { +#if PACKETVER >= 20120925 + EIA_SUCCESS = 0x0, + EIA_FAIL_LV = 0x1, + EIA_FAIL = 0x2, +#else + EIA_SUCCESS = 0x1, + EIA_FAIL_LV = 0x2, + EIA_FAIL = 0x0, +#endif +}; + +/* and again. because the client devs were replaced by monkeys. */ +enum e_UNEQUIP_ITEM_ACK { +#if PACKETVER >= 20120925 + UIA_SUCCESS = 0x0, + UIA_FAIL = 0x1, +#else + UIA_SUCCESS = 0x1, + UIA_FAIL = 0x0, +#endif +}; /** * Structures @@ -529,8 +552,8 @@ struct clif_interface { void (*use_card) (struct map_session_data *sd,int idx); void (*cart_additem) (struct map_session_data *sd,int n,int amount,int fail); void (*cart_delitem) (struct map_session_data *sd,int n,int amount); - void (*equipitemack) (struct map_session_data *sd,int n,int pos,int ok); - void (*unequipitemack) (struct map_session_data *sd,int n,int pos,int ok); + void (*equipitemack) (struct map_session_data *sd,int n,int pos,enum e_EQUIP_ITEM_ACK result); + void (*unequipitemack) (struct map_session_data *sd,int n,int pos,enum e_UNEQUIP_ITEM_ACK result); void (*useitemack) (struct map_session_data *sd,int index,int amount,bool ok); void (*addcards) (unsigned char* buf, struct item* item); void (*addcards2) (unsigned short *cards, struct item* item); diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index 9d7282c92..e9a582582 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -8,12 +8,6 @@ #include "../common/mmo.h" -/** - * structs for data - */ -struct EQUIPSLOTINFO { - unsigned short card[4]; -}; /** * **/ @@ -110,6 +104,82 @@ enum packet_headers { dropflooritemType = 0x84b, #else dropflooritemType = 0x9e, +#endif +#if PACKETVER >= 20120925 + inventorylistnormalType = 0x991, +#elif PACKETVER >= 20080102 + inventorylistnormalType = 0x2e8, +#elif PACKETVER >= 20071002 + inventorylistnormalType = 0x1ee, +#else + inventorylistnormalType = 0xa3, +#endif +#if PACKETVER >= 20120925 + inventorylistequipType = 0x992, +#elif PACKETVER >= 20080102 + inventorylistequipType = 0x2d0, +#elif PACKETVER >= 20071002 + inventorylistequipType = 0x295, +#else + inventorylistequipType = 0xa4, +#endif +#if PACKETVER >= 20120925 + storagelistnormalType = 0x995, +#elif PACKETVER >= 20080102 + storagelistnormalType = 0x2ea, +#elif PACKETVER >= 20071002 + storagelistnormalType = 0x295, +#else + storagelistnormalType = 0xa5, +#endif +#if PACKETVER >= 20120925 + storagelistequipType = 0x996, +#elif PACKETVER >= 20080102 + storagelistequipType = 0x2d1, +#elif PACKETVER >= 20071002 + storagelistequipType = 0x296, +#else + storagelistequipType = 0xa6, +#endif +#if PACKETVER >= 20120925 + cartlistnormalType = 0x993, +#elif PACKETVER >= 20080102 + cartlistnormalType = 0x2e9, +#elif PACKETVER >= 20071002 + cartlistnormalType = 0x1ef, +#else + cartlistnormalType = 0x123, +#endif +#if PACKETVER >= 20120925 + cartlistequipType = 0x994, +#elif PACKETVER >= 20080102 + cartlistequipType = 0x2d2, +#elif PACKETVER >= 20071002 + cartlistequipType = 0x297, +#else + cartlistequipType = 0x122, +#endif +#if PACKETVER >= 20120925 + equipitemType = 0x998, +#else + equipitemType = 0xa9, +#endif +#if PACKETVER >= 20120925 + equipitemackType = 0x999, +#else + equipitemackType = 0xaa, +#endif +#if PACKETVER >= 20120925 + unequipitemackType = 0x99a, +#else + unequipitemackType = 0xac, +#endif +#if PACKETVER >= 20120925 + viewequipackType = 0x997, +#elif PACKETVER >= 20101124 + viewequipackType = 0x859, +#else + viewequipackType = 0x2d7, #endif monsterhpType = 0x977, maptypeproperty2Type = 0x99b, @@ -117,6 +187,79 @@ enum packet_headers { #pragma pack(push, 1) +/** + * structs for data + */ +struct EQUIPSLOTINFO { + unsigned short card[4]; +} __attribute__((packed)); + +struct NORMALITEM_INFO { + short index; + unsigned short ITID; + unsigned char type; +#if PACKETVER < 20120925 + uint8 IsIdentified; +#endif + short count; +#if PACKETVER >= 20120925 + unsigned int WearState; +#else + unsigned short WearState; +#endif +#if PACKETVER >= 5 + struct EQUIPSLOTINFO slot; +#endif +#if PACKETVER >= 20080102 + int HireExpireDate; +#endif +#if PACKETVER >= 20120925 + struct { + unsigned int IsIdentified : 1; + unsigned int PlaceETCTab : 1; + unsigned int SpareBits : 6; + } Flag; +#endif +} __attribute__((packed)); + +struct EQUIPITEM_INFO { + short index; + unsigned short ITID; + unsigned char type; +#if PACKETVER < 20120925 + uint8 IsIdentified; +#endif +#if PACKETVER >= 20120925 + unsigned int location; + unsigned int WearState; +#else + unsigned short location; + unsigned short WearState; +#endif +#if PACKETVER < 20120925 + uint8 IsDamaged; +#endif + unsigned char RefiningLevel; + struct EQUIPSLOTINFO slot; +#if PACKETVER >= 20071002 + int HireExpireDate; +#endif +#if PACKETVER >= 20080102 + unsigned short bindOnEquipType; +#endif +#if PACKETVER >= 20100629 + unsigned short wItemSpriteNumber; +#endif +#if PACKETVER >= 20120925 + struct { + unsigned int IsIdentified : 1; + unsigned int IsDamaged : 1; + unsigned int PlaceETCTab : 1; + unsigned int SpareBits : 5; + } Flag; +#endif +} __attribute__((packed)); + struct packet_authok { short PacketType; unsigned int startTime; @@ -147,8 +290,8 @@ struct packet_additem { unsigned short Index; unsigned short count; unsigned short nameid; - bool IsIdentified; - bool IsDamaged; + uint8 IsIdentified; + uint8 IsDamaged; unsigned char refiningLevel; struct EQUIPSLOTINFO slot; #if PACKETVER >= 20120925 @@ -173,7 +316,7 @@ struct packet_dropflooritem { #if PACKETVER >= 20130000 /* not sure date */ unsigned short type; #endif - bool IsIdentified; + uint8 IsIdentified; short xPos; short yPos; unsigned char subX; @@ -205,7 +348,7 @@ struct packet_idle_unit2 { short GEmblemVer; short honor; short virtue; - bool isPKModeON; + uint8 isPKModeON; unsigned char sex; unsigned char PosDir[3]; unsigned char xSize; @@ -233,7 +376,7 @@ struct packet_spawn_unit2 { short headpalette; short bodypalette; short headDir; - bool isPKModeON; + uint8 isPKModeON; unsigned char sex; unsigned char PosDir[3]; unsigned char xSize; @@ -282,7 +425,7 @@ struct packet_spawn_unit { #else short virtue; #endif - bool isPKModeON; + uint8 isPKModeON; unsigned char sex; unsigned char PosDir[3]; unsigned char xSize; @@ -343,7 +486,7 @@ struct packet_unit_walking { #else short virtue; #endif - bool isPKModeON; + uint8 isPKModeON; unsigned char sex; unsigned char MoveData[6]; unsigned char xSize; @@ -401,7 +544,7 @@ struct packet_idle_unit { #else short virtue; #endif - bool isPKModeON; + uint8 isPKModeON; unsigned char sex; unsigned char PosDir[3]; unsigned char xSize; @@ -578,6 +721,90 @@ struct packet_banking_withdraw_ack { int Balance; } __attribute__((packed)); +struct packet_itemlist_normal { + short PacketType; + short PacketLength; + struct NORMALITEM_INFO list[MAX_ITEMLIST]; +} __attribute__((packed)); + +struct packet_itemlist_equip { + short PacketType; + short PacketLength; + struct EQUIPITEM_INFO list[MAX_ITEMLIST]; +} __attribute__((packed)); + +struct packet_storelist_normal { + short PacketType; + short PacketLength; +#if PACKETVER >= 20120925 + char name[NAME_LENGTH]; +#endif + struct NORMALITEM_INFO list[MAX_ITEMLIST]; +} __attribute__((packed)); + +struct packet_storelist_equip { + short PacketType; + short PacketLength; +#if PACKETVER >= 20120925 + char name[NAME_LENGTH]; +#endif + struct EQUIPITEM_INFO list[MAX_ITEMLIST]; +} __attribute__((packed)); + +struct packet_equip_item { + short PacketType; + unsigned short index; +#if PACKETVER >= 20120925 + unsigned int wearLocation; +#else + unsigned short wearLocation; +#endif +} __attribute__((packed)); + +struct packet_equipitem_ack { + short PacketType; + unsigned short index; +#if PACKETVER >= 20120925 + unsigned int wearLocation; +#else + unsigned short wearLocation; +#endif +#if PACKETVER >= 20100629 + unsigned short wItemSpriteNumber; +#endif + unsigned char result; +} __attribute__((packed)); + +struct packet_unequipitem_ack { + short PacketType; + unsigned short index; +#if PACKETVER >= 20120925 + unsigned int wearLocation; +#else + unsigned short wearLocation; +#endif + unsigned char result; +} __attribute__((packed)); + +struct packet_viewequip_ack { + short PacketType; + short PacketLength; + char characterName[NAME_LENGTH]; + short job; + short head; + short accessory; + short accessory2; + short accessory3; +#if PACKETVER >= 20101124 + short robe; +#endif + short headpalette; + short bodypalette; + unsigned char sex; + struct EQUIPITEM_INFO list[MAX_INVENTORY]; +} __attribute__((packed)); + + #pragma pack(pop) #endif /* _PACKETS_STRUCT_H_ */ diff --git a/src/map/pc.c b/src/map/pc.c index b39ae1c59..cbc1ed1d4 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -611,6 +611,8 @@ int pc_equippoint(struct map_session_data *sd,int n) if(ep == EQP_HAND_R && (pc->checkskill(sd,AS_LEFT) > 0 || (sd->class_&MAPID_UPPERMASK) == MAPID_ASSASSIN || (sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO))//Kagerou and Oboro can dual wield daggers. [Rytech] return EQP_ARMS; + if( ep == EQP_SHADOW_SHIELD )/* are there conditions for those? */ + return EQP_SHADOW_WEAPON|EQP_SHADOW_SHIELD; } return ep; } @@ -8526,13 +8528,13 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) nullpo_ret(sd); if( n < 0 || n >= MAX_INVENTORY ) { - clif->equipitemack(sd,0,0,0); + clif->equipitemack(sd,0,0,EIA_FAIL); return 0; } if( DIFF_TICK(sd->canequip_tick,timer->gettick()) > 0 ) { - clif->equipitemack(sd,n,0,0); + clif->equipitemack(sd,n,0,EIA_FAIL); return 0; } @@ -8543,13 +8545,13 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) ShowInfo("equip %d(%d) %x:%x\n",sd->status.inventory[n].nameid,n,id?id->equip:0,req_pos); if(!pc->isequip(sd,n) || !(pos&req_pos) || sd->status.inventory[n].equip != 0 || sd->status.inventory[n].attribute==1 ) { // [Valaris] // FIXME: pc->isequip: equip level failure uses 2 instead of 0 - clif->equipitemack(sd,n,0,0); // fail + clif->equipitemack(sd,n,0,EIA_FAIL); // fail return 0; } if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAY_NIGHT_FEVER]) { - clif->equipitemack(sd,n,0,0); // fail + clif->equipitemack(sd,n,0,EIA_FAIL); // fail return 0; } @@ -8589,7 +8591,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) clif->arrow_fail(sd,3); } else - clif->equipitemack(sd,n,pos,1); + clif->equipitemack(sd,n,pos,EIA_SUCCESS); sd->status.inventory[n].equip=pos; @@ -8738,20 +8740,20 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { nullpo_ret(sd); if( n < 0 || n >= MAX_INVENTORY ) { - clif->unequipitemack(sd,0,0,0); + clif->unequipitemack(sd,0,0,UIA_FAIL); return 0; } // if player is berserk then cannot unequip if (!(flag & 2) && sd->sc.count && (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAY_NIGHT_FEVER])) { - clif->unequipitemack(sd,n,0,0); + clif->unequipitemack(sd,n,0,UIA_FAIL); return 0; } if( !(flag&2) && sd->sc.count && sd->sc.data[SC_KYOUGAKU] ) { - clif->unequipitemack(sd,n,0,0); + clif->unequipitemack(sd,n,0,UIA_FAIL); return 0; } @@ -8759,7 +8761,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { ShowInfo("unequip %d %x:%x\n",n,pc->equippoint(sd,n),sd->status.inventory[n].equip); if(!sd->status.inventory[n].equip){ //Nothing to unequip - clif->unequipitemack(sd,n,0,0); + clif->unequipitemack(sd,n,0,UIA_FAIL); return 0; } for(i=0;ichangelook(&sd->bl,LOOK_ROBE,sd->status.robe); } - clif->unequipitemack(sd,n,sd->status.inventory[n].equip,1); + clif->unequipitemack(sd,n,sd->status.inventory[n].equip,UIA_SUCCESS); if((sd->status.inventory[n].equip & EQP_ARMS) && sd->weapontype1 == 0 && sd->weapontype2 == 0 && (!sd->sc.data[SC_TK_SEVENWIND] || sd->sc.data[SC_ASPERSIO])) //Check for seven wind (but not level seven!) diff --git a/src/map/pc.h b/src/map/pc.h index ff6246b22..8d031bc04 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -47,6 +47,12 @@ enum equip_index { EQI_COSTUME_MID, EQI_COSTUME_LOW, EQI_COSTUME_GARMENT, + EQI_SHADOW_ARMOR, + EQI_SHADOW_WEAPON, + EQI_SHADOW_SHIELD, + EQI_SHADOW_SHOES, + EQI_SHADOW_ACC_R, + EQI_SHADOW_ACC_L, EQI_AMMO, EQI_MAX }; @@ -526,21 +532,28 @@ struct map_session_data { //Equip position constants enum equip_pos { - EQP_HEAD_LOW = 0x0001, - EQP_HEAD_MID = 0x0200, //512 - EQP_HEAD_TOP = 0x0100, //256 - EQP_HAND_R = 0x0002, //2 - EQP_HAND_L = 0x0020, //32 - EQP_ARMOR = 0x0010, //16 - EQP_SHOES = 0x0040, //64 - EQP_GARMENT = 0x0004, //4 - EQP_ACC_L = 0x0008, //8 - EQP_ACC_R = 0x0080, //128 - EQP_COSTUME_HEAD_TOP = 0x0400, //1024 - EQP_COSTUME_HEAD_MID = 0x0800, //2048 - EQP_COSTUME_HEAD_LOW = 0x1000, //4096 - EQP_COSTUME_GARMENT = 0x2000, //8192 - EQP_AMMO = 0x8000, //32768 + EQP_HEAD_LOW = 0x000001, + EQP_HEAD_MID = 0x000200, //512 + EQP_HEAD_TOP = 0x000100, //256 + EQP_HAND_R = 0x000002, //2 + EQP_HAND_L = 0x000020, //32 + EQP_ARMOR = 0x000010, //16 + EQP_SHOES = 0x000040, //64 + EQP_GARMENT = 0x000004, //4 + EQP_ACC_L = 0x000008, //8 + EQP_ACC_R = 0x000080, //128 + EQP_COSTUME_HEAD_TOP = 0x000400, //1024 + EQP_COSTUME_HEAD_MID = 0x000800, //2048 + EQP_COSTUME_HEAD_LOW = 0x001000, //4096 + EQP_COSTUME_GARMENT = 0x002000, //8192 + //UNUSED_COSTUME_FLOOR = 0x004000, //16384 + EQP_AMMO = 0x008000, //32768 + EQP_SHADOW_ARMOR = 0x010000, //65536 + EQP_SHADOW_WEAPON = 0x020000, //131072 + EQP_SHADOW_SHIELD = 0x040000, //262144 + EQP_SHADOW_SHOES = 0x080000, //524288 + EQP_SHADOW_ACC_R = 0x100000, //1048576 + EQP_SHADOW_ACC_L = 0x200000, //2097152 }; #define EQP_WEAPON EQP_HAND_R diff --git a/src/map/pet.c b/src/map/pet.c index 023059a6b..21ee488d0 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -656,7 +656,7 @@ int pet_equipitem(struct map_session_data *sd,int index) { nameid = sd->status.inventory[index].nameid; if(pd->petDB->AcceID == 0 || nameid != pd->petDB->AcceID || pd->pet.equip != 0) { - clif->equipitemack(sd,0,0,0); + clif->equipitemack(sd,0,0,EIA_FAIL); return 1; } -- cgit v1.2.3-70-g09d2 From 4340bf74d5fa64d8205bc86a3d2c0592b7a542c7 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Wed, 30 Oct 2013 19:39:40 -0200 Subject: Official Font Support Fonts are now relog-persistent. Font items are now toggle-on/off, they no longer go away on use, they go away when their rental duration is over (and the font effect goes back to original). Special Thanks to Yommy for all the data! Signed-off-by: shennetsind --- db/pre-re/item_db.txt | 18 +++++----- db/re/item_db.txt | 18 +++++----- sql-files/main.sql | 2 ++ sql-files/upgrades/2013-10-30--21-12.sql | 3 ++ sql-files/upgrades/index.txt | 3 +- src/char/char.c | 17 +++++----- src/common/mmo.h | 2 ++ src/map/atcommand.c | 8 ++--- src/map/clif.c | 10 +++--- src/map/itemdb.h | 9 +++++ src/map/pc.c | 56 +++++++++++++++++++++++++++++++- src/map/pc.h | 1 - src/map/script.c | 6 ++-- 13 files changed, 112 insertions(+), 41 deletions(-) create mode 100644 sql-files/upgrades/2013-10-30--21-12.sql (limited to 'sql-files/main.sql') diff --git a/db/pre-re/item_db.txt b/db/pre-re/item_db.txt index 4a8161dbc..6f6fee45c 100644 --- a/db/pre-re/item_db.txt +++ b/db/pre-re/item_db.txt @@ -4833,9 +4833,9 @@ 12284,Internet_Cafe3,Internet Cafe3,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_INCINT,5400000,8; sc_start SC_INCVIT,5400000,4; sc_start SC_INCDEX,5400000,6; sc_start SC_PLUSMAGICPOWER,5400000,40; },{},{} 12285,Internet_Cafe4,Internet Cafe4,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_INCDEX,5400000,8; sc_start SC_INCLUK,5400000,4; sc_start SC_INCAGI,5400000,6; sc_start SC_PLUSATTACKPOWER,5400000,24; sc_start SC_PLUSMAGICPOWER,5400000,24; },{},{} 12286,Masquerade_Ball_Box2,Masquerade Ball Box2,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ getrandgroupitem 12286,1; },{},{} -12287,Love_Angel,Love Angel Magic Powder,2,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 1; },{},{} -12288,Squirrel,Squirrel Magic Powder,2,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 2; },{},{} -12289,Gogo,Gogo Magic Powder,2,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 3; },{},{} +12287,Love_Angel,Love Angel Magic Powder,11,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 1; },{},{} +12288,Squirrel,Squirrel Magic Powder,11,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 2; },{},{} +12289,Gogo,Gogo Magic Powder,11,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 3; },{},{} 12290,Mysterious_Can,Mysterious Can Magic Powder,2,10,,100,,,,,0xFFFFFFFF,7,2,,,,,,{ percentheal 5,0; skilleffect AL_BLESSING,0; sc_start SC_BLESSING,120000,5; },{},{} 12291,Mysterious_PET_Bottle,Mysterious PET Bottle,2,10,,100,,,,,0xFFFFFFFF,7,2,,,,,,{ percentheal 5,0; skilleffect AL_INCAGI,0; sc_start SC_INC_AGI,120000,5; },{},{} 12292,Unripe_Fruit,Unripe Fruit,0,500,,200,,,,,0xFFFFFFFF,7,2,,,,,,{ percentheal 20,0; },{},{} @@ -4850,12 +4850,12 @@ 12301,Doppelganger_Scroll,Doppelganger Contract,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ mercenary_create 1966,1800000; },{},{} 12302,Ygnizem_Scroll,Egnigem Cenia Contract,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ mercenary_create 1967,1800000; },{},{} 12303,Water_Of_Blessing,Blessing Of Water,2,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{} -12304,Picture_Diary,Diary Magic Powder,2,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 4; },{},{} -12305,Mini_Heart,Mini Heart Magic Powder,2,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 5; },{},{} -12306,Newcomer,Freshman Magic Powder,2,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 6; },{},{} -12307,Kid,Kid Magic Powder,2,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 7; },{},{} -12308,Magic_Castle,Magic Magic Powder,2,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 8; },{},{} -12309,Bulging_Head,JJangu Magic Powder,2,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 9; },{},{} +12304,Picture_Diary,Diary Magic Powder,11,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 4; },{},{} +12305,Mini_Heart,Mini Heart Magic Powder,11,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 5; },{},{} +12306,Newcomer,Freshman Magic Powder,11,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 6; },{},{} +12307,Kid,Kid Magic Powder,11,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 7; },{},{} +12308,Magic_Castle,Magic Magic Powder,11,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 8; },{},{} +12309,Bulging_Head,JJangu Magic Powder,11,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ setfont 9; },{},{} 12310,Spray_Of_Flowers,Spray Of Flowers,2,0,,50,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_INCFLEE,600000,10; },{},{} 12311,Large_Spray_Of_Flowers,Huge Spray Of Flowers,11,0,,100,,,,,0xFFFFFFFF,7,2,,,,,,{ itemskill ALL_PARTYFLEE,1; },{},{} 12312,Thick_Manual50,Thick Battle Manual,2,0,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_CASH_PLUSEXP,3600000,50; },{},{} diff --git a/db/re/item_db.txt b/db/re/item_db.txt index 5825034c8..98166f8bb 100644 --- a/db/re/item_db.txt +++ b/db/re/item_db.txt @@ -5609,9 +5609,9 @@ 12284,Internet_Cafe3,Internet Cafe3,2,0,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ sc_start SC_INCINT,5400000,8; sc_start SC_INCVIT,5400000,4; sc_start SC_INCDEX,5400000,6; sc_start SC_PLUSMAGICPOWER,5400000,40; },{},{} 12285,Internet_Cafe4,Internet Cafe4,2,0,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ sc_start SC_INCDEX,5400000,8; sc_start SC_INCLUK,5400000,4; sc_start SC_INCAGI,5400000,6; sc_start SC_PLUSATTACKPOWER,5400000,24; sc_start SC_PLUSMAGICPOWER,5400000,24; },{},{} 12286,Masquerade_Ball_Box2,Masquerade Ball Box2,2,0,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getrandgroupitem 12286,1; },{},{} -12287,Love_Angel,Love Angel Magic Powder,2,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 1; },{},{} -12288,Squirrel,Squirrel Magic Powder,2,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 2; },{},{} -12289,Gogo,Gogo Magic Powder,2,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 3; },{},{} +12287,Love_Angel,Love Angel Magic Powder,11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 1; },{},{} +12288,Squirrel,Squirrel Magic Powder,11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 2; },{},{} +12289,Gogo,Gogo Magic Powder,11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 3; },{},{} 12290,Mysterious_Can,Mysterious Can Magic Powder,2,10,,100,,,,,0xFFFFFFFF,63,2,,,,,,{ percentheal 5,0; skilleffect AL_BLESSING,0; sc_start SC_BLESSING,120000,5; },{},{} 12291,Mysterious_PET_Bottle,Mysterious PET Bottle,2,10,,100,,,,,0xFFFFFFFF,63,2,,,,,,{ percentheal 5,0; skilleffect AL_INCAGI,0; sc_start SC_INC_AGI,120000,5; },{},{} 12292,Unripe_Fruit,Unripe Yggdrasilberry,0,500,,200,,,,,0xFFFFFFFF,63,2,,,,,,{ percentheal 20,0; },{},{} @@ -5626,12 +5626,12 @@ 12301,Doppelganger_Scroll,Doppelganger Contract,2,0,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ mercenary_create 1966,1800000; },{},{} 12302,Ygnizem_Scroll,Egnigem Cenia Contract,2,0,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ mercenary_create 1967,1800000; },{},{} 12303,Water_Of_Blessing,Blessing Of Water,2,0,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{} -12304,Picture_Diary,Diary Magic Powder,2,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 4; },{},{} -12305,Mini_Heart,Mini Heart Magic Powder,2,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 5; },{},{} -12306,Newcomer,Freshman Magic Powder,2,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 6; },{},{} -12307,Kid,Kid Magic Powder,2,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 7; },{},{} -12308,Magic_Castle,Magic Magic Powder,2,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 8; },{},{} -12309,Bulging_Head,JJangu Magic Powder,2,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 9; },{},{} +12304,Picture_Diary,Diary Magic Powder,11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 4; },{},{} +12305,Mini_Heart,Mini Heart Magic Powder,11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 5; },{},{} +12306,Newcomer,Freshman Magic Powder,11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 6; },{},{} +12307,Kid,Kid Magic Powder,11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 7; },{},{} +12308,Magic_Castle,Magic Magic Powder,11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 8; },{},{} +12309,Bulging_Head,JJangu Magic Powder,11,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ setfont 9; },{},{} 12310,Spray_Of_Flowers,Spray Of Flowers,2,0,,50,,,,,0xFFFFFFFF,63,2,,,,,,{ sc_start SC_INCFLEE,600000,10; },{},{} 12311,Large_Spray_Of_Flowers,Huge Spray Of Flowers,11,0,,100,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill ALL_PARTYFLEE,1; },{},{} 12312,Thick_Manual50,Thick Battle Manual,2,0,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ sc_start SC_CASH_PLUSEXP,3600000,50; },{},{} diff --git a/sql-files/main.sql b/sql-files/main.sql index 8bd28c414..2c91d58b1 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -108,6 +108,7 @@ CREATE TABLE IF NOT EXISTS `char` ( `delete_date` INT(11) unsigned NOT NULL DEFAULT '0', `slotchange` SMALLINT(3) unsigned NOT NULL default '0', `char_opt` INT( 11 ) unsigned NOT NULL default '0', + `font` TINYINT( 3 ) UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY (`char_id`), UNIQUE KEY `name_key` (`name`), KEY `account_id` (`account_id`), @@ -660,6 +661,7 @@ INSERT INTO `sql_updates` (`timestamp`) VALUES (1366078541); INSERT INTO `sql_updates` (`timestamp`) VALUES (1381354728); INSERT INTO `sql_updates` (`timestamp`) VALUES (1381423003); INSERT INTO `sql_updates` (`timestamp`) VALUES (1382892428); +INSERT INTO `sql_updates` (`timestamp`) VALUES (1383167577); -- -- Table structure for table `sstatus` diff --git a/sql-files/upgrades/2013-10-30--21-12.sql b/sql-files/upgrades/2013-10-30--21-12.sql new file mode 100644 index 000000000..fdc16f418 --- /dev/null +++ b/sql-files/upgrades/2013-10-30--21-12.sql @@ -0,0 +1,3 @@ +#1383167577 +ALTER TABLE `char` ADD `font` TINYINT( 3 ) UNSIGNED NOT NULL DEFAULT '0'; +INSERT INTO `sql_updates` (`timestamp`) VALUES (1383167577); \ No newline at end of file diff --git a/sql-files/upgrades/index.txt b/sql-files/upgrades/index.txt index 4afcc5a0d..ca06e9c31 100644 --- a/sql-files/upgrades/index.txt +++ b/sql-files/upgrades/index.txt @@ -6,4 +6,5 @@ 2013-04-16--01-24.sql 2013-10-09--21-38.sql 2013-10-10--16-36.sql -2013-10-27--16-47.sql \ No newline at end of file +2013-10-27--16-47.sql +2013-10-30--21-12.sql \ No newline at end of file diff --git a/src/char/char.c b/src/char/char.c index 310163e3a..4a04c521d 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -463,7 +463,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p) (p->ele_id != cp->ele_id) || (p->shield != cp->shield) || (p->head_top != cp->head_top) || (p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) || (p->rename != cp->rename) || (p->slotchange != cp->slotchange) || (p->robe != cp->robe) || - (p->show_equip != cp->show_equip) || (p->allow_party != cp->allow_party) + (p->show_equip != cp->show_equip) || (p->allow_party != cp->allow_party) || (p->font != cp->font) ) { //Save status unsigned int opt = 0; @@ -479,7 +479,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p) "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d',`elemental_id`='%d'," "`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d'," "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d'," - "`delete_date`='%lu',`robe`='%d',`slotchange`='%d', `char_opt`='%u'" + "`delete_date`='%lu',`robe`='%d',`slotchange`='%d', `char_opt`='%u', `font`='%u'" " WHERE `account_id`='%d' AND `char_id` = '%d'", char_db, p->base_level, p->job_level, p->base_exp, p->job_exp, p->zeny, @@ -490,7 +490,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p) mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y, mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename, (unsigned long)p->delete_date, // FIXME: platform-dependent size - p->robe,p->slotchange,opt, + p->robe,p->slotchange,opt,p->font, p->account_id, p->char_id) ) { Sql_ShowDebug(sql_handle); @@ -1052,7 +1052,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) || SQL_ERROR == SQL->StmtBindColumn(stmt, 30, SQLDT_SHORT, &p.head_mid, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 31, SQLDT_SHORT, &p.head_bottom, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 32, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 33, SQLDT_USHORT, &p.rename, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 33, SQLDT_USHORT, &p.rename, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 35, SQLDT_SHORT, &p.robe, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 36, SQLDT_USHORT, &p.slotchange, 0, NULL, NULL) @@ -1115,7 +1115,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`," "`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`," "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`,`slotchange`," - "`char_opt`" + "`char_opt`,`font`" " FROM `%s` WHERE `char_id`=? LIMIT 1", char_db) || SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT, &char_id, 0) || SQL_ERROR == SQL->StmtExecute(stmt) @@ -1148,7 +1148,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything || SQL_ERROR == SQL->StmtBindColumn(stmt, 26, SQLDT_INT, &p->guild_id, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 27, SQLDT_INT, &p->pet_id, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 28, SQLDT_INT, &p->hom_id, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 29, SQLDT_INT, &p->ele_id, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 29, SQLDT_INT, &p->ele_id, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 30, SQLDT_SHORT, &p->hair, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 31, SQLDT_SHORT, &p->hair_color, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 32, SQLDT_SHORT, &p->clothes_color, 0, NULL, NULL) @@ -1168,11 +1168,12 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything || SQL_ERROR == SQL->StmtBindColumn(stmt, 46, SQLDT_INT, &p->mother, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 47, SQLDT_INT, &p->child, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 48, SQLDT_INT, &p->fame, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 49, SQLDT_USHORT, &p->rename, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 49, SQLDT_USHORT, &p->rename, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 50, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 51, SQLDT_SHORT, &p->robe, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 52, SQLDT_USHORT, &p->slotchange, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 53, SQLDT_UINT, &opt, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 53, SQLDT_UINT, &opt, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 54, SQLDT_UCHAR, &p->font, 0, NULL, NULL) ) { SqlStmt_ShowDebug(stmt); diff --git a/src/common/mmo.h b/src/common/mmo.h index 9281314dc..5f75f35da 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -414,6 +414,8 @@ struct mmo_charstatus { unsigned short slotchange; time_t delete_date; + + unsigned char font; }; typedef enum mail_status { diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 7ec589956..146159c63 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -8111,9 +8111,9 @@ ACMD(font) { font_id = atoi(message); if( font_id == 0 ) { - if( sd->user_font ) + if( sd->status.font ) { - sd->user_font = 0; + sd->status.font = 0; clif->message(fd, msg_txt(1356)); // Returning to normal font. clif->font(sd); } @@ -8125,9 +8125,9 @@ ACMD(font) { } else if( font_id < 0 || font_id > 9 ) clif->message(fd, msg_txt(1359)); // Invalid font. Use a value from 0 to 9. - else if( font_id != sd->user_font ) + else if( font_id != sd->status.font ) { - sd->user_font = font_id; + sd->status.font = font_id; clif->font(sd); clif->message(fd, msg_txt(1360)); // Font changed. } diff --git a/src/map/clif.c b/src/map/clif.c index 957f75d99..c1e7cb1c9 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -611,7 +611,7 @@ void clif_authok(struct map_session_data *sd) p.xSize = p.ySize = 5; /* not-used */ #if PACKETVER >= 20080102 - p.font = sd->user_font; // FIXME: Font is currently not saved. + p.font = sd->status.font; #endif clif->send(&p,sizeof(p),&sd->bl,SELF); @@ -982,7 +982,7 @@ void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enu p.state = vd->dead_sit; p.clevel = clif_setlevel(bl); #if PACKETVER >= 20080102 - p.font = (sd) ? sd->user_font : 0; + p.font = (sd) ? sd->status.font : 0; #endif #if PACKETVER >= 20140000 //actual 20120221 if( bl->type == BL_MOB ) { @@ -1110,7 +1110,7 @@ void clif_spawn_unit(struct block_list* bl, enum send_target target) { p.xSize = p.ySize = (sd) ? 5 : 0; p.clevel = clif_setlevel(bl); #if PACKETVER >= 20080102 - p.font = (sd) ? sd->user_font : 0; + p.font = (sd) ? sd->status.font : 0; #endif #if PACKETVER >= 20140000 //actual 20120221 if( bl->type == BL_MOB ) { @@ -1188,7 +1188,7 @@ void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, p.xSize = p.ySize = (sd) ? 5 : 0; p.clevel = clif_setlevel(bl); #if PACKETVER >= 20080102 - p.font = (sd) ? sd->user_font : 0; + p.font = (sd) ? sd->status.font : 0; #endif #if PACKETVER >= 20140000 //actual 20120221 if( bl->type == BL_MOB ) { @@ -16101,7 +16101,7 @@ void clif_font(struct map_session_data *sd) nullpo_retv(sd); WBUFW(buf,0) = 0x2ef; WBUFL(buf,2) = sd->bl.id; - WBUFW(buf,6) = sd->user_font; + WBUFW(buf,6) = sd->status.font; clif->send(buf, packet_len(0x2ef), &sd->bl, AREA); #endif } diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 0f46c1c01..2579d84ca 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -48,6 +48,15 @@ enum item_itemid { ITEMID_TRAP_ALLOY = 7940, ITEMID_ANCILLA = 12333, ITEMID_REINS_OF_MOUNT = 12622, + ITEMID_LOVE_ANGEL = 12287, + ITEMID_SQUIRREL = 12288, + ITEMID_GOGO = 12289, + ITEMID_PICTURE_DIARY = 12304, + ITEMID_MINI_HEART = 12305, + ITEMID_NEWCOMER = 12306, + ITEMID_KID = 12307, + ITEMID_MAGIC_CASTLE = 12308, + ITEMID_BULGING_HEAD = 12309, }; /** diff --git a/src/map/pc.c b/src/map/pc.c index 0244c6c84..35d883b6f 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -446,12 +446,66 @@ int pc_inventory_rental_clear(struct map_session_data *sd) /* assumes i is valid (from default areas where it is called, it is) */ void pc_rental_expire(struct map_session_data *sd, int i) { short nameid = sd->status.inventory[i].nameid; - + /* Soon to be dropped, we got plans to integrate it with item db */ switch( nameid ) { case ITEMID_REINS_OF_MOUNT: status_change_end(&sd->bl,SC_ALL_RIDING,INVALID_TIMER); break; + case ITEMID_LOVE_ANGEL: + if( sd->status.font == 1 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_SQUIRREL: + if( sd->status.font == 2 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_GOGO: + if( sd->status.font == 3 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_PICTURE_DIARY: + if( sd->status.font == 4 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_MINI_HEART: + if( sd->status.font == 5 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_NEWCOMER: + if( sd->status.font == 6 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_KID: + if( sd->status.font == 7 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_MAGIC_CASTLE: + if( sd->status.font == 8 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_BULGING_HEAD: + if( sd->status.font == 9 ) { + sd->status.font = 0; + clif->font(sd); + } + break; } clif->rental_expired(sd->fd, i, sd->status.inventory[i].nameid); diff --git a/src/map/pc.h b/src/map/pc.h index 14e1da5f4..ddd3de1b9 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -449,7 +449,6 @@ struct map_session_data { const char* debug_func; unsigned int bg_id; - unsigned short user_font; /** * For the Secure NPC Timeout option (check config/Secure.h) [RR] diff --git a/src/map/script.c b/src/map/script.c index 2a83f3918..d51f27ce9 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -16229,10 +16229,10 @@ BUILDIN(setfont) if( sd == NULL ) return true; - if( sd->user_font != font ) - sd->user_font = font; + if( sd->status.font != font ) + sd->status.font = font; else - sd->user_font = 0; + sd->status.font = 0; clif->font(sd); return true; -- cgit v1.2.3-70-g09d2 From c47d8e4b8f9d63ab6b4e7e286e91cd50a5bdd151 Mon Sep 17 00:00:00 2001 From: sevenzz23 Date: Thu, 31 Oct 2013 12:07:06 +0700 Subject: No error after compilation, but when logging in at map server it will crash. Im pretty sure its on the clif.c Signed-off-by: sevenzz23 --- conf/messages.conf | 41 +++++- doc/atcommands.txt | 16 +++ doc/permissions.txt | 3 +- doc/script_commands.txt | 46 +++++++ sql-files/main.sql | 4 + sql-files/upgrades/2013-10-31--07-49.sql | 4 + src/char/char.c | 94 +++++++------ src/char/int_mail.c | 2 + src/char/int_storage.c | 167 +++++++++++++++++++--- src/char/inter.c | 4 +- src/common/mmo.h | 6 +- src/config/core.h | 4 + src/map/atcommand.c | 78 ++++++++--- src/map/buyingstore.c | 4 +- src/map/clif.c | 26 ++-- src/map/guild.c | 52 +++++++ src/map/guild.h | 4 + src/map/intif.c | 63 +++++++-- src/map/intif.h | 4 + src/map/mail.c | 5 +- src/map/packets_struct.h | 1 + src/map/party.c | 9 +- src/map/pc.c | 59 ++++++-- src/map/pc.h | 7 +- src/map/pc_groups.c | 1 + src/map/pc_groups.h | 3 +- src/map/script.c | 229 ++++++++++++++++++++++++++++++- src/map/storage.c | 17 ++- src/map/trade.c | 6 + src/map/vending.c | 3 +- 30 files changed, 825 insertions(+), 137 deletions(-) create mode 100644 sql-files/upgrades/2013-10-31--07-49.sql (limited to 'sql-files/main.sql') diff --git a/conf/messages.conf b/conf/messages.conf index 7b7a99301..d2e57bb0e 100644 --- a/conf/messages.conf +++ b/conf/messages.conf @@ -316,6 +316,13 @@ 290: The player is no longer killable. 291: Weather effects will dispell on warp/refresh 292: Killer state reset. +//Item Bound System +293: This bounded item cannot be traded to that character. +294: This bounded item cannot be stored there. +295: Please enter an item name or ID (usage: @item ). +296: Please enter all parameters (usage: @item2 +297: ). +298: Invalid bound type. Valid types are - 1:Account 2:Guild 3:Party 4:Character // Guild Castles Number // -------------------- //299: ?? Castles @@ -455,6 +462,13 @@ // Messages of others (not for GM commands) // ---------------------------------------- +// Account-Bound Items +497: You cannot distribute this item - it is an account bounded item! + +// @itembound / @itembound2 +498: Cannot create bounded pet eggs or pet armors. +499: Cannot create bounded stackable items. + //500: FREE 501: Your account time limit is: %d-%m-%Y %H:%M:%S. 502: Day Mode is activated @@ -711,11 +725,13 @@ 981: Please enter color and message (usage: @kamic ). 982: Invalid color. -// @item -983: Please enter an item name or ID (usage: @item ). -// @item2 -984: Please enter all parameters (usage: @item2 +// @item / @itembound +983: Please enter an item name or ID (usage: @%s ). + + +// @item2 / @itembound2 +984: Please enter all parameters (usage: @%s ). 985: ). // @baselevelup @@ -1360,7 +1376,8 @@ 1361: Already using this font. // @new_mount -1362: NOTICE: If you crash with mount your LUA is outdated. +//1362: NOTICE: If you crash with mount your LUA is outdated. +1362: .. 1363: You have mounted. 1364: You have released your mount. @@ -1534,5 +1551,19 @@ //CashShop mapflag 1489: Cash Shop is disabled in this map + +// @autoloottype +1490: You're already autolooting this item type. +1491: Your autoloottype list has all item types. You can remove some items with @autoloottype -. +1492: Autolooting item type: '%s' {%d} +1493: You're currently not autolooting this item type. +1494: Removed item type: '%s' {%d} from your autoloottype list. +1495: To add an item type to the list, use "@aloottype +". To remove an item type, use "@aloottype -". +1496: Type List: healing = 0, usable = 2, etc = 3, weapon = 4, armor = 5, card = 6, petegg = 7, petarmor = 8, ammo = 10 +1497: "@aloottype reset" will clear your autoloottype list. +1498: Your autoloottype list is empty. +1499: Item types on your autoloottype list: +1500: Your autoloottype list has been reset. + //Custom translations import: conf/import/msg_conf.txt diff --git a/doc/atcommands.txt b/doc/atcommands.txt index 42b085cd6..a7377b563 100644 --- a/doc/atcommands.txt +++ b/doc/atcommands.txt @@ -625,6 +625,22 @@ Creates an item with the given parameters (the 'cards' can be any item). identify_flag: 0 = unidentified, 1 = identified attribute: 0 = not broken, 1 = broken +--------------------------------------- + +@itembound + +Creates the specified item and bounds it to the account. +bound_type: 1 = Account, 2 = Guild, 3 = Party, 4 = Character + +--------------------------------------- + +@itembound2 + +Creates an item with the given parameters (the 'cards' can be any item) and bounds it to the account. +identify_flag: 0 = unidentified, 1 = identified +attribute: 0 = not broken, 1 = broken +bound_type: 1 = Account, 2 = Guild, 3 = Party, 4 = Character + --------------------------------------- @produce <# of Very's> diff --git a/doc/permissions.txt b/doc/permissions.txt index 9760f716c..c2aeba081 100644 --- a/doc/permissions.txt +++ b/doc/permissions.txt @@ -3,7 +3,7 @@ //===== By: ================================================== //= Hercules Dev Team //===== Current Version: ===================================== -//= 20130528 +//= 20131031 //===== Description: ========================================= //= Player group permissions, configured in /conf/groups.conf. //============================================================ @@ -31,4 +31,5 @@ show_bossmobs : Ability to see boss mobs with @showmobs. disable_pvm : Ability to disable Player vs. Monster. disable_pvp : Ability to disable Player vs. Player. disable_commands_when_dead : Ability to disable @command usage when dead. +can_trade_bounded : Ability to trade or otherwise distribute bounded items (drop, storage, vending etc...). hchsys_admin : Hercules Chat System Admin (Ability to modify channel settings regardless of ownership and join password-protected channels without requiring a password.) diff --git a/doc/script_commands.txt b/doc/script_commands.txt index bd0b032f1..23bacec5f 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -2781,6 +2781,7 @@ recreate these items perfectly if they are destroyed. Here's what you get: @inventorylist_expire[] - expire time (Unix time stamp). 0 means never expires. @inventorylist_count - the number of items in these lists. +@inventorylist_bound - whether it is an account bounded item or not. This could be handy to save/restore a character's inventory, since no other command returns such a complete set of data, and could also be the @@ -4448,6 +4449,51 @@ command, creating a pet which is the same, but simultaneously exists in two eggs, and may hatch from either, although, I'm not sure what kind of a mess will this really cause. +--------------------------------------- +*getitembound ,,{,}; +*getitembound "",,{,}; + +This command behaves identically to 'getitem', but the items created will be +bound to the target character as specified by the bound type. All items created +in this manner cannot be dropped, sold, vended, auctioned, or mailed, and in +some cases cannot be traded or stored. + +Valid bound types are: + 1 - Account Bound + 2 - Guild Bound + 3 - Party Bound + 4 - Character Bound + +--------------------------------------- + +*getitembound2 ,,,,,,,,,; +*getitembound2 "",,,,,,,,,; + +This command behaves identically to 'getitem2', but the items created will be +bound to the target character as specified by the bound type. All items created +in this manner cannot be dropped, sold, vended, auctioned, or mailed, and in +some cases cannot be traded or stored. + +For a list of bound types see 'getitembound'. + +--------------------------------------- + +*countbound({}) + +This function will return the number of bounded items in the character's +inventory, and sets an array @bound_items[] containing all item IDs of the +counted items. If a bound type is specified, only those items will be counted. + +For a list of bound types see 'getitembound'. + +Example: + mes "You currently have "+countbound()+" bounded items."; + next; + mes "The list of bounded items include:"; + for(set .@i,0; .@i,; diff --git a/sql-files/main.sql b/sql-files/main.sql index 2c91d58b1..3f425d411 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -43,6 +43,7 @@ CREATE TABLE IF NOT EXISTS `cart_inventory` ( `card2` smallint(11) NOT NULL default '0', `card3` smallint(11) NOT NULL default '0', `expire_time` int(11) unsigned NOT NULL default '0', + `bound` tinyint(1) unsigned NOT NULL default '0', `unique_id` bigint(20) unsigned NOT NULL default '0', PRIMARY KEY (`id`), KEY `char_id` (`char_id`) @@ -342,6 +343,7 @@ CREATE TABLE IF NOT EXISTS `guild_storage` ( `card2` smallint(11) NOT NULL default '0', `card3` smallint(11) NOT NULL default '0', `expire_time` int(11) unsigned NOT NULL default '0', + `bound` tinyint(1) unsigned NOT NULL default '0', `unique_id` bigint(20) unsigned NOT NULL default '0', PRIMARY KEY (`id`), KEY `guild_id` (`guild_id`) @@ -406,6 +408,7 @@ CREATE TABLE IF NOT EXISTS `inventory` ( `card3` smallint(11) NOT NULL default '0', `expire_time` int(11) unsigned NOT NULL default '0', `favorite` tinyint(3) unsigned NOT NULL default '0', + `bound` tinyint(1) unsigned NOT NULL default '0', `unique_id` bigint(20) unsigned NOT NULL default '0', PRIMARY KEY (`id`), KEY `char_id` (`char_id`) @@ -691,6 +694,7 @@ CREATE TABLE IF NOT EXISTS `storage` ( `card2` smallint(11) NOT NULL default '0', `card3` smallint(11) NOT NULL default '0', `expire_time` int(11) unsigned NOT NULL default '0', + `bound` tinyint(1) unsigned NOT NULL default '0', `unique_id` bigint(20) unsigned NOT NULL default '0', PRIMARY KEY (`id`), KEY `account_id` (`account_id`) diff --git a/sql-files/upgrades/2013-10-31--07-49.sql b/sql-files/upgrades/2013-10-31--07-49.sql new file mode 100644 index 000000000..40e0421c8 --- /dev/null +++ b/sql-files/upgrades/2013-10-31--07-49.sql @@ -0,0 +1,4 @@ +ALTER TABLE `inventory` ADD COLUMN `bound` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `favorite`; +ALTER TABLE `cart_inventory` ADD COLUMN `bound` tinyint(1) UNSIGNED NOT NULL default '0' AFTER `expire_time`; +ALTER TABLE `storage` ADD COLUMN `bound` tinyint(1) UNSIGNED NOT NULL default '0' AFTER `expire_time`; +ALTER TABLE `guild_storage` ADD COLUMN `bound` TINYINT(3) UNSIGNED NOT NULL default '0' AFTER `expire_time`; \ No newline at end of file diff --git a/src/char/char.c b/src/char/char.c index 4a04c521d..61a1e24e0 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -724,8 +724,8 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit // it significantly reduces cpu load on the database server. StrBuf->Init(&buf); - StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); - for( j = 0; j < MAX_SLOTS; ++j ) + StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`"); + for( j = 0; j < MAX_SLOTS; ++j ) StrBuf->Printf(&buf, ", `card%d`", j); StrBuf->Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id); @@ -747,8 +747,9 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); - for( j = 0; j < MAX_SLOTS; ++j ) - SQL->StmtBindColumn(stmt, 8+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 8, SQLDT_UINT, &item.bound, 0, NULL, NULL); + for( j = 0; j < MAX_SLOTS; ++j ) + SQL->StmtBindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); // bit array indicating which inventory items have already been matched flag = (bool*) aCalloc(max, sizeof(bool)); @@ -775,17 +776,18 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit items[i].identify == item.identify && items[i].refine == item.refine && items[i].attribute == item.attribute && - items[i].expire_time == item.expire_time ) + items[i].expire_time == item.expire_time && + items[i].bound == item.bound ) ; //Do nothing. else { // update all fields. StrBuf->Clear(&buf); - StrBuf->Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u'", - tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); - for( j = 0; j < MAX_SLOTS; ++j ) - StrBuf->Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); - StrBuf->Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); + StrBuf->Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `bound`='%d'", + tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound); + for( j = 0; j < MAX_SLOTS; ++j )for( j = 0; j < MAX_SLOTS; ++j ) + StrBuf->Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); + StrBuf->Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); if( SQL_ERROR == SQL->QueryStr(sql_handle, StrBuf->Value(&buf)) ) { @@ -810,8 +812,8 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit SQL->StmtFree(stmt); StrBuf->Clear(&buf); - StrBuf->Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `unique_id`", tablename, selectoption); - for( j = 0; j < MAX_SLOTS; ++j ) + StrBuf->Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`", tablename, selectoption); + for( j = 0; j < MAX_SLOTS; ++j ) StrBuf->Printf(&buf, ", `card%d`", j); StrBuf->AppendStr(&buf, ") VALUES "); @@ -828,9 +830,9 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit else found = true; - StrBuf->Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%"PRIu64"'", - id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].unique_id); - for( j = 0; j < MAX_SLOTS; ++j ) + StrBuf->Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%"PRIu64"'", + id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound, items[i].unique_id); + for( j = 0; j < MAX_SLOTS; ++j ) StrBuf->Printf(&buf, ", '%d'", items[i].card[j]); StrBuf->AppendStr(&buf, ")"); @@ -868,8 +870,8 @@ int inventory_to_sql(const struct item items[], int max, int id) { // it significantly reduces cpu load on the database server. StrBuf->Init(&buf); - StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`"); - for( j = 0; j < MAX_SLOTS; ++j ) + StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`"); + for( j = 0; j < MAX_SLOTS; ++j ) StrBuf->Printf(&buf, ", `card%d`", j); StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", inventory_db, id); @@ -892,8 +894,9 @@ int inventory_to_sql(const struct item items[], int max, int id) { SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 8, SQLDT_CHAR, &item.favorite, 0, NULL, NULL); - for( j = 0; j < MAX_SLOTS; ++j ) - SQL->StmtBindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 9, SQLDT_CHAR, &item.bound, 0, NULL, NULL); + for( j = 0; j < MAX_SLOTS; ++j ) + SQL->StmtBindColumn(stmt, 10+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); // bit array indicating which inventory items have already been matched flag = (bool*) aCalloc(max, sizeof(bool)); @@ -919,15 +922,16 @@ int inventory_to_sql(const struct item items[], int max, int id) { items[i].refine == item.refine && items[i].attribute == item.attribute && items[i].expire_time == item.expire_time && - items[i].favorite == item.favorite ) + items[i].favorite == item.favorite && + items[i].bound == item.bound ) ; //Do nothing. else { // update all fields. StrBuf->Clear(&buf); - StrBuf->Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d'", - inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite); - for( j = 0; j < MAX_SLOTS; ++j ) - StrBuf->Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); + StrBuf->Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d', `bound`='%d'", + inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].bound); + for( j = 0; j < MAX_SLOTS; ++j ) + StrBuf->Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); StrBuf->Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); if( SQL_ERROR == SQL->QueryStr(sql_handle, StrBuf->Value(&buf)) ) { @@ -950,8 +954,8 @@ int inventory_to_sql(const struct item items[], int max, int id) { SQL->StmtFree(stmt); StrBuf->Clear(&buf); - StrBuf->Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `unique_id`", inventory_db); - for( j = 0; j < MAX_SLOTS; ++j ) + StrBuf->Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`", inventory_db); + for( j = 0; j < MAX_SLOTS; ++j ) StrBuf->Printf(&buf, ", `card%d`", j); StrBuf->AppendStr(&buf, ") VALUES "); @@ -967,9 +971,9 @@ int inventory_to_sql(const struct item items[], int max, int id) { else found = true; - StrBuf->Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%"PRIu64"'", - id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].unique_id); - for( j = 0; j < MAX_SLOTS; ++j ) + StrBuf->Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%d', '%"PRIu64"'", + id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].bound, items[i].unique_id); + for( j = 0; j < MAX_SLOTS; ++j ) StrBuf->Printf(&buf, ", '%d'", items[i].card[j]); StrBuf->AppendStr(&buf, ")"); @@ -1229,10 +1233,10 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything strcat(t_msg, " memo"); //read inventory - //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `expire_time`, `favorite`, `unique_id`) - StrBuf->Init(&buf); - StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `unique_id`"); - for( i = 0; i < MAX_SLOTS; ++i ) + //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `expire_time`, `favorite`, `bound`, `unique_id`) + StrBuf->Init(&buf); + StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`"); + for( i = 0; i < MAX_SLOTS; ++i ) StrBuf->Printf(&buf, ", `card%d`", i); StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY); @@ -1248,10 +1252,11 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything || SQL_ERROR == SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.favorite, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 9, SQLDT_ULONGLONG, &tmp_item.unique_id, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); + || SQL_ERROR == SQL->StmtBindColumn(stmt, 9, SQLDT_CHAR, &tmp_item.bound, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 10, SQLDT_ULONGLONG, &tmp_item.unique_id, 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); for( i = 0; i < MAX_SLOTS; ++i ) - if( SQL_ERROR == SQL->StmtBindColumn(stmt, 10+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) + if( SQL_ERROR == SQL->StmtBindColumn(stmt, 11+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) SqlStmt_ShowDebug(stmt); for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SQL->StmtNextRow(stmt); ++i ) @@ -1260,10 +1265,10 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything strcat(t_msg, " inventory"); //read cart - //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, expire_time`, `unique_id`) - StrBuf->Clear(&buf); - StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `unique_id`"); - for( j = 0; j < MAX_SLOTS; ++j ) + //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, expire_time`, `bound`, `unique_id`) + StrBuf->Clear(&buf); + StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`"); + for( j = 0; j < MAX_SLOTS; ++j ) StrBuf->Printf(&buf, ", `card%d`", j); StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART); @@ -1278,10 +1283,11 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything || SQL_ERROR == SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_ULONGLONG, &tmp_item.unique_id, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); + || SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.bound, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 9, SQLDT_ULONGLONG, &tmp_item.unique_id, 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); for( i = 0; i < MAX_SLOTS; ++i ) - if( SQL_ERROR == SQL->StmtBindColumn(stmt, 9+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) + if( SQL_ERROR == SQL->StmtBindColumn(stmt, 10+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) SqlStmt_ShowDebug(stmt); for( i = 0; i < MAX_CART && SQL_SUCCESS == SQL->StmtNextRow(stmt); ++i ) @@ -2947,7 +2953,7 @@ int parse_frommap(int fd) break; } //Check account only if this ain't final save. Final-save goes through because of the char-map reconnect - if (RFIFOB(fd,12) || ( + if (RFIFOB(fd,12) || RFIFOB(fd,13) || ( (character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL && character->char_id == cid)) { diff --git a/src/char/int_mail.c b/src/char/int_mail.c index e4b88b5bf..b69824d4b 100644 --- a/src/char/int_mail.c +++ b/src/char/int_mail.c @@ -64,6 +64,7 @@ static int mail_fromsql(int char_id, struct mail_data* md) SQL->GetData(sql_handle,14, &data, NULL); item->identify = atoi(data); SQL->GetData(sql_handle,15, &data, NULL); item->unique_id = strtoull(data, NULL, 10); item->expire_time = 0; + item->bound = 0; for (j = 0; j < MAX_SLOTS; j++) { @@ -184,6 +185,7 @@ static bool mail_loadmessage(int mail_id, struct mail_message* msg) SQL->GetData(sql_handle,14, &data, NULL); msg->item.identify = atoi(data); SQL->GetData(sql_handle,15, &data, NULL); msg->item.unique_id = strtoull(data, NULL, 10); msg->item.expire_time = 0; + msg->item.bound = 0; for( j = 0; j < MAX_SLOTS; j++ ) { diff --git a/src/char/int_storage.c b/src/char/int_storage.c index 429b80105..6443aa743 100644 --- a/src/char/int_storage.c +++ b/src/char/int_storage.c @@ -39,8 +39,8 @@ int storage_fromsql(int account_id, struct storage_data* p) // storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} StrBuf->Init(&buf); - StrBuf->AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`,`unique_id`"); - for( j = 0; j < MAX_SLOTS; ++j ) + StrBuf->AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`,`bound`,`unique_id`"); + for( j = 0; j < MAX_SLOTS; ++j ) StrBuf->Printf(&buf, ",`card%d`", j); StrBuf->Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id); @@ -60,10 +60,11 @@ int storage_fromsql(int account_id, struct storage_data* p) SQL->GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data); SQL->GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data); SQL->GetData(sql_handle, 7, &data, NULL); item->expire_time = (unsigned int)atoi(data); - SQL->GetData(sql_handle, 8, &data, NULL); item->unique_id = strtoull(data, NULL, 10); - for( j = 0; j < MAX_SLOTS; ++j ) + SQL->GetData(sql_handle, 8, &data, NULL); item->bound = atoi(data); + SQL->GetData(sql_handle, 9, &data, NULL); item->unique_id = strtoull(data, NULL, 10); + for( j = 0; j < MAX_SLOTS; ++j ) { - SQL->GetData(sql_handle, 9+j, &data, NULL); item->card[j] = atoi(data); + SQL->GetData(sql_handle, 10+j, &data, NULL); item->card[j] = atoi(data); } } p->storage_amount = i; @@ -96,8 +97,8 @@ int guild_storage_fromsql(int guild_id, struct guild_storage* p) // storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} StrBuf->Init(&buf); - StrBuf->AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`unique_id`"); - for( j = 0; j < MAX_SLOTS; ++j ) + StrBuf->AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`bound`,`unique_id`"); + for( j = 0; j < MAX_SLOTS; ++j ) StrBuf->Printf(&buf, ",`card%d`", j); StrBuf->Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id); @@ -116,11 +117,13 @@ int guild_storage_fromsql(int guild_id, struct guild_storage* p) SQL->GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data); SQL->GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data); SQL->GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data); - SQL->GetData(sql_handle, 7, &data, NULL); item->unique_id = strtoull(data, NULL, 10); - item->expire_time = 0; + SQL->GetData(sql_handle, 7, &data, NULL); item->bound = atoi(data); + SQL->GetData(sql_handle, 8, &data, NULL); item->unique_id = strtoull(data, NULL, 10); + item->expire_time = 0; + item->bound = 0; for( j = 0; j < MAX_SLOTS; ++j ) { - SQL->GetData(sql_handle, 8+j, &data, NULL); item->card[j] = atoi(data); + SQL->GetData(sql_handle, 9+j, &data, NULL); item->card[j] = atoi(data); } } p->storage_amount = i; @@ -159,19 +162,20 @@ int inter_guild_storage_delete(int guild_id) //--------------------------------------------------------- // packet from map server -int mapif_load_guild_storage(int fd,int account_id,int guild_id) +int mapif_load_guild_storage(int fd,int account_id,int guild_id, char flag) { if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) ) Sql_ShowDebug(sql_handle); else if( SQL->NumRows(sql_handle) > 0 ) {// guild exists - WFIFOHEAD(fd, sizeof(struct guild_storage)+12); + WFIFOHEAD(fd, sizeof(struct guild_storage)+13); WFIFOW(fd,0) = 0x3818; - WFIFOW(fd,2) = sizeof(struct guild_storage)+12; + WFIFOW(fd,2) = sizeof(struct guild_storage)+13; WFIFOL(fd,4) = account_id; WFIFOL(fd,8) = guild_id; - guild_storage_fromsql(guild_id, (struct guild_storage*)WFIFOP(fd,12)); - WFIFOSET(fd, WFIFOW(fd,2)); + WFIFOB(fd,12) = flag; //1 open storage, 0 don't open + guild_storage_fromsql(guild_id, (struct guild_storage*)WFIFOP(fd,13)); + WFIFOSET(fd, WFIFOW(fd,2)); return 0; } // guild does not exist @@ -201,7 +205,7 @@ int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail) int mapif_parse_LoadGuildStorage(int fd) { RFIFOHEAD(fd); - mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6)); + mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6),1); return 0; } @@ -235,6 +239,134 @@ int mapif_parse_SaveGuildStorage(int fd) return 0; } +#ifdef BOUND_ITEMS +int mapif_itembound_ack(int fd, int aid, int guild_id) +{ + WFIFOHEAD(fd,8); + WFIFOW(fd,0) = 0x3856; + WFIFOL(fd,2) = aid; + WFIFOW(fd,6) = guild_id; + WFIFOSET(fd,8); + return 0; +} + +//------------------------------------------------ +//Guild bound items pull for offline characters [Akinari] +//Revised by [Mhalicot] +//------------------------------------------------ +int mapif_parse_itembound_retrieve(int fd) +{ + StringBuf buf; + SqlStmt* stmt; + struct item item; + int j, i=0, s; + bool found=false; + struct item items[MAX_INVENTORY]; + int char_id = RFIFOL(fd,2); + int aid = RFIFOL(fd,6); + int guild_id = RFIFOW(fd,10); + + StrBuf->Init(&buf); + StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`"); + for( j = 0; j < MAX_SLOTS; ++j ) + StrBuf->Printf(&buf, ", `card%d`", j); + StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`='%d'",inventory_db,char_id); + + stmt = SQL->StmtMalloc(sql_handle); + if( SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) + || SQL_ERROR == SQL->StmtExecute(stmt) ) + { + Sql_ShowDebug(sql_handle); + SQL->StmtFree(stmt); + StrBuf->Destroy(&buf); + return 1; + } + + SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 8, SQLDT_UINT, &item.bound, 0, NULL, NULL); + for( j = 0; j < MAX_SLOTS; ++j ) + SQL->StmtBindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); + + while( SQL_SUCCESS == SQL->StmtNextRow(stmt) ) { + if(item.bound == 2) { + memcpy(&items[i],&item,sizeof(struct item)); + i++; + } + } + SQL->FreeResult(sql_handle); + + if(!i) { //No items found - No need to continue + StrBuf->Destroy(&buf); + SQL->StmtFree(stmt); + return 0; + } + + //First we delete the character's items + StrBuf->Clear(&buf); + StrBuf->Printf(&buf, "DELETE FROM `%s` WHERE",inventory_db); + for(j=0; jAppendStr(&buf, " OR"); + else + found = true; + StrBuf->Printf(&buf, " `id`=%d",items[j].id); + } + + if( SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) + || SQL_ERROR == SQL->StmtExecute(stmt) ) + { + Sql_ShowDebug(sql_handle); + SQL->StmtFree(stmt); + StrBuf->Destroy(&buf); + return 1; + } + + //Now let's update the guild storage with those deleted items + found = false; + StrBuf->Clear(&buf); + StrBuf->Printf(&buf, "INSERT INTO `%s` (`guild_id`, `nameid`, `amount`, `identify`, `refine`, `attribute`, `expire_time`, `bound`", guild_storage_db); + for( j = 0; j < MAX_SLOTS; ++j ) + StrBuf->Printf(&buf, ", `card%d`", j); + StrBuf->AppendStr(&buf, ") VALUES "); + + for( j = 0; j < i; ++j ) { + if( found ) + StrBuf->AppendStr(&buf, ","); + else + found = true; + + StrBuf->Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d'", + guild_id, items[j].nameid, items[j].amount, items[j].identify, items[j].refine, items[j].attribute, items[j].expire_time, items[j].bound); + for( s = 0; s < MAX_SLOTS; ++s ) + StrBuf->Printf(&buf, ", '%d'", items[j].card[s]); + StrBuf->AppendStr(&buf, ")"); + } + + if( SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) + || SQL_ERROR == SQL->StmtExecute(stmt) ) + { + Sql_ShowDebug(sql_handle); + SQL->StmtFree(stmt); + StrBuf->Destroy(&buf); + return 1; + } + + StrBuf->Destroy(&buf); + SQL->StmtFree(stmt); + + //Finally reload storage and tell map we're done + mapif_load_guild_storage(fd,aid,guild_id,0); + mapif_itembound_ack(fd,aid,guild_id); + return 0; +} +#endif int inter_storage_parse_frommap(int fd) { @@ -242,6 +374,9 @@ int inter_storage_parse_frommap(int fd) switch(RFIFOW(fd,0)){ case 0x3018: mapif_parse_LoadGuildStorage(fd); break; case 0x3019: mapif_parse_SaveGuildStorage(fd); break; +#ifdef BOUND_ITEMS + case 0x3056: mapif_parse_itembound_retrieve(fd); break; +#endif default: return 0; } diff --git a/src/char/inter.c b/src/char/inter.c index 040246c31..54672faee 100644 --- a/src/char/inter.c +++ b/src/char/inter.c @@ -52,8 +52,8 @@ int inter_recv_packet_length[] = { -1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020- Party -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030- -1, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040- - -1,-1,10,10, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus] - 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish] + -1,-1,10,10, 0,-1, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus] [Mhalicot] + 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish] -1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, -1,10, 6,-1, // 3070- Mercenary packets [Zephyrus], Elemental packets [pakpil] 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080- -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator] diff --git a/src/common/mmo.h b/src/common/mmo.h index 5f75f35da..d5bf45adf 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -48,11 +48,11 @@ // 20120307 - 2012-03-07aRagexeRE+ - 0x970 #ifndef PACKETVER - #define PACKETVER 20120418 + #define PACKETVER 20130807 #endif // Comment the following line if your client is NOT ragexeRE (required because of conflicting packets in ragexe vs ragexeRE). -#define PACKETVER_RE +//#define PACKETVER_RE // Client support for experimental RagexeRE UI present in 2012-04-10 and 2012-04-18 #ifdef PACKETVER_RE @@ -222,7 +222,7 @@ struct item { char attribute; short card[MAX_SLOTS]; unsigned int expire_time; - char favorite; + char favorite, bound; uint64 unique_id; }; diff --git a/src/config/core.h b/src/config/core.h index b5ad1b794..481c35af8 100644 --- a/src/config/core.h +++ b/src/config/core.h @@ -61,6 +61,10 @@ /// By enabling it, the system will create an unique id for each new non stackable item created //#define NSI_UNIQUE_ID +/// Comment to disable Guild/Party Bound item system +/// By default, we recover/remove Guild/Party Bound items automatically +#define BOUND_ITEMS + /// Uncomment to enable real-time server stats (in and out data and ram usage). [Ai4rei] //#define SHOW_SERVER_STATS diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 146159c63..2900fde03 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -1081,22 +1081,29 @@ ACMD(heal) /*========================================== * @item command (usage: @item ) (modified by [Yor] for pet_egg) + * @itembound command (usage: @itembound ) (revised by [Mhalicot]) *------------------------------------------*/ ACMD(item) { char item_name[100]; - int number = 0, item_id, flag = 0; + int number = 0, item_id, flag = 0, bound = 0; struct item item_tmp; struct item_data *item_data; int get_count, i; memset(item_name, '\0', sizeof(item_name)); - - if (!message || !*message || ( - sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 && - sscanf(message, "%99s %d", item_name, &number) < 1 - )) { - clif->message(fd, msg_txt(983)); // Please enter an item name or ID (usage: @item ). + + if (!strcmpi(command+1,"itembound") && (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d %d", item_name, &number, &bound) < 2 && + sscanf(message, "%99s %d %d", item_name, &number, &bound) < 2 + ))) { + clif->message(fd, msg_txt(295)); // Please enter an item name or ID (usage: @itembound ). + return -1; + } else if (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 && + sscanf(message, "%99s %d", item_name, &number) < 1 )) + { + clif->message(fd, msg_txt(983)); // Please enter an item name or ID (usage: @item ). return false; } @@ -1110,11 +1117,24 @@ ACMD(item) return false; } + if( bound < 0 || bound > 4 ) { + clif->message(fd, msg_txt(298)); // Invalid bound type + return false; + } + item_id = item_data->nameid; get_count = number; //Check if it's stackable. - if (!itemdb->isstackable2(item_data)) - get_count = 1; + if (!itemdb->isstackable2(item_data)) { + if( bound && (item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) ) { + clif->message(fd, msg_txt(498)); // Cannot create bounded pet eggs or pet armors. + return false; + } + get_count = 1; + } else if( bound ) { + clif->message(fd, msg_txt(499)); // Cannot create bounded stackable items. + return false; + } for (i = 0; i < number; i += get_count) { // if not pet egg @@ -1122,6 +1142,7 @@ ACMD(item) memset(&item_tmp, 0, sizeof(item_tmp)); item_tmp.nameid = item_id; item_tmp.identify = 1; + item_tmp.bound = bound; if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) clif->additem(sd, 0, 0, flag); @@ -1134,21 +1155,27 @@ ACMD(item) } /*========================================== - * + * @item2 and @itembound2 command (revised by [Mhalicot]) *------------------------------------------*/ ACMD(item2) { struct item item_tmp; struct item_data *item_data; char item_name[100]; - int item_id, number = 0; + int item_id, number = 0, bound = 0; int identify = 0, refine = 0, attr = 0; int c1 = 0, c2 = 0, c3 = 0, c4 = 0; memset(item_name, '\0', sizeof(item_name)); - if (!message || !*message || ( - sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 && + if (!strcmpi(command+1,"itembound2") && (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 && + sscanf(message, "%99s %d %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 ))) { + clif->message(fd, msg_txt(296)); // Please enter all parameters (usage: @itembound2 + clif->message(fd, msg_txt(297)); // ). + return false; + } else if ( !message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 && sscanf(message, "%99s %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 )) { clif->message(fd, msg_txt(984)); // Please enter all parameters (usage: @item2 @@ -1158,7 +1185,12 @@ ACMD(item2) if (number <= 0) number = 1; - + + if( bound < 0 || bound > 4 ) { + clif->message(fd, msg_txt(298)); // Invalid bound type + return -1; + } + item_id = 0; if ((item_data = itemdb->search_name(item_name)) != NULL || (item_data = itemdb->exists(atoi(item_name))) != NULL) @@ -1169,9 +1201,14 @@ ACMD(item2) int loop, get_count, i; loop = 1; get_count = number; - if (item_data->type == IT_WEAPON || item_data->type == IT_ARMOR || - item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) { - loop = number; + if( !strcmpi(command+1,"itembound2") ) + bound = 1; + if( !itemdb->isstackable2(item_data) ) { + if( bound && (item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) ) { + clif->message(fd, msg_txt(498)); // Cannot create bounded pet eggs or pet armors. + return false; + } + loop = number; get_count = 1; if (item_data->type == IT_PETEGG) { identify = 1; @@ -1182,6 +1219,10 @@ ACMD(item2) if (refine > MAX_REFINE) refine = MAX_REFINE; } else { + if( bound ) { + clif->message(fd, msg_txt(499)); // Cannot create bounded stackable items. + return false; + } identify = 1; refine = attr = 0; } @@ -1195,6 +1236,7 @@ ACMD(item2) item_tmp.card[1] = c2; item_tmp.card[2] = c3; item_tmp.card[3] = c4; + item_tmp.bound = bound; if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) clif->additem(sd, 0, 0, flag); } @@ -9230,6 +9272,8 @@ void atcommand_basecommands(void) { ACMD_DEF(heal), ACMD_DEF(item), ACMD_DEF(item2), + ACMD_DEF2("itembound", item), + ACMD_DEF2("itembound2", item2), ACMD_DEF(itemreset), ACMD_DEF(clearstorage), ACMD_DEF(cleargstorage), diff --git a/src/map/buyingstore.c b/src/map/buyingstore.c index 2a9e6a88e..44ece49c6 100644 --- a/src/map/buyingstore.c +++ b/src/map/buyingstore.c @@ -290,8 +290,8 @@ void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int return; } - if( sd->status.inventory[index].expire_time || !itemdb_cantrade(&sd->status.inventory[index], pc->get_group_level(sd), pc->get_group_level(pl_sd)) || memcmp(sd->status.inventory[index].card, buyingstore->blankslots, sizeof(buyingstore->blankslots)) ) - {// non-tradable item + if( sd->status.inventory[index].expire_time || (sd->status.inventory[index].bound && !pc->can_give_bounded_items(sd)) || !itemdb_cantrade(&sd->status.inventory[index], pc->get_group_level(sd), pc->get_group_level(pl_sd)) || memcmp(sd->status.inventory[index].card, buyingstore->blankslots, sizeof(buyingstore->blankslots)) ) + {// non-tradable item clif->buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid); return; } diff --git a/src/map/clif.c b/src/map/clif.c index c1e7cb1c9..99f7c87d7 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -1802,10 +1802,13 @@ void clif_selllist(struct map_session_data *sd) if( !itemdb_cansell(&sd->status.inventory[i], pc->get_group_level(sd)) ) continue; - if( sd->status.inventory[i].expire_time ) - continue; // Cannot Sell Rental Items + if( sd->status.inventory[i].expire_time || (sd->status.inventory[i].bound && !pc->can_give_bounded_items(sd)) ) + continue; // Cannot Sell Rental Items or Account Bounded Items + + if( sd->status.inventory[i].bound && !pc->can_give_bounded_items(sd)) + continue; // Don't allow sale of bound items - val=sd->inventory_data[i]->value_sell; + val=sd->inventory_data[i]->value_sell; if( val < 0 ) continue; WFIFOW(fd,4+c*10)=i+2; @@ -2229,7 +2232,7 @@ void clif_additem(struct map_session_data *sd, int n, int amount, int fail) { p.HireExpireDate = sd->status.inventory[n].expire_time; #endif #if PACKETVER >= 20071002 - p.bindOnEquipType = 0; // unused + p.bindOnEquipType = sd->status.inventory[n].bound ? 2 : 0; #endif } p.result = (unsigned char)fail; @@ -2341,7 +2344,7 @@ void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *i, struct #endif #if PACKETVER >= 20080102 - p->bindOnEquipType = 0; + p->bindOnEquipType = i->bound ? 2 : 0; #endif #if PACKETVER >= 20100629 @@ -2378,6 +2381,7 @@ void clif_item_normal(short idx, struct NORMALITEM_INFO *p, struct item *i, stru #if PACKETVER >= 20080102 p->HireExpireDate = i->expire_time; + p->bindOnEquipType = i->bound ? 2 : 0; #endif #if PACKETVER >= 20120925 @@ -15061,8 +15065,9 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd) if( !pc->can_give_items(sd) || sd->status.inventory[idx].expire_time || !sd->status.inventory[idx].identify || - !itemdb_canauction(&sd->status.inventory[idx],pc->get_group_level(sd)) ) { // Quest Item or something else - clif->auction_setitem(sd->fd, idx, true); + !itemdb_canauction(&sd->status.inventory[idx],pc->get_group_level(sd)) || + (sd->status.inventory[idx].bound && !pc->can_give_bounded_items(sd)) ) { // Quest Item or something else + clif->auction_setitem(sd->fd, idx, true); return; } @@ -15139,9 +15144,10 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd) } // Auction checks... - if( sd->status.zeny < (auction.hours * battle_config.auction_feeperhour) ) { - clif->auction_message(fd, 5); // You do not have enough zeny to pay the Auction Fee. - return; + if( sd->status.inventory[sd->auction.index].bound && !pc->can_give_bounded_items(sd) ) { + clif->message(sd->fd, msg_txt(293)); + clif->auction_message(fd, 2); // The auction has been canceled + return; } if( auction.buynow > battle_config.auction_maximumprice ) diff --git a/src/map/guild.c b/src/map/guild.c index 0ae45bede..517a49cc4 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -865,6 +865,11 @@ int guild_member_withdraw(int guild_id, int account_id, int char_id, int flag, c online_member_sd = guild->getavailablesd(g); if(online_member_sd == NULL) return 0; // noone online to inform + +#ifdef BOUND_ITEMS + //Guild bound item check + guild->retrieveitembound(char_id,account_id,guild_id); +#endif if(!flag) clif->guild_leave(online_member_sd, name, mes); @@ -899,6 +904,41 @@ int guild_member_withdraw(int guild_id, int account_id, int char_id, int flag, c return 0; } +#ifdef BOUND_ITEMS +void guild_retrieveitembound(int char_id,int aid,int guild_id) +{ + TBL_PC *sd = map->id2sd(aid); + if(sd){ //Character is online + int idxlist[MAX_INVENTORY]; + int j,i; + j = pc->bound_chk(sd,2,idxlist); + if(j) { + struct guild_storage *gstor = gstorage->id2storage(guild_id); + for(i=0;iadditem(sd,gstor,&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); + } + gstorage->close(sd); //Close and save the storage + } + } + else { //Character is offline, ask char server to do the job + struct guild_storage *gstor = gstorage->id2storage2(guild_id); + if(gstor && gstor->storage_status == 1) { //Someone is in guild storage, close them + struct s_mapiterator* iter = mapit_getallusers(); + for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) { + if(sd->status.guild_id == guild_id && sd->state.storage_flag == 2) { + gstorage->close(sd); + break; + } + } + mapit->free(iter); + } + intif->itembound_req(char_id,aid,guild_id); + } +} +#endif + int guild_send_memberinfoshort(struct map_session_data *sd,int online) { // cleaned up [LuzZza] struct guild *g; @@ -1813,6 +1853,11 @@ int guild_break(struct map_session_data *sd,char *name) { struct guild *g; struct unit_data *ud; int i; + +#ifdef BOUND_ITEMS + int j; + int idxlist[MAX_INVENTORY]; +#endif nullpo_ret(sd); @@ -1855,6 +1900,13 @@ int guild_break(struct map_session_data *sd,char *name) { skill->del_unitgroup(groups[i],ALC_MARK); } } + +#ifdef BOUND_ITEMS + //Guild bound item check - Removes the bound flag + j = pc->bound_chk(sd,2,idxlist); + for(i=0;istatus.inventory[idxlist[i]].bound = 0; +#endif intif->guild_break(g->guild_id); return 1; diff --git a/src/map/guild.h b/src/map/guild.h index 348a6c7e4..57148867a 100644 --- a/src/map/guild.h +++ b/src/map/guild.h @@ -147,6 +147,10 @@ struct guild_interface { void (*flags_clear) (void); /* guild aura */ void (*aura_refresh) (struct map_session_data *sd, uint16 skill_id, uint16 skill_lv); + /* item bound [Mhalicot]*/ +#ifdef BOUND_ITEMS + void (*retrieveitembound) (int char_id,int aid,int guild_id); +#endif /* */ int (*payexp_timer) (int tid, int64 tick, int id, intptr_t data); TBL_PC* (*sd_check) (int guild_id, int account_id, int char_id); diff --git a/src/map/intif.c b/src/map/intif.c index f31ab0f5a..b8b16a356 100644 --- a/src/map/intif.c +++ b/src/map/intif.c @@ -982,15 +982,19 @@ void intif_parse_LoadGuildStorage(int fd) { struct guild_storage *gstor; struct map_session_data *sd; - int guild_id; + int guild_id, flag; guild_id = RFIFOL(fd,8); + flag = RFIFOL(fd,12); if(guild_id <= 0) return; sd=map->id2sd( RFIFOL(fd,4) ); - if(sd==NULL){ - ShowError("intif_parse_LoadGuildStorage: user not found %d\n",RFIFOL(fd,4)); - return; + 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)); + return; + } + } gstor=gstorage->id2storage(guild_id); if(!gstor) { @@ -998,20 +1002,21 @@ void intif_parse_LoadGuildStorage(int fd) return; } if (gstor->storage_status == 1) { // Already open.. lets ignore this update - ShowWarning("intif_parse_LoadGuildStorage: storage received for a client already open (User %d:%d)\n", sd->status.account_id, sd->status.char_id); - return; + 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; } if (gstor->dirty) { // Already have storage, and it has been modified and not saved yet! Exploit! [Skotlex] - ShowWarning("intif_parse_LoadGuildStorage: received storage for an already modified non-saved storage! (User %d:%d)\n", sd->status.account_id, sd->status.char_id); - return; + ShowWarning("intif_parse_LoadGuildStorage: received storage for an already modified non-saved storage! (User %d:%d)\n", flag?sd->status.account_id:1, flag?sd->status.char_id:1); + return; } - if( RFIFOW(fd,2)-12 != sizeof(struct guild_storage) ){ - ShowError("intif_parse_LoadGuildStorage: data size error %d %d\n",RFIFOW(fd,2)-12 , sizeof(struct guild_storage)); - gstor->storage_status = 0; + 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; return; } - memcpy(gstor,RFIFOP(fd,12),sizeof(struct guild_storage)); + memcpy(gstor,RFIFOP(fd,13),sizeof(struct guild_storage)); + if( flag ) gstorage->open(sd); } @@ -2005,7 +2010,31 @@ void intif_parse_MessageToFD(int fd) { return; } +/*========================================== + * Item Bound System [Xantara][Mhalicot] + *------------------------------------------*/ +#ifdef BOUND_ITEMS +void intif_itembound_req(int char_id,int aid,int guild_id) { + struct guild_storage *gstor = gstorage->id2storage2(guild_id); + WFIFOHEAD(inter_fd,12); + WFIFOW(inter_fd,0) = 0x3056; + WFIFOL(inter_fd,2) = char_id; + WFIFOL(inter_fd,6) = aid; + WFIFOW(inter_fd,10) = guild_id; + WFIFOSET(inter_fd,12); + if(gstor) + gstor->lock = 1; //Lock for retrieval process +} + +//3856 +void intif_parse_Itembound_ack(int fd) { + struct guild_storage *gstor; + int guild_id = RFIFOW(fd,6); + gstor = gstorage->id2storage2(guild_id); + if(gstor) gstor->lock = 0; //Unlock now that operation is completed +} +#endif //----------------------------------------------------------------- // Communication from the inter server // Return a 0 (false) if there were any errors. @@ -2088,7 +2117,10 @@ int intif_parse(int fd) case 0x3853: intif->pAuctionClose(fd); break; case 0x3854: intif->pAuctionMessage(fd); break; case 0x3855: intif->pAuctionBid(fd); break; - + //Bound items +#ifdef BOUND_ITEMS + case 0x3856: intif->pItembound_ack(fd); break; +#endif // Mercenary System case 0x3870: intif->pMercenaryReceived(fd); break; case 0x3871: intif->pMercenaryDeleted(fd); break; @@ -2127,8 +2159,8 @@ void intif_defaults(void) { 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3850 Auctions [Zephyrus] - -1, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3860 Quests [Kevin] [Inkfish] + -1,-1, 7, 7, 7,11, 8, 0, 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] 11,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3880 -1,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3890 Homunculus [albator] @@ -2263,6 +2295,7 @@ void intif_defaults(void) { intif->pAuctionClose = intif_parse_AuctionClose; intif->pAuctionMessage = intif_parse_AuctionMessage; intif->pAuctionBid = intif_parse_AuctionBid; + intif->pItembound_ack = intif_parse_Itembound_ack; intif->pMercenaryReceived = intif_parse_MercenaryReceived; intif->pMercenaryDeleted = intif_parse_MercenaryDeleted; intif->pMercenarySaved = intif_parse_MercenarySaved; diff --git a/src/map/intif.h b/src/map/intif.h index 768e735de..577d58923 100644 --- a/src/map/intif.h +++ b/src/map/intif.h @@ -75,6 +75,9 @@ struct intif_interface { int (*guild_emblem) (int guild_id, int len, const char *data); int (*guild_castle_dataload) (int num, int *castle_ids); int (*guild_castle_datasave) (int castle_id, int index, int value); +#ifdef BOUND_ITEMS + void (*itembound_req) (int char_id, int aid, int guild_id); +#endif int (*request_petdata) (int account_id, int char_id, int pet_id); int (*save_petdata) (int account_id, struct s_pet *p); int (*delete_petdata) (int pet_id); @@ -161,6 +164,7 @@ struct intif_interface { void (*pAuctionClose) (int fd); void (*pAuctionMessage) (int fd); void (*pAuctionBid) (int fd); + void (*pItembound_ack) (int fd); void (*pMercenaryReceived) (int fd); void (*pMercenaryDeleted) (int fd); void (*pMercenarySaved) (int fd); diff --git a/src/map/mail.c b/src/map/mail.c index 2378cbe2a..6b1537d87 100644 --- a/src/map/mail.c +++ b/src/map/mail.c @@ -82,8 +82,9 @@ unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount) { if( amount < 0 || amount > sd->status.inventory[idx].amount ) return 1; if( !pc->can_give_items(sd) || sd->status.inventory[idx].expire_time || - !itemdb_canmail(&sd->status.inventory[idx],pc->get_group_level(sd)) ) - return 1; + !itemdb_canmail(&sd->status.inventory[idx],pc->get_group_level(sd)) || + (sd->status.inventory[idx].bound && !pc->can_give_bounded_items(sd)) ) + return 1; sd->mail.index = idx; sd->mail.nameid = sd->status.inventory[idx].nameid; diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index 813aebee0..e6f68ea4f 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -212,6 +212,7 @@ struct NORMALITEM_INFO { #endif #if PACKETVER >= 20080102 int HireExpireDate; + unsigned short bindOnEquipType; #endif #if PACKETVER >= 20120925 struct { diff --git a/src/map/party.c b/src/map/party.c index ab05c23f7..69b343fb7 100644 --- a/src/map/party.c +++ b/src/map/party.c @@ -547,7 +547,14 @@ int party_member_withdraw(int party_id, int account_id, int char_id) } if( sd && sd->status.party_id == party_id && sd->status.char_id == char_id ) { - sd->status.party_id = 0; +#ifdef BOUND_ITEMS + int idxlist[MAX_INVENTORY]; //or malloc to reduce consumtion + int j,i; + j = pc->bound_chk(sd,3,idxlist); + for(i=0;idelitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_OTHER); +#endif + sd->status.party_id = 0; clif->charnameupdate(sd); //Update name display [Skotlex] //TODO: hp bars should be cleared too if( p->instances ) diff --git a/src/map/pc.c b/src/map/pc.c index 35d883b6f..ba445b4f4 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -568,6 +568,14 @@ bool pc_can_give_items(struct map_session_data *sd) return pc->has_permission(sd, PC_PERM_TRADE); } +/** + * Determines if player can give / drop / trade / vend bounded items + */ +bool pc_can_give_bounded_items(struct map_session_data *sd) +{ + return pc->has_permission(sd, PC_PERM_TRADE_BOUNDED); +} + /*========================================== * prepares character for saving. *------------------------------------------*/ @@ -991,6 +999,10 @@ int pc_isequip(struct map_session_data *sd,int n) *------------------------------------------*/ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, struct mmo_charstatus *st, bool changing_mapservers) { int i; +#ifdef BOUND_ITEMS + int j; + int idxlist[MAX_INVENTORY]; +#endif int64 tick = timer->gettick(); uint32 ip = session[sd->fd]->client_addr; @@ -1190,7 +1202,15 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim * Check if player have any item cooldowns on **/ pc->itemcd_do(sd,true); - + +#ifdef BOUND_ITEMS + // Party bound item check + if(sd->status.party_id == 0 && (j = pc->bound_chk(sd,3,idxlist))) { // Party was deleted while character offline + for(i=0;idelitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_OTHER); + } +#endif + /* [Ind/Hercules] */ sd->sc_display = NULL; sd->sc_display_count = 0; @@ -3948,8 +3968,8 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l { // Stackable | Non Rental for( i = 0; i < MAX_INVENTORY; i++ ) { - if( sd->status.inventory[i].nameid == item_data->nameid && memcmp(&sd->status.inventory[i].card, &item_data->card, sizeof(item_data->card)) == 0 ) - { + if( sd->status.inventory[i].nameid == item_data->nameid && sd->status.inventory[i].bound == item_data->bound && memcmp(&sd->status.inventory[i].card, &item_data->card, sizeof(item_data->card)) == 0 ) + { if( amount > MAX_AMOUNT - sd->status.inventory[i].amount || ( data->stack.inventory && amount > data->stack.amount - sd->status.inventory[i].amount ) ) return 5; sd->status.inventory[i].amount += amount; @@ -4500,8 +4520,8 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun return 1; } - if( !itemdb_cancartstore(item_data, pc->get_group_level(sd)) ) - { // Check item trade restrictions [Skotlex] + if( !itemdb_cancartstore(item_data, pc->get_group_level(sd)) || (item_data->bound > 1 && !pc->can_give_bounded_items(sd))) + { // Check item trade restrictions [Skotlex] clif->message (sd->fd, msg_txt(264)); return 1;/* TODO: there is no official response to this? */ } @@ -4513,8 +4533,8 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun if( itemdb->isstackable2(data) && !item_data->expire_time ) { ARR_FIND( 0, MAX_CART, i, - sd->status.cart[i].nameid == item_data->nameid && - sd->status.cart[i].card[0] == item_data->card[0] && sd->status.cart[i].card[1] == item_data->card[1] && + sd->status.cart[i].nameid == item_data->nameid && sd->status.cart[i].bound == item_data->bound && + sd->status.cart[i].card[0] == item_data->card[0] && sd->status.cart[i].card[1] == item_data->card[1] && sd->status.cart[i].card[2] == item_data->card[2] && sd->status.cart[i].card[3] == item_data->card[3] ); }; @@ -4647,7 +4667,25 @@ int pc_getitemfromcart(struct map_session_data *sd,int idx,int amount) return flag; } - + /*========================================== + * Bound Item Check + * Type: + * 1 Account Bound + * 2 Guild Bound + * 3 Party Bound + * 4 Character Bound + *------------------------------------------*/ +int pc_bound_chk(TBL_PC *sd,int type,int *idxlist) +{ + int i=0, j=0; + for(i=0;istatus.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0 && sd->status.inventory[i].bound == type) { + idxlist[j] = i; + j++; + } + } + return j; +} /*========================================== * Display item stolen msg to player sd *------------------------------------------*/ @@ -7965,8 +8003,8 @@ int pc_setmadogear(TBL_PC* sd, int flag) *------------------------------------------*/ int pc_candrop(struct map_session_data *sd, struct item *item) { - if( item && item->expire_time ) - return 0; + if( item && (item->expire_time || (item->bound && !pc->can_give_bounded_items(sd))) ) + return 0; if( !pc->can_give_items(sd) ) //check if this GM level can drop items return 0; return (itemdb_isdropable(item, pc->get_group_level(sd))); @@ -10293,6 +10331,7 @@ void pc_defaults(void) { pc->class2idx = pc_class2idx; pc->get_group_level = pc_get_group_level; pc->can_give_items = pc_can_give_items; + pc->can_give_bounded_items = pc_can_give_bounded_items; pc->can_use_command = pc_can_use_command; pc->has_permission = pc_has_permission; diff --git a/src/map/pc.h b/src/map/pc.h index fc37d0ef2..d517d8fcf 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -749,7 +749,8 @@ struct pc_interface { int (*get_group_level) (struct map_session_data *sd); //int (*getrefinebonus) (int lv,int type); FIXME: This function does not exist, nor it is ever called bool (*can_give_items) (struct map_session_data *sd); - + bool (*can_give_bounded_items) (struct map_session_data *sd); + bool (*can_use_command) (struct map_session_data *sd, const char *command); bool (*has_permission) (struct map_session_data *sd, enum e_pc_permission permission); int (*set_group) (struct map_session_data *sd, int group_id); @@ -788,6 +789,10 @@ struct pc_interface { int (*additem) (struct map_session_data *sd,struct item *item_data,int amount,e_log_pick_type log_type); int (*getzeny) (struct map_session_data *sd,int zeny, enum e_log_pick_type type, struct map_session_data *tsd); int (*delitem) (struct map_session_data *sd,int n,int amount,int type, short reason, e_log_pick_type log_type); + + //Bound items + int (*bound_chk) (TBL_PC *sd,int type,int *idxlist); + // Special Shop System int (*paycash) (struct map_session_data *sd, int price, int points); int (*getcash) (struct map_session_data *sd, int cash, int points); diff --git a/src/map/pc_groups.c b/src/map/pc_groups.c index be02b5f15..41bc19cba 100644 --- a/src/map/pc_groups.c +++ b/src/map/pc_groups.c @@ -55,6 +55,7 @@ const struct pc_permission_name_table pc_g_permission_name[NUM_PC_PERM] = { { "disable_pvp", PC_PERM_DISABLE_PVP }, { "disable_commands_when_dead", PC_PERM_DISABLE_CMD_DEAD }, { "hchsys_admin", PC_PERM_HCHSYS_ADMIN }, + { "can_trade_bounded", PC_PERM_TRADE_BOUNDED }, }; static DBMap* pc_group_db; // id -> GroupSettings diff --git a/src/map/pc_groups.h b/src/map/pc_groups.h index 8f350c2b6..63e7acc51 100644 --- a/src/map/pc_groups.h +++ b/src/map/pc_groups.h @@ -30,6 +30,7 @@ enum e_pc_permission { PC_PERM_DISABLE_PVP = 0x080000, // #20 PC_PERM_DISABLE_CMD_DEAD = 0x100000, PC_PERM_HCHSYS_ADMIN = 0x200000, + PC_PERM_TRADE_BOUNDED = 0x400000, }; /// Total number of PC permissions (without PC_PERM_NONE). @@ -37,7 +38,7 @@ enum e_pc_permission { /// so it's possible to apply sizeof to it [C-FAQ 1.24] /// Whenever adding new permission: 1. add enum entry above, 2. add entry into /// pc_g_permission_name (in pc.c), 3. increase NUM_PC_PERM below by 1. -#define NUM_PC_PERM 22 +#define NUM_PC_PERM 23 struct pc_permission_name_table { const char *name; diff --git a/src/map/script.c b/src/map/script.c index d51f27ce9..174d12316 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -5946,6 +5946,7 @@ BUILDIN(rentitem) it.nameid = nameid; it.identify = 1; it.expire_time = (unsigned int)(time(NULL) + seconds); + it.bound = 0; if( (flag = pc->additem(sd, &it, 1, LOG_TYPE_SCRIPT)) ) { @@ -10850,6 +10851,7 @@ BUILDIN(successremovecards) { item_tmp.refine = sd->status.inventory[i].refine; item_tmp.attribute = sd->status.inventory[i].attribute; item_tmp.expire_time = sd->status.inventory[i].expire_time; + item_tmp.bound = sd->status.inventory[i].bound; for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++) item_tmp.card[j]=sd->status.inventory[i].card[j]; @@ -10923,7 +10925,8 @@ BUILDIN(failedremovecards) { item_tmp.refine = sd->status.inventory[i].refine; item_tmp.attribute = sd->status.inventory[i].attribute; item_tmp.expire_time = sd->status.inventory[i].expire_time; - + item_tmp.bound = sd->status.inventory[i].bound; + for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++) item_tmp.card[j]=sd->status.inventory[i].card[j]; @@ -11573,7 +11576,8 @@ BUILDIN(getinventorylist) pc->setreg(sd,reference_uid(script->add_str(card_var), j),sd->status.inventory[i].card[k]); } pc->setreg(sd,reference_uid(script->add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time); - j++; + pc->setreg(sd,reference_uid(script->add_str("@inventorylist_bound"), j),sd->status.inventory[i].bound); + j++; } } pc->setreg(sd,script->add_str("@inventorylist_count"),j); @@ -17529,6 +17533,219 @@ BUILDIN(bg_join_team) { return true; } + +/*==============[Mhalicot]================== + * getitembound ,,{,}; + * getitembound "",,{,}; + * Type: + * 1 - Account Bound + * 2 - Guild Bound + * 3 - Party Bound + * 4 - Character Bound + *------------------------------------------*/ +BUILDIN(getitembound) +{ + int nameid, amount, i, flag; + struct item it; + struct script_data *data; + char bound = script_getnum(st,4); + TBL_PC *sd; + + data = script_getdata(st,2); + get_val(st,data); + if( data_isstring(data) ) { // "" + const char *name = script->conv_str(st,data); + struct item_data *item_data = itemdb->search_name(name); + if( item_data == NULL ) { + ShowError("buildin_getitembound: Nonexistant item %s requested.\n", name); + return 1; //No item created. + } + nameid = item_data->nameid; + } else if( data_isint(data) ) { // + nameid = script->conv_num(st,data); + if( nameid <= 0 || !itemdb->exists(nameid) ) { + ShowError("buildin_getitembound: Nonexistant item %d requested.\n", nameid); + return 1; //No item created. + } + } else { + ShowError("buildin_getitembound: invalid data type for argument #1 (%d).", data->type); + return 1; + } + + if( itemdb->isstackable(nameid) || itemdb_type(nameid) == IT_PETEGG ) { + ShowError("buildin_getitembound: invalid item type. Bound only work for non stackeable items (Item %d).", nameid); + return 1; + } + + if( (amount = script_getnum(st,3)) <= 0) + return 0; //return if amount <=0, skip the useless iteration + + memset(&it,0,sizeof(it)); + it.nameid = nameid; + it.identify = 1; + it.bound = bound; + + if( bound < 1 || bound > 4) { //Not a correct bound type + ShowError("script_getitembound: Not a correct bound type! Type=%d\n",bound); + return 1; + } + + if( script_hasdata(st,5) ) + sd=map->id2sd(script_getnum(st,5)); // Account ID + else + sd=script->rid2sd(st); // Attached player + + if( sd == NULL ) // no target + return 0; + + for( i = 0; i < amount; i++ ) { + if( (flag = pc->additem(sd, &it, 1, LOG_TYPE_SCRIPT)) ) { + clif->additem(sd, 0, 0, flag); + if( pc->candrop(sd,&it) ) + map->addflooritem(&it,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + } + } + + return 0; +} + +/*==============[Mhalicot]================== + * getitembound2 ,,,,,,,,,; + * getitembound2 "",,,,,,,,,; + *------------------------------------------*/ +BUILDIN(getitembound2) +{ + int nameid,amount,get_count,i,flag = 0; + int iden,ref,attr,c1,c2,c3,c4; + char bound=0; + struct item_data *item_data; + struct item item_tmp; + TBL_PC *sd; + struct script_data *data; + + bound = script_getnum(st,11); + if( bound < 1 || bound > 4) { //Not a correct bound type + ShowError("script_getitembound2: Not a correct bound type! Type=%d\n",bound); + return 1; + } + if( script_hasdata(st,12) ) + sd=map->id2sd(script_getnum(st,12)); + else + sd=script->rid2sd(st); // Attached player + + if( sd == NULL ) // no target + return true; + + data=script_getdata(st,2); + script->get_val(st,data); + if( data_isstring(data) ){ + const char *name=script->conv_str(st,data); + struct item_data *item_data = itemdb->search_name(name); + if( item_data ) + nameid=item_data->nameid; + else + nameid=UNKNOWN_ITEM_ID; + }else + nameid=script->conv_num(st,data); + + amount=script_getnum(st,3); + iden=script_getnum(st,4); + ref=script_getnum(st,5); + attr=script_getnum(st,6); + c1=(short)script_getnum(st,7); + c2=(short)script_getnum(st,8); + c3=(short)script_getnum(st,9); + c4=(short)script_getnum(st,10); + + if(nameid<0) { // Invalide nameid + nameid = -nameid; + flag = 1; + } + + if(nameid > 0) { + memset(&item_tmp,0,sizeof(item_tmp)); + item_data=itemdb->exists(nameid); + if (item_data == NULL) + return -1; + if(item_data->type==IT_WEAPON || item_data->type==IT_ARMOR){ + if(ref > MAX_REFINE) ref = MAX_REFINE; + } + else if(item_data->type==IT_PETEGG) { + iden = 1; + ref = 0; + } + else { + iden = 1; + ref = attr = 0; + } + + item_tmp.nameid=nameid; + if(!flag) + item_tmp.identify=iden; + else if(item_data->type==IT_WEAPON || item_data->type==IT_ARMOR) + item_tmp.identify=0; + item_tmp.refine=ref; + item_tmp.attribute=attr; + item_tmp.card[0]=(short)c1; + item_tmp.card[1]=(short)c2; + item_tmp.card[2]=(short)c3; + item_tmp.card[3]=(short)c4; + item_tmp.bound=bound; + + //Check if it's stackable. + if (!itemdb->isstackable(nameid)) + get_count = 1; + else + get_count = amount; + + for (i = 0; i < amount; i += get_count) { + // if not pet egg + if (!pet->create_egg(sd, nameid)) { + if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_SCRIPT))) { + clif->additem(sd, 0, 0, flag); + if( pc->candrop(sd,&item_tmp) ) + map->addflooritem(&item_tmp,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + } + } + } + } + + return true; +} +/*==============[Mhalicot]================== + * countbound {}; + * Creates an array of bounded item IDs + * Returns amount of items found + * Type: + * 1 - Account Bound + * 2 - Guild Bound + * 3 - Party Bound + *------------------------------------------*/ +BUILDIN(countbound) +{ + int i, type, j=0, k=0; + TBL_PC *sd; + + if( (sd = script->rid2sd(st)) == NULL ) + return false; + + type = script_hasdata(st,2)?script_getnum(st,2):0; + + for(i=0;istatus.inventory[i].nameid > 0 && ( + (!type && sd->status.inventory[i].bound > 0) || + (type && sd->status.inventory[i].bound == type) + )) { + pc->setreg(sd,reference_uid(script->add_str("@bound_items"), k),sd->status.inventory[i].nameid); + k++; + j += sd->status.inventory[i].amount; + } + } + + script_pushint(st,j); + return 0; +} + /* bg_match_over( arena_name {, optional canceled } ) */ /* returns 0 when successful, 1 otherwise */ BUILDIN(bg_match_over) { @@ -18109,7 +18326,13 @@ void script_parse_builtin(void) { BUILDIN_DEF(bindatcmd, "ss???"), BUILDIN_DEF(unbindatcmd, "s"), BUILDIN_DEF(useatcmd, "s"), - + /** + * Item bound [Mhalicot\Hercules] + **/ + BUILDIN_DEF(getitembound,"vii?"), + BUILDIN_DEF(getitembound2,"viiiiiiiii?"), + BUILDIN_DEF(countbound, "?"), + //Quest Log System [Inkfish] BUILDIN_DEF(questinfo, "ii??"), BUILDIN_DEF(setquest, "i"), diff --git a/src/map/storage.c b/src/map/storage.c index cc1100d28..df406257d 100644 --- a/src/map/storage.c +++ b/src/map/storage.c @@ -107,7 +107,8 @@ int compare_item(struct item *a, struct item *b) a->identify == b->identify && a->refine == b->refine && a->attribute == b->attribute && - a->expire_time == b->expire_time ) + a->expire_time == b->expire_time && + a->bound == b->bound ) { int i; for (i = 0; i < MAX_SLOTS && (a->card[i] == b->card[i]); i++); @@ -140,6 +141,11 @@ int storage_additem(struct map_session_data* sd, struct item* item_data, int amo return 1; } + if( (item_data->bound > 1) && !pc->can_give_bounded_items(sd) ) { + clif->message(sd->fd, msg_txt(294)); + return 1; + } + if( itemdb->isstackable2(data) ) {//Stackable for( i = 0; i < MAX_STORAGE; i++ ) @@ -429,12 +435,17 @@ int guild_storage_additem(struct map_session_data* sd, struct guild_storage* sto return 1; } - if( !itemdb_canguildstore(item_data, pc->get_group_level(sd)) || item_data->expire_time ) - { //Check if item is storable. [Skotlex] + if( !itemdb_canguildstore(item_data, pc->get_group_level(sd)) || item_data->expire_time || (item_data->bound && !pc->can_give_bounded_items(sd)) ) + { //Check if item is storable. [Skotlex] clif->message (sd->fd, msg_txt(264)); return 1; } + if( (item_data->bound == 1 || item_data->bound > 2) && !pc->can_give_bounded_items(sd) ) { + clif->message(sd->fd, msg_txt(294)); + return 1; + } + if(itemdb->isstackable2(data)){ //Stackable for(i=0;iitems[i], item_data)) { diff --git a/src/map/trade.c b/src/map/trade.c index 8dd30371b..7085fdda3 100644 --- a/src/map/trade.c +++ b/src/map/trade.c @@ -365,6 +365,12 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount) return; } + if( ((item->bound == 1 || item->bound > 2) || (item->bound == 2 && sd->status.guild_id != target_sd->status.guild_id)) && !pc->can_give_bounded_items(sd) ) { // Item Bound + clif->message(sd->fd, msg_txt(293)); + clif->tradeitemok(sd, index+2, 1); + return; + } + //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 diff --git a/src/map/vending.c b/src/map/vending.c index 7d6d02cfb..be3826754 100644 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -257,7 +257,8 @@ void vending_openvending(struct map_session_data* sd, const char* message, const || !sd->status.cart[index].identify // unidentified item || sd->status.cart[index].attribute == 1 // broken item || sd->status.cart[index].expire_time // It should not be in the cart but just in case - || !itemdb_cantrade(&sd->status.cart[index], pc->get_group_level(sd), pc->get_group_level(sd)) ) // untradeable item + || (sd->status.cart[index].bound && !pc->can_give_bounded_items(sd)) // can't trade account bound items and has no permission + || !itemdb_cantrade(&sd->status.cart[index], pc->get_group_level(sd), pc->get_group_level(sd)) ) // untradeable item continue; sd->vending[i].index = index; -- cgit v1.2.3-70-g09d2 From 5c94e76753c0cdb4ffb7dabbd6e135f1f7d42ef2 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Sat, 2 Nov 2013 17:16:07 -0200 Subject: Updated to latest Hercules Signed-off-by: shennetsind --- sql-files/main.sql | 4 ++++ sql-files/upgrades/index.txt | 1 + src/common/mmo.h | 3 +++ 3 files changed, 8 insertions(+) (limited to 'sql-files/main.sql') diff --git a/sql-files/main.sql b/sql-files/main.sql index 2c91d58b1..f8a225ee9 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -661,6 +661,7 @@ INSERT INTO `sql_updates` (`timestamp`) VALUES (1366078541); INSERT INTO `sql_updates` (`timestamp`) VALUES (1381354728); INSERT INTO `sql_updates` (`timestamp`) VALUES (1381423003); INSERT INTO `sql_updates` (`timestamp`) VALUES (1382892428); +INSERT INTO `sql_updates` (`timestamp`) VALUES (1383162785); INSERT INTO `sql_updates` (`timestamp`) VALUES (1383167577); -- @@ -715,6 +716,9 @@ INSERT INTO `interreg` (`varname`, `value`) VALUES CREATE TABLE IF NOT EXISTS `account_data` ( `account_id` int(11) unsigned NOT NULL default '0', `bank_vault` int(11) unsigned NOT NULL default '0', + `base_exp` TINYINT( 4 ) UNSIGNED NOT NULL default '0', + `base_drop` TINYINT( 4 ) UNSIGNED NOT NULL default '0', + `base_death` TINYINT( 4 ) UNSIGNED NOT NULL default '0', PRIMARY KEY (`account_id`) ) ENGINE=MyISAM; diff --git a/sql-files/upgrades/index.txt b/sql-files/upgrades/index.txt index ca06e9c31..1fc0ebd77 100644 --- a/sql-files/upgrades/index.txt +++ b/sql-files/upgrades/index.txt @@ -7,4 +7,5 @@ 2013-10-09--21-38.sql 2013-10-10--16-36.sql 2013-10-27--16-47.sql +2013-10-30--19-53.sql 2013-10-30--21-12.sql \ No newline at end of file diff --git a/src/common/mmo.h b/src/common/mmo.h index 5f75f35da..603ec7573 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -415,6 +415,9 @@ struct mmo_charstatus { time_t delete_date; + /* `account_data` modifiers */ + unsigned short mod_exp,mod_drop,mod_death; + unsigned char font; }; -- cgit v1.2.3-70-g09d2 From b9b32ac7609e33c21b488d722103cc0eea16b12c Mon Sep 17 00:00:00 2001 From: shennetsind Date: Thu, 7 Nov 2013 16:04:51 -0200 Subject: Item Bound Fixes/Adjustments/Improvements Special Thanks to Haruna Signed-off-by: shennetsind --- conf/groups.conf | 2 +- conf/messages.conf | 4 +- doc/permissions.txt | 2 +- sql-files/main.sql | 1 + sql-files/upgrades/2013-10-31--07-49.sql | 4 +- sql-files/upgrades/index.txt | 3 +- src/char/char.c | 32 ++-- src/char/int_storage.c | 58 ++++--- src/char/inter.c | 18 +-- src/common/mmo.h | 12 +- src/config/core.h | 3 +- src/map/atcommand.c | 20 +-- src/map/clif.c | 33 ++-- src/map/clif.h | 8 + src/map/guild.c | 39 ++--- src/map/guild.h | 2 - src/map/intif.c | 28 ++-- src/map/intif.h | 2 - src/map/mail.c | 6 +- src/map/packets_struct.h | 1 - src/map/party.c | 10 +- src/map/pc.c | 92 +++++++---- src/map/pc.h | 5 +- src/map/pc_groups.c | 2 +- src/map/pc_groups.h | 2 +- src/map/script.c | 252 ++++++++----------------------- src/map/script.h | 1 + src/map/storage.c | 8 +- src/map/trade.c | 23 +-- src/map/vending.c | 2 +- 30 files changed, 285 insertions(+), 390 deletions(-) (limited to 'sql-files/main.sql') diff --git a/conf/groups.conf b/conf/groups.conf index c1a8d10e6..d31f46f24 100644 --- a/conf/groups.conf +++ b/conf/groups.conf @@ -261,7 +261,7 @@ groups: ( log_commands: true permissions: { can_trade: true - can_trade_bounded: false + can_trade_bound: false can_party: true all_skill: false all_equipment: false diff --git a/conf/messages.conf b/conf/messages.conf index 3564de043..2d429d79e 100644 --- a/conf/messages.conf +++ b/conf/messages.conf @@ -317,8 +317,8 @@ 291: Weather effects will dispell on warp/refresh 292: Killer state reset. //Item Bind System -293: This bounded item cannot be traded to that character. -294: This bounded item cannot be stored there. +293: This bound item cannot be traded to that character. +294: This bound item cannot be stored there. 295: Please enter an item name or ID (usage: @itembound ). 296: Please enter all parameters (usage: @itembound2 297: ). diff --git a/doc/permissions.txt b/doc/permissions.txt index c2aeba081..7280395dc 100644 --- a/doc/permissions.txt +++ b/doc/permissions.txt @@ -31,5 +31,5 @@ show_bossmobs : Ability to see boss mobs with @showmobs. disable_pvm : Ability to disable Player vs. Monster. disable_pvp : Ability to disable Player vs. Player. disable_commands_when_dead : Ability to disable @command usage when dead. -can_trade_bounded : Ability to trade or otherwise distribute bounded items (drop, storage, vending etc...). +can_trade_bound: Ability to trade or otherwise distribute bound items (drop, storage, vending etc...). hchsys_admin : Hercules Chat System Admin (Ability to modify channel settings regardless of ownership and join password-protected channels without requiring a password.) diff --git a/sql-files/main.sql b/sql-files/main.sql index ddf3b6712..387d01893 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -666,6 +666,7 @@ INSERT INTO `sql_updates` (`timestamp`) VALUES (1381423003); INSERT INTO `sql_updates` (`timestamp`) VALUES (1382892428); INSERT INTO `sql_updates` (`timestamp`) VALUES (1383162785); INSERT INTO `sql_updates` (`timestamp`) VALUES (1383167577); +INSERT INTO `sql_updates` (`timestamp`) VALUES (1383205740); -- -- Table structure for table `sstatus` diff --git a/sql-files/upgrades/2013-10-31--07-49.sql b/sql-files/upgrades/2013-10-31--07-49.sql index 40e0421c8..e18c7e20d 100644 --- a/sql-files/upgrades/2013-10-31--07-49.sql +++ b/sql-files/upgrades/2013-10-31--07-49.sql @@ -1,4 +1,6 @@ +#1383205740 ALTER TABLE `inventory` ADD COLUMN `bound` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `favorite`; ALTER TABLE `cart_inventory` ADD COLUMN `bound` tinyint(1) UNSIGNED NOT NULL default '0' AFTER `expire_time`; ALTER TABLE `storage` ADD COLUMN `bound` tinyint(1) UNSIGNED NOT NULL default '0' AFTER `expire_time`; -ALTER TABLE `guild_storage` ADD COLUMN `bound` TINYINT(3) UNSIGNED NOT NULL default '0' AFTER `expire_time`; \ No newline at end of file +ALTER TABLE `guild_storage` ADD COLUMN `bound` TINYINT(3) UNSIGNED NOT NULL default '0' AFTER `expire_time`; +INSERT INTO `sql_updates` (`timestamp`) VALUES (1383205740); \ No newline at end of file diff --git a/sql-files/upgrades/index.txt b/sql-files/upgrades/index.txt index 1fc0ebd77..133366319 100644 --- a/sql-files/upgrades/index.txt +++ b/sql-files/upgrades/index.txt @@ -8,4 +8,5 @@ 2013-10-10--16-36.sql 2013-10-27--16-47.sql 2013-10-30--19-53.sql -2013-10-30--21-12.sql \ No newline at end of file +2013-10-30--21-12.sql +2013-10-31--07-49.sql \ No newline at end of file diff --git a/src/char/char.c b/src/char/char.c index 9e84f0245..ce4fcbe53 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -747,7 +747,7 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); - SQL->StmtBindColumn(stmt, 8, SQLDT_UINT, &item.bound, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 8, SQLDT_UCHAR, &item.bound, 0, NULL, NULL); for( j = 0; j < MAX_SLOTS; ++j ) SQL->StmtBindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); @@ -894,7 +894,7 @@ int inventory_to_sql(const struct item items[], int max, int id) { SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 8, SQLDT_CHAR, &item.favorite, 0, NULL, NULL); - SQL->StmtBindColumn(stmt, 9, SQLDT_CHAR, &item.bound, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 9, SQLDT_UCHAR, &item.bound, 0, NULL, NULL); for( j = 0; j < MAX_SLOTS; ++j ) SQL->StmtBindColumn(stmt, 10+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); @@ -1243,17 +1243,17 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything if( SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) || SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT, &char_id, 0) || SQL_ERROR == SQL->StmtExecute(stmt) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_UINT, &tmp_item.equip, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.favorite, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 9, SQLDT_CHAR, &tmp_item.bound, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 10, SQLDT_ULONGLONG, &tmp_item.unique_id, 0, NULL, NULL) ) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_UINT, &tmp_item.equip, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.favorite, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 9, SQLDT_UCHAR, &tmp_item.bound, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 10, SQLDT_UINT64, &tmp_item.unique_id, 0, NULL, NULL) ) SqlStmt_ShowDebug(stmt); for( i = 0; i < MAX_SLOTS; ++i ) if( SQL_ERROR == SQL->StmtBindColumn(stmt, 11+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) @@ -1283,8 +1283,8 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything || SQL_ERROR == SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.bound, 0, NULL, NULL) - || SQL_ERROR == SQL->StmtBindColumn(stmt, 9, SQLDT_ULONGLONG, &tmp_item.unique_id, 0, NULL, NULL) ) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_UCHAR, &tmp_item.bound, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 9, SQLDT_UINT64, &tmp_item.unique_id, 0, NULL, NULL) ) SqlStmt_ShowDebug(stmt); for( i = 0; i < MAX_SLOTS; ++i ) if( SQL_ERROR == SQL->StmtBindColumn(stmt, 10+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) @@ -2959,7 +2959,7 @@ int parse_frommap(int fd) break; } //Check account only if this ain't final save. Final-save goes through because of the char-map reconnect - if (RFIFOB(fd,12) || RFIFOB(fd,13) || ( + if (RFIFOB(fd,12) || ( (character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL && character->char_id == cid)) { diff --git a/src/char/int_storage.c b/src/char/int_storage.c index 6443aa743..30671df5e 100644 --- a/src/char/int_storage.c +++ b/src/char/int_storage.c @@ -107,8 +107,7 @@ int guild_storage_fromsql(int guild_id, struct guild_storage* p) StrBuf->Destroy(&buf); - for( i = 0; i < MAX_GUILD_STORAGE && SQL_SUCCESS == SQL->NextRow(sql_handle); ++i ) - { + for( i = 0; i < MAX_GUILD_STORAGE && SQL_SUCCESS == SQL->NextRow(sql_handle); ++i ) { item = &p->items[i]; SQL->GetData(sql_handle, 0, &data, NULL); item->id = atoi(data); SQL->GetData(sql_handle, 1, &data, NULL); item->nameid = atoi(data); @@ -120,9 +119,8 @@ int guild_storage_fromsql(int guild_id, struct guild_storage* p) SQL->GetData(sql_handle, 7, &data, NULL); item->bound = atoi(data); SQL->GetData(sql_handle, 8, &data, NULL); item->unique_id = strtoull(data, NULL, 10); item->expire_time = 0; - item->bound = 0; - for( j = 0; j < MAX_SLOTS; ++j ) - { + + for( j = 0; j < MAX_SLOTS; ++j ) { SQL->GetData(sql_handle, 9+j, &data, NULL); item->card[j] = atoi(data); } } @@ -239,14 +237,15 @@ int mapif_parse_SaveGuildStorage(int fd) return 0; } -#ifdef BOUND_ITEMS int mapif_itembound_ack(int fd, int aid, int guild_id) { +#ifdef GP_BOUND_ITEMS WFIFOHEAD(fd,8); WFIFOW(fd,0) = 0x3856; WFIFOL(fd,2) = aid; WFIFOW(fd,6) = guild_id; WFIFOSET(fd,8); +#endif return 0; } @@ -254,23 +253,23 @@ int mapif_itembound_ack(int fd, int aid, int guild_id) //Guild bound items pull for offline characters [Akinari] //Revised by [Mhalicot] //------------------------------------------------ -int mapif_parse_itembound_retrieve(int fd) +int mapif_parse_ItemBoundRetrieve(int fd) { +#ifdef GP_BOUND_ITEMS StringBuf buf; SqlStmt* stmt; struct item item; int j, i=0, s; - bool found=false; struct item items[MAX_INVENTORY]; int char_id = RFIFOL(fd,2); int aid = RFIFOL(fd,6); int guild_id = RFIFOW(fd,10); StrBuf->Init(&buf); - StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`"); + StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`"); for( j = 0; j < MAX_SLOTS; ++j ) StrBuf->Printf(&buf, ", `card%d`", j); - StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`='%d'",inventory_db,char_id); + StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`='%d' AND `bound` = '%d'",inventory_db,char_id,IBT_GUILD); stmt = SQL->StmtMalloc(sql_handle); if( SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) @@ -290,15 +289,14 @@ int mapif_parse_itembound_retrieve(int fd) SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); - SQL->StmtBindColumn(stmt, 8, SQLDT_UINT, &item.bound, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 8, SQLDT_UCHAR, &item.bound, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 9, SQLDT_UINT64, &item.unique_id, 0, NULL, NULL); for( j = 0; j < MAX_SLOTS; ++j ) - SQL->StmtBindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 10+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); while( SQL_SUCCESS == SQL->StmtNextRow(stmt) ) { - if(item.bound == 2) { - memcpy(&items[i],&item,sizeof(struct item)); - i++; - } + memcpy(&items[i],&item,sizeof(struct item)); + i++; } SQL->FreeResult(sql_handle); @@ -312,10 +310,9 @@ int mapif_parse_itembound_retrieve(int fd) StrBuf->Clear(&buf); StrBuf->Printf(&buf, "DELETE FROM `%s` WHERE",inventory_db); for(j=0; jAppendStr(&buf, " OR"); - else - found = true; + StrBuf->Printf(&buf, " `id`=%d",items[j].id); } @@ -329,21 +326,18 @@ int mapif_parse_itembound_retrieve(int fd) } //Now let's update the guild storage with those deleted items - found = false; StrBuf->Clear(&buf); - StrBuf->Printf(&buf, "INSERT INTO `%s` (`guild_id`, `nameid`, `amount`, `identify`, `refine`, `attribute`, `expire_time`, `bound`", guild_storage_db); + StrBuf->Printf(&buf, "INSERT INTO `%s` (`guild_id`, `nameid`, `amount`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`", guild_storage_db); for( j = 0; j < MAX_SLOTS; ++j ) StrBuf->Printf(&buf, ", `card%d`", j); StrBuf->AppendStr(&buf, ") VALUES "); for( j = 0; j < i; ++j ) { - if( found ) + if( j ) StrBuf->AppendStr(&buf, ","); - else - found = true; StrBuf->Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d'", - guild_id, items[j].nameid, items[j].amount, items[j].identify, items[j].refine, items[j].attribute, items[j].expire_time, items[j].bound); + guild_id, items[j].nameid, items[j].amount, items[j].identify, items[j].refine, items[j].attribute, items[j].expire_time, items[j].bound, items[j].unique_id); for( s = 0; s < MAX_SLOTS; ++s ) StrBuf->Printf(&buf, ", '%d'", items[j].card[s]); StrBuf->AppendStr(&buf, ")"); @@ -364,21 +358,21 @@ int mapif_parse_itembound_retrieve(int fd) //Finally reload storage and tell map we're done mapif_load_guild_storage(fd,aid,guild_id,0); mapif_itembound_ack(fd,aid,guild_id); +#endif return 0; } -#endif int inter_storage_parse_frommap(int fd) { RFIFOHEAD(fd); switch(RFIFOW(fd,0)){ - case 0x3018: mapif_parse_LoadGuildStorage(fd); break; - case 0x3019: mapif_parse_SaveGuildStorage(fd); break; -#ifdef BOUND_ITEMS - case 0x3056: mapif_parse_itembound_retrieve(fd); break; + case 0x3018: mapif_parse_LoadGuildStorage(fd); break; + case 0x3019: mapif_parse_SaveGuildStorage(fd); break; +#ifdef GP_BOUND_ITEMS + case 0x3056: mapif_parse_ItemBoundRetrieve(fd); break; #endif - default: - return 0; + default: + return 0; } return 1; } diff --git a/src/char/inter.c b/src/char/inter.c index 54672faee..b213f1608 100644 --- a/src/char/inter.c +++ b/src/char/inter.c @@ -48,15 +48,15 @@ unsigned int party_share_level = 10; // recv. packet list int inter_recv_packet_length[] = { -1,-1, 7,-1, -1,13,36, (2 + 4 + 4 + 4 + NAME_LENGTH), 0, 0, 0, 0, 0, 0, 0, 0, // 3000- - 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, // 3010- - -1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020- Party - -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030- - -1, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040- - -1,-1,10,10, 0,-1, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus] [Mhalicot] - 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish] - -1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, -1,10, 6,-1, // 3070- Mercenary packets [Zephyrus], Elemental packets [pakpil] - 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080- - -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator] + 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, // 3010- + -1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020- Party + -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030- + -1, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040- + -1,-1,10,10, 0,-1,12, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus], Item Bound [Mhalicot] + 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish] + -1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, -1,10, 6,-1, // 3070- Mercenary packets [Zephyrus], Elemental packets [pakpil] + 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080- + -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator] }; struct WisData { diff --git a/src/common/mmo.h b/src/common/mmo.h index f676893ea..369f5c894 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -222,7 +222,8 @@ struct item { char attribute; short card[MAX_SLOTS]; unsigned int expire_time; - char favorite, bound; + char favorite; + unsigned char bound; uint64 unique_id; }; @@ -249,6 +250,15 @@ enum e_mmo_charstatus_opt { OPT_ALLOW_PARTY = 0x2, }; +enum e_item_bound_type { + IBT_MIN = 0x1, + IBT_ACCOUNT = 0x1, + IBT_GUILD = 0x2, + IBT_PARTY = 0x3, + IBT_CHARACTER = 0x4, + IBT_MAX = 0x4, +}; + struct s_skill { unsigned short id; unsigned char lv; diff --git a/src/config/core.h b/src/config/core.h index 481c35af8..daadc6455 100644 --- a/src/config/core.h +++ b/src/config/core.h @@ -62,8 +62,7 @@ //#define NSI_UNIQUE_ID /// Comment to disable Guild/Party Bound item system -/// By default, we recover/remove Guild/Party Bound items automatically -#define BOUND_ITEMS +#define GP_BOUND_ITEMS /// Uncomment to enable real-time server stats (in and out data and ram usage). [Ai4rei] //#define SHOW_SERVER_STATS diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 3f3e9679e..e19428d36 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -1104,7 +1104,7 @@ ACMD(item) sscanf(message, "%99s %d %d", item_name, &number, &bound) < 2 ))) { clif->message(fd, msg_txt(295)); // Please enter an item name or ID (usage: @itembound ). - return -1; + return false; } else if (!message || !*message || ( sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 && sscanf(message, "%99s %d", item_name, &number) < 1 )) @@ -1123,7 +1123,7 @@ ACMD(item) return false; } - if( bound < 0 || bound > 4 ) { + if( bound < IBT_MIN || bound > IBT_MAX ) { clif->message(fd, msg_txt(298)); // Invalid bound type return false; } @@ -1137,9 +1137,6 @@ ACMD(item) return false; } get_count = 1; - } else if( bound ) { - clif->message(fd, msg_txt(499)); // Cannot create bounded stackable items. - return false; } for (i = 0; i < number; i += get_count) { @@ -1148,7 +1145,7 @@ ACMD(item) memset(&item_tmp, 0, sizeof(item_tmp)); item_tmp.nameid = item_id; item_tmp.identify = 1; - item_tmp.bound = bound; + item_tmp.bound = (unsigned char)bound; if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) clif->additem(sd, 0, 0, flag); @@ -1192,9 +1189,9 @@ ACMD(item2) if (number <= 0) number = 1; - if( bound < 0 || bound > 4 ) { + if( bound < IBT_MIN || bound > IBT_MAX ) { clif->message(fd, msg_txt(298)); // Invalid bound type - return -1; + return false; } item_id = 0; @@ -1225,10 +1222,6 @@ ACMD(item2) if (refine > MAX_REFINE) refine = MAX_REFINE; } else { - if( bound ) { - clif->message(fd, msg_txt(499)); // Cannot create bounded stackable items. - return false; - } identify = 1; refine = attr = 0; } @@ -1238,11 +1231,12 @@ ACMD(item2) item_tmp.identify = identify; item_tmp.refine = refine; item_tmp.attribute = attr; + item_tmp.bound = (unsigned char)bound; item_tmp.card[0] = c1; item_tmp.card[1] = c2; item_tmp.card[2] = c3; item_tmp.card[3] = c4; - item_tmp.bound = bound; + if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) clif->additem(sd, 0, 0, flag); } diff --git a/src/map/clif.c b/src/map/clif.c index 04614158a..fecf0be0e 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -1802,13 +1802,13 @@ void clif_selllist(struct map_session_data *sd) if( !itemdb_cansell(&sd->status.inventory[i], pc->get_group_level(sd)) ) continue; - if( sd->status.inventory[i].expire_time || (sd->status.inventory[i].bound && !pc->can_give_bounded_items(sd)) ) - continue; // Cannot Sell Rental Items or Account Bounded Items + if( sd->status.inventory[i].expire_time ) + continue; // Cannot Sell Rental Items if( sd->status.inventory[i].bound && !pc->can_give_bounded_items(sd)) continue; // Don't allow sale of bound items - val=sd->inventory_data[i]->value_sell; + val=sd->inventory_data[i]->value_sell; if( val < 0 ) continue; WFIFOW(fd,4+c*10)=i+2; @@ -2232,7 +2232,10 @@ void clif_additem(struct map_session_data *sd, int n, int amount, int fail) { p.HireExpireDate = sd->status.inventory[n].expire_time; #endif #if PACKETVER >= 20071002 - p.bindOnEquipType = sd->status.inventory[n].bound ? 2 : 0; + /* why restrict the flag to non-stackable? because this is the only packet allows stackable to, + * show the color, and therefore it'd be inconsistent with the rest (aka it'd show yellow, you relog/refresh and boom its gone) + */ + p.bindOnEquipType = sd->status.inventory[n].bound && !itemdb->isstackable2(sd->inventory_data[n]) ? 2 : 0; #endif } p.result = (unsigned char)fail; @@ -2381,7 +2384,6 @@ void clif_item_normal(short idx, struct NORMALITEM_INFO *p, struct item *i, stru #if PACKETVER >= 20080102 p->HireExpireDate = i->expire_time; - p->bindOnEquipType = i->bound ? 2 : 0; #endif #if PACKETVER >= 20120925 @@ -15067,8 +15069,8 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd) if( !pc->can_give_items(sd) || sd->status.inventory[idx].expire_time || !sd->status.inventory[idx].identify || - !itemdb_canauction(&sd->status.inventory[idx],pc->get_group_level(sd)) || - (sd->status.inventory[idx].bound && !pc->can_give_bounded_items(sd)) ) { // Quest Item or something else + !itemdb_canauction(&sd->status.inventory[idx],pc->get_group_level(sd)) || // Quest Item or something else + (sd->status.inventory[idx].bound && !pc->can_give_bounded_items(sd)) ) { clif->auction_setitem(sd->fd, idx, true); return; } @@ -15145,13 +15147,11 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd) return; } - // Auction checks... - if( sd->status.inventory[sd->auction.index].bound && !pc->can_give_bounded_items(sd) ) { - clif->message(sd->fd, msg_txt(293)); - clif->auction_message(fd, 2); // The auction has been canceled - return; + if( sd->status.zeny < (auction.hours * battle_config.auction_feeperhour) ) { + clif_Auction_message(fd, 5); // You do not have enough zeny to pay the Auction Fee. + return; } - + if( auction.buynow > battle_config.auction_maximumprice ) { // Zeny Limits auction.buynow = battle_config.auction_maximumprice; @@ -15177,6 +15177,13 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd) return; } + // Auction checks... + if( sd->status.inventory[sd->auction.index].bound && !pc->can_give_bounded_items(sd) ) { + clif->message(sd->fd, msg_txt(293)); + clif->auction_message(fd, 2); // The auction has been canceled + return; + } + safestrncpy(auction.item_name, item->jname, sizeof(auction.item_name)); auction.type = item->type; memcpy(&auction.item, &sd->status.inventory[sd->auction.index], sizeof(struct item)); diff --git a/src/map/clif.h b/src/map/clif.h index 710cb6590..cc222d8aa 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -450,6 +450,14 @@ enum e_UNEQUIP_ITEM_ACK { #endif }; +enum e_trade_item_ok { + TIO_SUCCESS = 0x0, + TIO_OVERWEIGHT = 0x1, + TIO_CANCEL = 0x2, + /* feedback-friendly code that causes the client not to display a error message */ + TIO_INDROCKS = 0x9, +}; + /** * Structures **/ diff --git a/src/map/guild.c b/src/map/guild.c index 719d6bf69..cba568bd8 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -866,7 +866,7 @@ int guild_member_withdraw(int guild_id, int account_id, int char_id, int flag, c if(online_member_sd == NULL) return 0; // noone online to inform -#ifdef BOUND_ITEMS +#ifdef GP_BOUND_ITEMS //Guild bound item check guild->retrieveitembound(char_id,account_id,guild_id); #endif @@ -904,25 +904,12 @@ int guild_member_withdraw(int guild_id, int account_id, int char_id, int flag, c return 0; } -#ifdef BOUND_ITEMS -void guild_retrieveitembound(int char_id,int aid,int guild_id) -{ +void guild_retrieveitembound(int char_id,int aid,int guild_id) { +#ifdef GP_BOUND_ITEMS TBL_PC *sd = map->id2sd(aid); if(sd){ //Character is online - int idxlist[MAX_INVENTORY]; - int j,i; - j = pc->bound_chk(sd,2,idxlist); - if(j) { - struct guild_storage *gstor = gstorage->id2storage(guild_id); - for(i=0;iadditem(sd,gstor,&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); - } - gstorage->close(sd); //Close and save the storage - } - } - else { //Character is offline, ask char server to do the job + pc->bound_clear(sd,IBT_GUILD); + } else { //Character is offline, ask char server to do the job struct guild_storage *gstor = gstorage->id2storage2(guild_id); if(gstor && gstor->storage_status == 1) { //Someone is in guild storage, close them struct s_mapiterator* iter = mapit_getallusers(); @@ -936,8 +923,8 @@ void guild_retrieveitembound(int char_id,int aid,int guild_id) } intif->itembound_req(char_id,aid,guild_id); } -} #endif +} int guild_send_memberinfoshort(struct map_session_data *sd,int online) { // cleaned up [LuzZza] @@ -1854,11 +1841,6 @@ int guild_break(struct map_session_data *sd,char *name) { struct unit_data *ud; int i; -#ifdef BOUND_ITEMS - int j; - int idxlist[MAX_INVENTORY]; -#endif - nullpo_ret(sd); if( (g=sd->guild)==NULL ) @@ -1901,11 +1883,8 @@ int guild_break(struct map_session_data *sd,char *name) { } } -#ifdef BOUND_ITEMS - //Guild bound item check - Removes the bound flag - j = pc->bound_chk(sd,2,idxlist); - for(i=0;istatus.inventory[idxlist[i]].bound = 0; +#ifdef GP_BOUND_ITEMS + pc->bound_clear(sd,IBT_GUILD); #endif intif->guild_break(g->guild_id); @@ -2380,4 +2359,6 @@ void guild_defaults(void) { guild->check_member = guild_check_member; guild->get_alliance_count = guild_get_alliance_count; guild->castle_reconnect_sub = guild_castle_reconnect_sub; + /* */ + guild->retrieveitembound = guild_retrieveitembound; } diff --git a/src/map/guild.h b/src/map/guild.h index 9326d8d5a..1a04a98ef 100644 --- a/src/map/guild.h +++ b/src/map/guild.h @@ -148,9 +148,7 @@ struct guild_interface { /* guild aura */ void (*aura_refresh) (struct map_session_data *sd, uint16 skill_id, uint16 skill_lv); /* item bound [Mhalicot]*/ -#ifdef BOUND_ITEMS void (*retrieveitembound) (int char_id,int aid,int guild_id); -#endif /* */ int (*payexp_timer) (int tid, int64 tick, int id, intptr_t data); TBL_PC* (*sd_check) (int guild_id, int account_id, int char_id); diff --git a/src/map/intif.c b/src/map/intif.c index b8b16a356..5cf385fe4 100644 --- a/src/map/intif.c +++ b/src/map/intif.c @@ -994,7 +994,6 @@ void intif_parse_LoadGuildStorage(int fd) ShowError("intif_parse_LoadGuildStorage: user not found %d\n",RFIFOL(fd,4)); return; } - } gstor=gstorage->id2storage(guild_id); if(!gstor) { @@ -1002,12 +1001,12 @@ void intif_parse_LoadGuildStorage(int fd) return; } if (gstor->storage_status == 1) { // 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; + ShowWarning("intif_parse_LoadGuildStorage: storage received for a client already open (User %d:%d)\n", flag?sd->status.account_id:0, flag?sd->status.char_id:0); + return; } if (gstor->dirty) { // Already have storage, and it has been modified and not saved yet! Exploit! [Skotlex] - ShowWarning("intif_parse_LoadGuildStorage: received storage for an already modified non-saved storage! (User %d:%d)\n", flag?sd->status.account_id:1, flag?sd->status.char_id:1); - return; + ShowWarning("intif_parse_LoadGuildStorage: received storage for an already modified non-saved storage! (User %d:%d)\n", flag?sd->status.account_id:0, flag?sd->status.char_id:0); + return; } 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)); @@ -1017,7 +1016,7 @@ void intif_parse_LoadGuildStorage(int fd) memcpy(gstor,RFIFOP(fd,13),sizeof(struct guild_storage)); if( flag ) - gstorage->open(sd); + gstorage->open(sd); } // ACK guild_storage saved @@ -2013,8 +2012,8 @@ void intif_parse_MessageToFD(int fd) { /*========================================== * Item Bound System [Xantara][Mhalicot] *------------------------------------------*/ -#ifdef BOUND_ITEMS void intif_itembound_req(int char_id,int aid,int guild_id) { +#ifdef GP_BOUND_ITEMS struct guild_storage *gstor = gstorage->id2storage2(guild_id); WFIFOHEAD(inter_fd,12); WFIFOW(inter_fd,0) = 0x3056; @@ -2024,17 +2023,20 @@ void intif_itembound_req(int char_id,int aid,int guild_id) { WFIFOSET(inter_fd,12); if(gstor) gstor->lock = 1; //Lock for retrieval process +#endif } //3856 void intif_parse_Itembound_ack(int fd) { +#ifdef GP_BOUND_ITEMS struct guild_storage *gstor; int guild_id = RFIFOW(fd,6); gstor = gstorage->id2storage2(guild_id); - if(gstor) gstor->lock = 0; //Unlock now that operation is completed -} + if(gstor) + gstor->lock = 0; //Unlock now that operation is completed #endif +} //----------------------------------------------------------------- // Communication from the inter server // Return a 0 (false) if there were any errors. @@ -2118,9 +2120,9 @@ int intif_parse(int fd) case 0x3854: intif->pAuctionMessage(fd); break; case 0x3855: intif->pAuctionBid(fd); break; //Bound items -#ifdef BOUND_ITEMS +#ifdef GP_BOUND_ITEMS case 0x3856: intif->pItembound_ack(fd); break; -#endif +#endif // Mercenary System case 0x3870: intif->pMercenaryReceived(fd); break; case 0x3871: intif->pMercenaryDeleted(fd); break; @@ -2160,7 +2162,7 @@ void intif_defaults(void) { 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, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3860 Quests [Kevin] [Inkfish] + -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] 11,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3880 -1,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3890 Homunculus [albator] @@ -2248,6 +2250,8 @@ void intif_defaults(void) { /* */ intif->CheckForCharServer = CheckForCharServer; /* */ + intif->itembound_req = intif_itembound_req; + /* parse functions */ intif->pWisMessage = intif_parse_WisMessage; intif->pWisEnd = intif_parse_WisEnd; intif->pWisToGM_sub = mapif_parse_WisToGM_sub; diff --git a/src/map/intif.h b/src/map/intif.h index 577d58923..5e996b6fe 100644 --- a/src/map/intif.h +++ b/src/map/intif.h @@ -75,9 +75,7 @@ struct intif_interface { int (*guild_emblem) (int guild_id, int len, const char *data); int (*guild_castle_dataload) (int num, int *castle_ids); int (*guild_castle_datasave) (int castle_id, int index, int value); -#ifdef BOUND_ITEMS void (*itembound_req) (int char_id, int aid, int guild_id); -#endif int (*request_petdata) (int account_id, int char_id, int pet_id); int (*save_petdata) (int account_id, struct s_pet *p); int (*delete_petdata) (int pet_id); diff --git a/src/map/mail.c b/src/map/mail.c index 6b1537d87..76c94879b 100644 --- a/src/map/mail.c +++ b/src/map/mail.c @@ -82,9 +82,9 @@ unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount) { if( amount < 0 || amount > sd->status.inventory[idx].amount ) return 1; if( !pc->can_give_items(sd) || sd->status.inventory[idx].expire_time || - !itemdb_canmail(&sd->status.inventory[idx],pc->get_group_level(sd)) || - (sd->status.inventory[idx].bound && !pc->can_give_bounded_items(sd)) ) - return 1; + !itemdb_canmail(&sd->status.inventory[idx],pc->get_group_level(sd)) || + (sd->status.inventory[idx].bound && !pc->can_give_bounded_items(sd)) ) + return 1; sd->mail.index = idx; sd->mail.nameid = sd->status.inventory[idx].nameid; diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index e6f68ea4f..813aebee0 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -212,7 +212,6 @@ struct NORMALITEM_INFO { #endif #if PACKETVER >= 20080102 int HireExpireDate; - unsigned short bindOnEquipType; #endif #if PACKETVER >= 20120925 struct { diff --git a/src/map/party.c b/src/map/party.c index 16b9d99f9..0a7467162 100644 --- a/src/map/party.c +++ b/src/map/party.c @@ -547,14 +547,10 @@ int party_member_withdraw(int party_id, int account_id, int char_id) } if( sd && sd->status.party_id == party_id && sd->status.char_id == char_id ) { -#ifdef BOUND_ITEMS - int idxlist[MAX_INVENTORY]; //or malloc to reduce consumtion - int j,i; - j = pc->bound_chk(sd,3,idxlist); - for(i=0;idelitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_OTHER); +#ifdef GP_BOUND_ITEMS + pc->bound_clear(sd,IBT_PARTY); #endif - sd->status.party_id = 0; + sd->status.party_id = 0; clif->charnameupdate(sd); //Update name display [Skotlex] //TODO: hp bars should be cleared too if( p->instances ) diff --git a/src/map/pc.c b/src/map/pc.c index 31a38372a..752151888 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -573,7 +573,7 @@ bool pc_can_give_items(struct map_session_data *sd) */ bool pc_can_give_bounded_items(struct map_session_data *sd) { - return pc->has_permission(sd, PC_PERM_TRADE_BOUNDED); + return pc->has_permission(sd, PC_PERM_TRADE_BOUND); } /*========================================== @@ -999,10 +999,6 @@ int pc_isequip(struct map_session_data *sd,int n) *------------------------------------------*/ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, struct mmo_charstatus *st, bool changing_mapservers) { int i; -#ifdef BOUND_ITEMS - int j; - int idxlist[MAX_INVENTORY]; -#endif int64 tick = timer->gettick(); uint32 ip = session[sd->fd]->client_addr; @@ -1203,12 +1199,9 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim **/ pc->itemcd_do(sd,true); -#ifdef BOUND_ITEMS - // Party bound item check - if(sd->status.party_id == 0 && (j = pc->bound_chk(sd,3,idxlist))) { // Party was deleted while character offline - for(i=0;idelitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_OTHER); - } +#ifdef GP_BOUND_ITEMS + if( sd->status.party_id == 0 ) + pc->bound_clear(sd,IBT_PARTY); #endif /* [Ind/Hercules] */ @@ -3962,6 +3955,28 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l if(sd->weight + w > sd->max_weight) return 2; + if( item_data->bound ) { + switch( (enum e_item_bound_type)item_data->bound ) { + case IBT_CHARACTER: + case IBT_ACCOUNT: + break; /* no restrictions */ + case IBT_PARTY: + if( !sd->status.party_id ) { + ShowError("pc_additem: can't add party_bound item to character without party!\n"); + ShowError("pc_additem: %s - x%d %s (%d)\n",sd->status.name,amount,data->jname,data->nameid); + return 7;/* need proper code? */ + } + break; + case IBT_GUILD: + if( !sd->status.guild_id ) { + ShowError("pc_additem: can't add guild_bound item to character without guild!\n"); + ShowError("pc_additem: %s - x%d %s (%d)\n",sd->status.name,amount,data->jname,data->nameid); + return 7;/* need proper code? */ + } + break; + } + } + i = MAX_INVENTORY; if( itemdb->isstackable2(data) && item_data->expire_time == 0 ) @@ -3969,7 +3984,7 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l for( i = 0; i < MAX_INVENTORY; i++ ) { if( sd->status.inventory[i].nameid == item_data->nameid && sd->status.inventory[i].bound == item_data->bound && memcmp(&sd->status.inventory[i].card, &item_data->card, sizeof(item_data->card)) == 0 ) - { + { if( amount > MAX_AMOUNT - sd->status.inventory[i].amount || ( data->stack.inventory && amount > data->stack.amount - sd->status.inventory[i].amount ) ) return 5; sd->status.inventory[i].amount += amount; @@ -4520,7 +4535,7 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun return 1; } - if( !itemdb_cancartstore(item_data, pc->get_group_level(sd)) || (item_data->bound > 1 && !pc->can_give_bounded_items(sd))) + if( !itemdb_cancartstore(item_data, pc->get_group_level(sd)) || (item_data->bound > IBT_ACCOUNT && !pc->can_give_bounded_items(sd))) { // Check item trade restrictions [Skotlex] clif->message (sd->fd, msg_txt(264)); return 1;/* TODO: there is no official response to this? */ @@ -4667,24 +4682,38 @@ int pc_getitemfromcart(struct map_session_data *sd,int idx,int amount) return flag; } - /*========================================== - * Bound Item Check - * Type: - * 1 Account Bound - * 2 Guild Bound - * 3 Party Bound - * 4 Character Bound - *------------------------------------------*/ -int pc_bound_chk(TBL_PC *sd,int type,int *idxlist) -{ - int i=0, j=0; - for(i=0;istatus.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0 && sd->status.inventory[i].bound == type) { - idxlist[j] = i; - j++; - } +void pc_bound_clear(struct map_session_data *sd, enum e_item_bound_type type) { + int i; + + switch( type ) { + /* both restricted to inventory */ + case IBT_PARTY: + case IBT_CHARACTER: + for( i = 0; i < MAX_INVENTORY; i++ ){ + if( sd->status.inventory[i].bound == type ) { + pc->delitem(sd,i,sd->status.inventory[i].amount,0,1,LOG_TYPE_OTHER); + } + } + break; + case IBT_ACCOUNT: + ShowError("Helllo! You reached pc_bound_clear for IBT_ACCOUNT, unfortunately no scenario was expected for this!\n"); + break; + case IBT_GUILD: { + struct guild_storage *gstor = gstorage->id2storage(sd->status.guild_id); + + for( i = 0; i < MAX_INVENTORY; i++ ){ + if(sd->status.inventory[i].bound == type) { + if( gstor ) + gstorage->additem(sd,gstor,&sd->status.inventory[i],sd->status.inventory[i].amount); + pc->delitem(sd,i,sd->status.inventory[i].amount,0,1,gstor?LOG_TYPE_GSTORAGE:LOG_TYPE_OTHER); + } + } + if( gstor ) + gstorage->close(sd); + } + break; } - return j; + } /*========================================== * Display item stolen msg to player sd @@ -10366,7 +10395,6 @@ void pc_defaults(void) { pc->class2idx = pc_class2idx; pc->get_group_level = pc_get_group_level; pc->can_give_items = pc_can_give_items; - pc->bound_chk = pc_bound_chk; pc->can_give_bounded_items = pc_can_give_bounded_items; pc->can_use_command = pc_can_use_command; @@ -10600,4 +10628,6 @@ void pc_defaults(void) { pc->rental_expire = pc_rental_expire; pc->scdata_received = pc_scdata_received; + + pc->bound_clear = pc_bound_clear; } diff --git a/src/map/pc.h b/src/map/pc.h index 3645fc599..93463d19b 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -791,9 +791,6 @@ struct pc_interface { int (*getzeny) (struct map_session_data *sd,int zeny, enum e_log_pick_type type, struct map_session_data *tsd); int (*delitem) (struct map_session_data *sd,int n,int amount,int type, short reason, e_log_pick_type log_type); - //Bound items - int (*bound_chk) (TBL_PC *sd,int type,int *idxlist); - // Special Shop System int (*paycash) (struct map_session_data *sd, int price, int points); int (*getcash) (struct map_session_data *sd, int cash, int points); @@ -986,6 +983,8 @@ struct pc_interface { void (*rental_expire) (struct map_session_data *sd, int i); void (*scdata_received) (struct map_session_data *sd); + + void (*bound_clear) (struct map_session_data *sd, enum e_item_bound_type type); }; struct pc_interface *pc; diff --git a/src/map/pc_groups.c b/src/map/pc_groups.c index c44e2634a..f95878e97 100644 --- a/src/map/pc_groups.c +++ b/src/map/pc_groups.c @@ -417,7 +417,7 @@ void do_init_pc_groups(void) { { "disable_pvp", PC_PERM_DISABLE_PVP }, { "disable_commands_when_dead", PC_PERM_DISABLE_CMD_DEAD }, { "hchsys_admin", PC_PERM_HCHSYS_ADMIN }, - { "can_trade_bounded", PC_PERM_TRADE_BOUNDED }, + { "can_trade_bound", PC_PERM_TRADE_BOUND }, }; unsigned char i, len = ARRAYLENGTH(pc_g_defaults); diff --git a/src/map/pc_groups.h b/src/map/pc_groups.h index df99b19df..943fb7fa5 100644 --- a/src/map/pc_groups.h +++ b/src/map/pc_groups.h @@ -30,7 +30,7 @@ enum e_pc_permission { PC_PERM_DISABLE_PVP = 0x080000, // #20 PC_PERM_DISABLE_CMD_DEAD = 0x100000, PC_PERM_HCHSYS_ADMIN = 0x200000, - PC_PERM_TRADE_BOUNDED = 0x400000, + PC_PERM_TRADE_BOUND = 0x400000, }; // Cached config settings for quick lookup diff --git a/src/map/script.c b/src/map/script.c index 6dce018ef..cf3c3fb50 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -3779,6 +3779,17 @@ int script_reload(void) { return 0; } +/* returns name of current function being run, from within the stack [Ind/Hercules] */ +const char *script_getfuncname(struct script_state *st) { + struct script_data *data; + + data = &st->stack->stack_data[st->start]; + + if( data->type == C_NAME && script->str_data[data->u.num].type == C_FUNC ) + return script->get_str(data->u.num); + + return NULL; +} //----------------------------------------------------------------------------- // buildin functions @@ -5763,10 +5774,13 @@ BUILDIN(checkweight2) /*========================================== * getitem ,{,}; * getitem "",{,}; + * + * getitembound ,,{,}; + * getitembound "",,{,}; *------------------------------------------*/ BUILDIN(getitem) { - int nameid,amount,get_count,i,flag = 0; + int nameid,amount,get_count,i,flag = 0, offset = 0; struct item it; TBL_PC *sd; struct script_data *data; @@ -5778,7 +5792,7 @@ BUILDIN(getitem) {// "" const char *name=script->conv_str(st,data); if( (item_data = itemdb->search_name(name)) == NULL ){ - ShowError("buildin_getitem: Nonexistant item %s requested.\n", name); + ShowError("buildin_%s: Nonexistant item %s requested.\n", script->getfuncname(st), name); return false; //No item created. } nameid=item_data->nameid; @@ -5790,11 +5804,11 @@ BUILDIN(getitem) flag = 1; } if( nameid <= 0 || !(item_data = itemdb->exists(nameid)) ){ - ShowError("buildin_getitem: Nonexistant item %d requested.\n", nameid); + ShowError("buildin_%s: Nonexistant item %d requested.\n", script->getfuncname(st), nameid); return false; //No item created. } } else { - ShowError("buildin_getitem: invalid data type for argument #1 (%d).", data->type); + ShowError("buildin_%s: invalid data type for argument #1 (%d).", script->getfuncname(st), data->type); return false; } @@ -5804,13 +5818,28 @@ BUILDIN(getitem) memset(&it,0,sizeof(it)); it.nameid=nameid; + if(!flag) it.identify=1; else it.identify=itemdb->isidentified2(item_data); - if( script_hasdata(st,4) ) - sd=map->id2sd(script_getnum(st,4)); // + if( !strcmp(script->getfuncname(st),"getitembound") ) { + int bound = script_getnum(st,4); + if( bound < IBT_MIN || bound > IBT_MAX ) { //Not a correct bound type + ShowError("script_getitembound: Not a correct bound type! Type=%d\n",bound); + return false; + } + if( item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR ) { + ShowError("script_getitembound: can't bind a pet egg/armor!\n",bound); + return false; + } + it.bound = (unsigned char)bound; + offset += 1; + } + + if( script_hasdata(st,4+offset) ) + sd=map->id2sd(script_getnum(st,4+offset)); // else sd=script->rid2sd(st); // Attached player @@ -5842,15 +5871,24 @@ BUILDIN(getitem) *------------------------------------------*/ BUILDIN(getitem2) { - int nameid,amount,get_count,i,flag = 0; - int iden,ref,attr,c1,c2,c3,c4; + int nameid,amount,get_count,i,flag = 0, offset = 0; + int iden,ref,attr,c1,c2,c3,c4, bound = 0; struct item_data *item_data; struct item item_tmp; TBL_PC *sd; struct script_data *data; - if( script_hasdata(st,11) ) - sd=map->id2sd(script_getnum(st,11)); // + if( !strcmp(script->getfuncname(st),"getitembound2") ) { + bound = script_getnum(st,11); + if( bound < IBT_MIN || bound > IBT_MAX ) { //Not a correct bound type + ShowError("script_getitembound2: Not a correct bound type! Type=%d\n",bound); + return false; + } + offset += 1; + } + + if( script_hasdata(st,11+offset) ) + sd=map->id2sd(script_getnum(st,11+offset)); // else sd=script->rid2sd(st); // Attached player @@ -5878,6 +5916,11 @@ BUILDIN(getitem2) c3=(short)script_getnum(st,9); c4=(short)script_getnum(st,10); + if( bound && (itemdb_type(nameid) == IT_PETEGG || itemdb_type(nameid) == IT_PETARMOR) ) { + ShowError("script_getitembound2: can't bind a pet egg/armor!\n",bound); + return false; + } + if(nameid<0) { // Invalide nameid nameid = -nameid; flag = 1; @@ -5907,6 +5950,7 @@ BUILDIN(getitem2) item_tmp.identify=0; item_tmp.refine=ref; item_tmp.attribute=attr; + item_tmp.bound=(unsigned char)bound; item_tmp.card[0]=(short)c1; item_tmp.card[1]=(short)c2; item_tmp.card[2]=(short)c3; @@ -17562,185 +17606,6 @@ BUILDIN(bg_join_team) { return true; } - -/*==============[Mhalicot]================== - * getitembound ,,{,}; - * getitembound "",,{,}; - * Type: - * 1 - Account Bound - * 2 - Guild Bound - * 3 - Party Bound - * 4 - Character Bound - *------------------------------------------*/ -BUILDIN(getitembound) -{ - int nameid, amount, i, flag; - struct item it; - struct script_data *data; - char bound = script_getnum(st,4); - TBL_PC *sd; - - data = script_getdata(st,2); - get_val(st,data); - if( data_isstring(data) ) { // "" - const char *name = script->conv_str(st,data); - struct item_data *item_data = itemdb->search_name(name); - if( item_data == NULL ) { - ShowError("buildin_getitembound: Nonexistant item %s requested.\n", name); - return 1; //No item created. - } - nameid = item_data->nameid; - } else if( data_isint(data) ) { // - nameid = script->conv_num(st,data); - if( nameid <= 0 || !itemdb->exists(nameid) ) { - ShowError("buildin_getitembound: Nonexistant item %d requested.\n", nameid); - return 1; //No item created. - } - } else { - ShowError("buildin_getitembound: invalid data type for argument #1 (%d).", data->type); - return 1; - } - - if( itemdb->isstackable(nameid) || itemdb_type(nameid) == IT_PETEGG ) { - ShowError("buildin_getitembound: invalid item type. Bound only work for non stackeable items (Item %d).", nameid); - return 1; - } - - if( (amount = script_getnum(st,3)) <= 0) - return 0; //return if amount <=0, skip the useless iteration - - memset(&it,0,sizeof(it)); - it.nameid = nameid; - it.identify = 1; - it.bound = bound; - - if( bound < 1 || bound > 4) { //Not a correct bound type - ShowError("script_getitembound: Not a correct bound type! Type=%d\n",bound); - return 1; - } - - if( script_hasdata(st,5) ) - sd=map->id2sd(script_getnum(st,5)); // Account ID - else - sd=script->rid2sd(st); // Attached player - - if( sd == NULL ) // no target - return 0; - - for( i = 0; i < amount; i++ ) { - if( (flag = pc->additem(sd, &it, 1, LOG_TYPE_SCRIPT)) ) { - clif->additem(sd, 0, 0, flag); - if( pc->candrop(sd,&it) ) - map->addflooritem(&it,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); - } - } - - return 0; -} - -/*==============[Mhalicot]================== - * getitembound2 ,,,,,,,,,; - * getitembound2 "",,,,,,,,,; - *------------------------------------------*/ -BUILDIN(getitembound2) -{ - int nameid,amount,get_count,i,flag = 0; - int iden,ref,attr,c1,c2,c3,c4; - char bound=0; - struct item_data *item_data; - struct item item_tmp; - TBL_PC *sd; - struct script_data *data; - - bound = script_getnum(st,11); - if( bound < 1 || bound > 4) { //Not a correct bound type - ShowError("script_getitembound2: Not a correct bound type! Type=%d\n",bound); - return 1; - } - if( script_hasdata(st,12) ) - sd=map->id2sd(script_getnum(st,12)); - else - sd=script->rid2sd(st); // Attached player - - if( sd == NULL ) // no target - return true; - - data=script_getdata(st,2); - script->get_val(st,data); - if( data_isstring(data) ){ - const char *name=script->conv_str(st,data); - struct item_data *item_data = itemdb->search_name(name); - if( item_data ) - nameid=item_data->nameid; - else - nameid=UNKNOWN_ITEM_ID; - }else - nameid=script->conv_num(st,data); - - amount=script_getnum(st,3); - iden=script_getnum(st,4); - ref=script_getnum(st,5); - attr=script_getnum(st,6); - c1=(short)script_getnum(st,7); - c2=(short)script_getnum(st,8); - c3=(short)script_getnum(st,9); - c4=(short)script_getnum(st,10); - - if(nameid<0) { // Invalide nameid - nameid = -nameid; - flag = 1; - } - - if(nameid > 0) { - memset(&item_tmp,0,sizeof(item_tmp)); - item_data=itemdb->exists(nameid); - if (item_data == NULL) - return -1; - if(item_data->type==IT_WEAPON || item_data->type==IT_ARMOR){ - if(ref > MAX_REFINE) ref = MAX_REFINE; - } - else if(item_data->type==IT_PETEGG) { - iden = 1; - ref = 0; - } - else { - iden = 1; - ref = attr = 0; - } - - item_tmp.nameid=nameid; - if(!flag) - item_tmp.identify=iden; - else if(item_data->type==IT_WEAPON || item_data->type==IT_ARMOR) - item_tmp.identify=0; - item_tmp.refine=ref; - item_tmp.attribute=attr; - item_tmp.card[0]=(short)c1; - item_tmp.card[1]=(short)c2; - item_tmp.card[2]=(short)c3; - item_tmp.card[3]=(short)c4; - item_tmp.bound=bound; - - //Check if it's stackable. - if (!itemdb->isstackable(nameid)) - get_count = 1; - else - get_count = amount; - - for (i = 0; i < amount; i += get_count) { - // if not pet egg - if (!pet->create_egg(sd, nameid)) { - if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_SCRIPT))) { - clif->additem(sd, 0, 0, flag); - if( pc->candrop(sd,&item_tmp) ) - map->addflooritem(&item_tmp,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); - } - } - } - } - - return true; -} /*==============[Mhalicot]================== * countbound {}; * Creates an array of bounded item IDs @@ -17749,6 +17614,7 @@ BUILDIN(getitembound2) * 1 - Account Bound * 2 - Guild Bound * 3 - Party Bound + * 4 - Character Bound *------------------------------------------*/ BUILDIN(countbound) { @@ -18355,11 +18221,12 @@ void script_parse_builtin(void) { BUILDIN_DEF(bindatcmd, "ss???"), BUILDIN_DEF(unbindatcmd, "s"), BUILDIN_DEF(useatcmd, "s"), + /** - * Item bound [Mhalicot\Hercules] + * Item bound [Xantara] [Akinari] [Mhalicot/Hercules] **/ - BUILDIN_DEF(getitembound,"vii?"), - BUILDIN_DEF(getitembound2,"viiiiiiiii?"), + BUILDIN_DEF2(getitem,"getitembound","vii?"), + BUILDIN_DEF2(getitem2,"getitembound2","viiiiiiiii?"), BUILDIN_DEF(countbound, "?"), //Quest Log System [Inkfish] @@ -18652,6 +18519,7 @@ void script_defaults(void) { script->buildin_mobuseskill_sub = buildin_mobuseskill_sub; script->cleanfloor_sub = script_cleanfloor_sub; script->run_func = run_func; + script->getfuncname = script_getfuncname; /* script_config base */ script->config.warn_func_mismatch_argtypes = 1; diff --git a/src/map/script.h b/src/map/script.h index 6aebc8a30..a846365dd 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -630,6 +630,7 @@ struct script_interface { int (*buildin_mobuseskill_sub) (struct block_list *bl, va_list ap); int (*cleanfloor_sub) (struct block_list *bl, va_list ap); int (*run_func) (struct script_state *st); + const char *(*getfuncname) (struct script_state *st); }; struct script_interface *script; diff --git a/src/map/storage.c b/src/map/storage.c index cffbf23ec..0a2e6d118 100644 --- a/src/map/storage.c +++ b/src/map/storage.c @@ -141,7 +141,7 @@ int storage_additem(struct map_session_data* sd, struct item* item_data, int amo return 1; } - if( (item_data->bound > 1) && !pc->can_give_bounded_items(sd) ) { + if( item_data->bound > IBT_ACCOUNT && !pc->can_give_bounded_items(sd) ) { clif->message(sd->fd, msg_txt(294)); return 1; } @@ -435,13 +435,13 @@ int guild_storage_additem(struct map_session_data* sd, struct guild_storage* sto return 1; } - if( !itemdb_canguildstore(item_data, pc->get_group_level(sd)) || item_data->expire_time || (item_data->bound && !pc->can_give_bounded_items(sd)) ) + if( !itemdb_canguildstore(item_data, pc->get_group_level(sd)) || item_data->expire_time ) { //Check if item is storable. [Skotlex] clif->message (sd->fd, msg_txt(264)); return 1; } - if( (item_data->bound == 1 || item_data->bound > 2) && !pc->can_give_bounded_items(sd) ) { + if( item_data->bound && item_data->bound != IBT_GUILD && !pc->can_give_bounded_items(sd) ) { clif->message(sd->fd, msg_txt(294)); return 1; } @@ -531,6 +531,8 @@ int storage_guild_storageadd(struct map_session_data* sd, int index, int amount) if(gstorage->additem(sd,stor,&sd->status.inventory[index],amount)==0) pc->delitem(sd,index,amount,0,4,LOG_TYPE_GSTORAGE); + else + clif->dropitem(sd, index,0); return 1; } diff --git a/src/map/trade.c b/src/map/trade.c index 7085fdda3..327d19880 100644 --- a/src/map/trade.c +++ b/src/map/trade.c @@ -335,7 +335,7 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount) if( amount == 0 ) { //Why do this.. ~.~ just send an ack, the item won't display on the trade window. - clif->tradeitemok(sd, index, 0); + clif->tradeitemok(sd, index, TIO_SUCCESS); return; } @@ -354,35 +354,38 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount) (pc->get_partner(sd) != target_sd || !itemdb_canpartnertrade(item, src_lv, dst_lv)) ) //Can't partner-trade { clif->message (sd->fd, msg_txt(260)); - clif->tradeitemok(sd, index+2, 1); + clif->tradeitemok(sd, index+2, TIO_INDROCKS); return; } if( item->expire_time ) { // Rental System clif->message (sd->fd, msg_txt(260)); - clif->tradeitemok(sd, index+2, 1); + clif->tradeitemok(sd, index+2, TIO_INDROCKS); return; } - if( ((item->bound == 1 || item->bound > 2) || (item->bound == 2 && sd->status.guild_id != target_sd->status.guild_id)) && !pc->can_give_bounded_items(sd) ) { // Item Bound + if( item->bound && + !( item->bound == IBT_GUILD && sd->status.guild_id == target_sd->status.guild_id ) && + !( item->bound == IBT_PARTY && sd->status.party_id == target_sd->status.party_id ) + && !pc->can_give_bounded_items(sd) ) { clif->message(sd->fd, msg_txt(293)); - clif->tradeitemok(sd, index+2, 1); + clif->tradeitemok(sd, index+2, TIO_INDROCKS); return; } - + //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 { - clif->tradeitemok(sd, index+2, 1); + clif->tradeitemok(sd, index+2, TIO_OVERWEIGHT); return; } trade_weight = sd->inventory_data[index]->weight * amount; if( target_sd->weight + sd->deal.weight + trade_weight > target_sd->max_weight ) { //fail to add item -- the player was over weighted. - clif->tradeitemok(sd, index+2, 1); + clif->tradeitemok(sd, index+2, TIO_OVERWEIGHT); return; } @@ -402,7 +405,7 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount) } sd->deal.weight += trade_weight; - clif->tradeitemok(sd, index+2, 0); // Return the index as it was received + clif->tradeitemok(sd, index+2, TIO_SUCCESS); // Return the index as it was received clif->tradeadditem(sd, target_sd, index+2, amount); } @@ -446,7 +449,7 @@ void trade_tradeok(struct map_session_data *sd) { return; } sd->state.deal_locked = 1; - clif->tradeitemok(sd, 0, 0); + clif->tradeitemok(sd, 0, TIO_SUCCESS); clif->tradedeal_lock(sd, 0); clif->tradedeal_lock(target_sd, 1); } diff --git a/src/map/vending.c b/src/map/vending.c index 14a5e64d1..d5e5d1804 100644 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -257,7 +257,7 @@ void vending_openvending(struct map_session_data* sd, const char* message, const || !sd->status.cart[index].identify // unidentified item || sd->status.cart[index].attribute == 1 // broken item || sd->status.cart[index].expire_time // It should not be in the cart but just in case - || (sd->status.cart[index].bound && !pc->can_give_bounded_items(sd)) // can't trade account bound items and has no permission + || (sd->status.cart[index].bound && !pc->can_give_bounded_items(sd)) // can't trade bound items w/o permission || !itemdb_cantrade(&sd->status.cart[index], pc->get_group_level(sd), pc->get_group_level(sd)) ) // untradeable item continue; -- cgit v1.2.3-70-g09d2 From 8ed38f98894fb04b4403b44dc0f36281cfd36326 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Fri, 8 Nov 2013 22:09:40 -0200 Subject: Adjusted account-modifiers default values to 100. Special Thanks to Haruna, ossi0110. Signed-off-by: shennetsind --- sql-files/main.sql | 7 ++++--- sql-files/upgrades/2013-11-09--00-03.sql | 5 +++++ sql-files/upgrades/index.txt | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 sql-files/upgrades/2013-11-09--00-03.sql (limited to 'sql-files/main.sql') diff --git a/sql-files/main.sql b/sql-files/main.sql index 387d01893..23170096f 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -667,6 +667,7 @@ INSERT INTO `sql_updates` (`timestamp`) VALUES (1382892428); INSERT INTO `sql_updates` (`timestamp`) VALUES (1383162785); INSERT INTO `sql_updates` (`timestamp`) VALUES (1383167577); INSERT INTO `sql_updates` (`timestamp`) VALUES (1383205740); +INSERT INTO `sql_updates` (`timestamp`) VALUES (1383955424); -- -- Table structure for table `sstatus` @@ -721,9 +722,9 @@ INSERT INTO `interreg` (`varname`, `value`) VALUES CREATE TABLE IF NOT EXISTS `account_data` ( `account_id` int(11) unsigned NOT NULL default '0', `bank_vault` int(11) unsigned NOT NULL default '0', - `base_exp` TINYINT( 4 ) UNSIGNED NOT NULL default '0', - `base_drop` TINYINT( 4 ) UNSIGNED NOT NULL default '0', - `base_death` TINYINT( 4 ) UNSIGNED NOT NULL default '0', + `base_exp` TINYINT( 4 ) UNSIGNED NOT NULL default '100', + `base_drop` TINYINT( 4 ) UNSIGNED NOT NULL default '100', + `base_death` TINYINT( 4 ) UNSIGNED NOT NULL default '100', PRIMARY KEY (`account_id`) ) ENGINE=MyISAM; diff --git a/sql-files/upgrades/2013-11-09--00-03.sql b/sql-files/upgrades/2013-11-09--00-03.sql new file mode 100644 index 000000000..09c63307f --- /dev/null +++ b/sql-files/upgrades/2013-11-09--00-03.sql @@ -0,0 +1,5 @@ +#1383955424 +ALTER TABLE `account_data` MODIFY `base_exp` TINYINT( 4 ) UNSIGNED NOT NULL default '100'; +ALTER TABLE `account_data` MODIFY `base_drop` TINYINT( 4 ) UNSIGNED NOT NULL default '100'; +ALTER TABLE `account_data` MODIFY `base_death` TINYINT( 4 ) UNSIGNED NOT NULL default '100'; +INSERT INTO `sql_updates` (`timestamp`) VALUES (1383955424); \ No newline at end of file diff --git a/sql-files/upgrades/index.txt b/sql-files/upgrades/index.txt index 133366319..9074f5c62 100644 --- a/sql-files/upgrades/index.txt +++ b/sql-files/upgrades/index.txt @@ -9,4 +9,5 @@ 2013-10-27--16-47.sql 2013-10-30--19-53.sql 2013-10-30--21-12.sql -2013-10-31--07-49.sql \ No newline at end of file +2013-10-31--07-49.sql +2013-11-09--00-03.sql \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 40262e063a7d503104667a4135c564d996bc49c6 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Fri, 15 Nov 2013 18:02:59 -0200 Subject: Updated `account_data` upgrade files to avoid issues as demonstrated by report 7824 http://hercules.ws/board/tracker/issue-7824-exp-and-drop-rates-in-lat/ Special Thanks to Yommy! Signed-off-by: shennetsind --- sql-files/main.sql | 1 + sql-files/upgrades/2013-10-30--19-53.sql | 6 +++--- sql-files/upgrades/2013-11-15--19-57.sql | 5 +++++ sql-files/upgrades/index.txt | 1 + 4 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 sql-files/upgrades/2013-11-15--19-57.sql (limited to 'sql-files/main.sql') diff --git a/sql-files/main.sql b/sql-files/main.sql index 23170096f..cd50c10fa 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -668,6 +668,7 @@ INSERT INTO `sql_updates` (`timestamp`) VALUES (1383162785); INSERT INTO `sql_updates` (`timestamp`) VALUES (1383167577); INSERT INTO `sql_updates` (`timestamp`) VALUES (1383205740); INSERT INTO `sql_updates` (`timestamp`) VALUES (1383955424); +INSERT INTO `sql_updates` (`timestamp`) VALUES (1384545461); -- -- Table structure for table `sstatus` diff --git a/sql-files/upgrades/2013-10-30--19-53.sql b/sql-files/upgrades/2013-10-30--19-53.sql index 05481cff4..8bc63b1f1 100644 --- a/sql-files/upgrades/2013-10-30--19-53.sql +++ b/sql-files/upgrades/2013-10-30--19-53.sql @@ -1,5 +1,5 @@ #1383162785 -ALTER TABLE `account_data` ADD `base_exp` TINYINT( 4 ) UNSIGNED NOT NULL default '0'; -ALTER TABLE `account_data` ADD `base_drop` TINYINT( 4 ) UNSIGNED NOT NULL default '0'; -ALTER TABLE `account_data` ADD `base_death` TINYINT( 4 ) UNSIGNED NOT NULL default '0'; +ALTER TABLE `account_data` ADD `base_exp` TINYINT( 4 ) UNSIGNED NOT NULL default '100'; +ALTER TABLE `account_data` ADD `base_drop` TINYINT( 4 ) UNSIGNED NOT NULL default '100'; +ALTER TABLE `account_data` ADD `base_death` TINYINT( 4 ) UNSIGNED NOT NULL default '100'; INSERT INTO `sql_updates` (`timestamp`) VALUES (1383162785); \ No newline at end of file diff --git a/sql-files/upgrades/2013-11-15--19-57.sql b/sql-files/upgrades/2013-11-15--19-57.sql new file mode 100644 index 000000000..0644c47c9 --- /dev/null +++ b/sql-files/upgrades/2013-11-15--19-57.sql @@ -0,0 +1,5 @@ +#1384545461 +UPDATE `account_data` SET `base_exp` = '100' WHERE `base_exp` = '0'; +UPDATE `account_data` SET `base_drop` = '100' WHERE `base_drop` = '0'; +UPDATE `account_data` SET `base_death` = '100' WHERE `base_death` = '0'; +INSERT INTO `sql_updates` (`timestamp`) VALUES (1384545461); \ No newline at end of file diff --git a/sql-files/upgrades/index.txt b/sql-files/upgrades/index.txt index 734c0868a..4fed9ff9b 100644 --- a/sql-files/upgrades/index.txt +++ b/sql-files/upgrades/index.txt @@ -12,3 +12,4 @@ 2013-10-31--07-49.sql 2013-11-09--00-03.sql 2013-11-15--00-06.sql +2013-11-15--19-57.sql \ No newline at end of file -- cgit v1.2.3-70-g09d2 From aee2f6317e1c927847993801b5973d7e2e27a418 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Sat, 16 Nov 2013 16:30:11 -0200 Subject: Introducing Character Ban Support. @charban/@charunban, can temporarily block any accounts as opposed to the usual account-wide block. Special Thanks to Haruna, Yommy! Signed-off-by: shennetsind --- conf/messages.conf | 3 +- sql-files/main.sql | 2 + sql-files/upgrades/2013-11-16--07-49.sql | 3 + sql-files/upgrades/index.txt | 3 +- src/char/char.c | 215 +++++++++++++++++++++++-------- src/char/char.h | 1 + src/common/showmsg.h | 1 + src/common/utils.c | 11 ++ src/common/utils.h | 2 + src/login/login.c | 13 +- src/map/atcommand.c | 8 +- src/map/chrif.c | 24 +++- src/map/clif.c | 32 +++++ src/map/clif.h | 2 + 14 files changed, 241 insertions(+), 79 deletions(-) create mode 100644 sql-files/upgrades/2013-11-16--07-49.sql (limited to 'sql-files/main.sql') diff --git a/conf/messages.conf b/conf/messages.conf index 2d429d79e..f98a91083 100644 --- a/conf/messages.conf +++ b/conf/messages.conf @@ -452,7 +452,8 @@ 430: unblock 431: unban 432: change the sex of - +433: This character has been banned until +434: Char-server has been asked to %s the character '%.*s'. // Homunculus messages 450: You already have a homunculus diff --git a/sql-files/main.sql b/sql-files/main.sql index cd50c10fa..60b21285d 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -110,6 +110,7 @@ CREATE TABLE IF NOT EXISTS `char` ( `slotchange` SMALLINT(3) unsigned NOT NULL default '0', `char_opt` INT( 11 ) unsigned NOT NULL default '0', `font` TINYINT( 3 ) UNSIGNED NOT NULL DEFAULT '0', + `unban_time` int(11) unsigned NOT NULL default '0', PRIMARY KEY (`char_id`), UNIQUE KEY `name_key` (`name`), KEY `account_id` (`account_id`), @@ -669,6 +670,7 @@ INSERT INTO `sql_updates` (`timestamp`) VALUES (1383167577); INSERT INTO `sql_updates` (`timestamp`) VALUES (1383205740); INSERT INTO `sql_updates` (`timestamp`) VALUES (1383955424); INSERT INTO `sql_updates` (`timestamp`) VALUES (1384545461); +INSERT INTO `sql_updates` (`timestamp`) VALUES (1384588175); -- -- Table structure for table `sstatus` diff --git a/sql-files/upgrades/2013-11-16--07-49.sql b/sql-files/upgrades/2013-11-16--07-49.sql new file mode 100644 index 000000000..9f4b80452 --- /dev/null +++ b/sql-files/upgrades/2013-11-16--07-49.sql @@ -0,0 +1,3 @@ +#1384588175 +ALTER TABLE `char` ADD COLUMN `unban_time` int(11) unsigned NOT NULL default '0'; +INSERT INTO `sql_updates` (`timestamp`) VALUES (1384588175); \ No newline at end of file diff --git a/sql-files/upgrades/index.txt b/sql-files/upgrades/index.txt index 4fed9ff9b..1e76ee41b 100644 --- a/sql-files/upgrades/index.txt +++ b/sql-files/upgrades/index.txt @@ -12,4 +12,5 @@ 2013-10-31--07-49.sql 2013-11-09--00-03.sql 2013-11-15--00-06.sql -2013-11-15--19-57.sql \ No newline at end of file +2013-11-15--19-57.sql +2013-11-16--07-49.sql \ No newline at end of file diff --git a/src/char/char.c b/src/char/char.c index 112bbe0ae..ce05f32f4 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -1004,6 +1004,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) struct mmo_charstatus p; int j = 0, i; char last_map[MAP_NAME_LENGTH_EXT]; + size_t unban_time; stmt = SQL->StmtMalloc(sql_handle); if( stmt == NULL ) { @@ -1012,8 +1013,10 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) } memset(&p, 0, sizeof(p)); - for(i = 0 ; i < MAX_CHARS; i++ ) + for(i = 0 ; i < MAX_CHARS; i++ ) { sd->found_char[i] = -1; + sd->unban_time[i] = 0; + } // read char data if( SQL_ERROR == SQL->StmtPrepare(stmt, "SELECT " @@ -1021,7 +1024,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," "`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`," "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`," - "`robe`,`slotchange`" + "`robe`,`slotchange`,`unban_time`" " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS) || SQL_ERROR == SQL->StmtExecute(stmt) || SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL) @@ -1061,6 +1064,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) || SQL_ERROR == SQL->StmtBindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 35, SQLDT_SHORT, &p.robe, 0, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 36, SQLDT_USHORT, &p.slotchange, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 37, SQLDT_LONG, &unban_time, 0, NULL, NULL) ) { SqlStmt_ShowDebug(stmt); @@ -1071,6 +1075,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) for( i = 0; i < MAX_CHARS && SQL_SUCCESS == SQL->StmtNextRow(stmt); i++ ) { p.last_point.map = mapindex_name2id(last_map); sd->found_char[p.slot] = p.char_id; + sd->unban_time[p.slot] = unban_time; j += mmo_char_tobuf(WBUFP(buf, j), &p); } @@ -1931,6 +1936,7 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) { return 106+offset; } + /* Made Possible by Yommy~! <3 */ void mmo_char_send099d(int fd, struct char_session_data *sd) { WFIFOHEAD(fd,4 + (MAX_CHARS*MAX_CHAR_BUF)); @@ -1938,6 +1944,34 @@ void mmo_char_send099d(int fd, struct char_session_data *sd) { WFIFOW(fd,2) = mmo_chars_fromsql(sd, WFIFOP(fd,4)) + 4; WFIFOSET(fd,WFIFOW(fd,2)); } +/* Sends character ban list */ +/* Made Possible by Yommy~! <3 */ +void mmo_char_send020d(int fd, struct char_session_data *sd) { + int i; + time_t now = time(NULL); + + ARR_FIND(0, MAX_CHARS, i, sd->unban_time[i] > now); + + if( i != MAX_CHARS ) { + int c; + + WFIFOHEAD(fd, 4 + (MAX_CHARS*24)); + + WFIFOW(fd, 0) = 0x20d; + + for(i = 0, c = 0; i < MAX_CHARS; i++) { + if( sd->unban_time[i] > now ) { + WFIFOL(fd, 4 + (24*c)) = sd->found_char[i]; + timestamp2string((char*)WFIFOP(fd,8 + (28*c)), 20, sd->unban_time[i], "%Y-%m-%d %H:%M:%S"); + c++; + } + } + + WFIFOW(fd, 2) = 4 + (24*c); + + WFIFOSET(fd, WFIFOW(fd, 2)); + } +} int mmo_char_send006b(int fd, struct char_session_data* sd); //---------------------------------------- // [Ind/Hercules] notify client about charselect window data @@ -2304,6 +2338,9 @@ int parse_fromlogin(int fd) { #else mmo_char_send006b(i, sd); #endif + #if PACKETVER >= 20080000 + mmo_char_send020d(i, sd); + #endif #if PACKETVER >= 20110309 pincode->handle(i, sd); #endif @@ -3141,7 +3178,7 @@ int parse_frommap(int fd) RFIFOSKIP(fd, 86); break; - case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server) + case 0x2b0e: // Request from map-server to change an account's or character's status (accounts will just be forwarded to login server) if (RFIFOREST(fd) < 44) return 0; { @@ -3150,7 +3187,7 @@ int parse_frommap(int fd) int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request) const char* name = (char*)RFIFOP(fd,6); // name of the target character - int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban + int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban, 5 changesex, 6 charban, 7 charunban short year = RFIFOW(fd,32); short month = RFIFOW(fd,34); short day = RFIFOW(fd,36); @@ -3160,25 +3197,24 @@ int parse_frommap(int fd) RFIFOSKIP(fd,44); SQL->EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) + + if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `account_id`,`name`,`char_id`,`unban_time` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) Sql_ShowDebug(sql_handle); - else - if( SQL->NumRows(sql_handle) == 0 ) - { + else if( SQL->NumRows(sql_handle) == 0 ) { result = 1; // 1-player not found - } - else - if( SQL_SUCCESS != SQL->NextRow(sql_handle) ) + } else if( SQL_SUCCESS != SQL->NextRow(sql_handle) ) { Sql_ShowDebug(sql_handle); - //FIXME: set proper result value? - else - { + result = 1; // 1-player not found + } else { char name[NAME_LENGTH]; - int account_id; + int account_id, char_id; char* data; + time_t unban_time; SQL->GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); SQL->GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); + SQL->GetData(sql_handle, 2, &data, NULL); char_id = atoi(data); + SQL->GetData(sql_handle, 3, &data, NULL); unban_time = atol(data); if( login_fd <= 0 ) result = 3; // 3-login-server offline @@ -3186,53 +3222,111 @@ int parse_frommap(int fd) // else // if( acc != -1 && isGM(acc) < isGM(account_id) ) // result = 2; // 2-gm level too low - else - switch( type ) { - case 1: // block - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x2724; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = 5; // new account status - WFIFOSET(login_fd,10); - break; - case 2: // ban - WFIFOHEAD(login_fd,18); - WFIFOW(login_fd, 0) = 0x2725; - WFIFOL(login_fd, 2) = account_id; - WFIFOW(login_fd, 6) = year; - WFIFOW(login_fd, 8) = month; - WFIFOW(login_fd,10) = day; - WFIFOW(login_fd,12) = hour; - WFIFOW(login_fd,14) = minute; - WFIFOW(login_fd,16) = second; - WFIFOSET(login_fd,18); - break; - case 3: // unblock - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x2724; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = 0; // new account status - WFIFOSET(login_fd,10); - break; - case 4: // unban - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272a; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - break; - case 5: // changesex - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2727; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - break; + else { + switch( type ) { + case 1: // block + WFIFOHEAD(login_fd,10); + WFIFOW(login_fd,0) = 0x2724; + WFIFOL(login_fd,2) = account_id; + WFIFOL(login_fd,6) = 5; // new account status + WFIFOSET(login_fd,10); + break; + case 2: // ban + WFIFOHEAD(login_fd,18); + WFIFOW(login_fd, 0) = 0x2725; + WFIFOL(login_fd, 2) = account_id; + WFIFOW(login_fd, 6) = year; + WFIFOW(login_fd, 8) = month; + WFIFOW(login_fd,10) = day; + WFIFOW(login_fd,12) = hour; + WFIFOW(login_fd,14) = minute; + WFIFOW(login_fd,16) = second; + WFIFOSET(login_fd,18); + break; + case 3: // unblock + WFIFOHEAD(login_fd,10); + WFIFOW(login_fd,0) = 0x2724; + WFIFOL(login_fd,2) = account_id; + WFIFOL(login_fd,6) = 0; // new account status + WFIFOSET(login_fd,10); + break; + case 4: // unban + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272a; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + break; + case 5: // changesex + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x2727; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + break; + case 6: //char ban + /* handled by char server, so no redirection */ + { + time_t timestamp; + struct tm *tmtime; + SqlStmt* stmt = SQL->StmtMalloc(sql_handle); + + if (unban_time == 0 || unban_time < time(NULL)) + timestamp = time(NULL); // new ban + else + timestamp = unban_time; // add to existing ban + + tmtime = localtime(×tamp); + tmtime->tm_year = tmtime->tm_year + year; + tmtime->tm_mon = tmtime->tm_mon + month; + tmtime->tm_mday = tmtime->tm_mday + day; + tmtime->tm_hour = tmtime->tm_hour + hour; + tmtime->tm_min = tmtime->tm_min + minute; + tmtime->tm_sec = tmtime->tm_sec + second; + timestamp = mktime(tmtime); + + if( SQL_SUCCESS != SQL->StmtPrepare(stmt, + "UPDATE `%s` SET `unban_time` = ? WHERE `char_id` = ? LIMIT 1", + char_db) + || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_LONG, (void*)×tamp, sizeof(timestamp)) + || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_INT, (void*)&char_id, sizeof(char_id)) + || SQL_SUCCESS != SQL->StmtExecute(stmt) + + ) { + SqlStmt_ShowDebug(stmt); + } + + SQL->StmtFree(stmt); + + // condition applies; send to all map-servers to disconnect the player + if( timestamp > time(NULL) ) { + unsigned char buf[11]; + + WBUFW(buf,0) = 0x2b14; + WBUFL(buf,2) = account_id; + WBUFB(buf,6) = 2; + WBUFL(buf,7) = (unsigned int)timestamp; + mapif_sendall(buf, 11); + + // disconnect player if online on char-server + disconnect_player(account_id); + } + } + break; + case 7: //char unban + /* handled by char server, so no redirection */ + if( SQL_ERROR == SQL->Query(sql_handle, "UPDATE `%s` SET `unban_time` = '0' WHERE `char_id` = '%d' LIMIT 1", char_db, char_id) ) { + Sql_ShowDebug(sql_handle); + result = 1; + } + break; + + } } } SQL->FreeResult(sql_handle); // send answer if a player ask, not if the server ask - if( acc != -1 && type != 5) { // Don't send answer for changesex + if( acc != -1 && type != 5 ) { // Don't send answer for changesex WFIFOHEAD(fd,34); WFIFOW(fd, 0) = 0x2b0f; WFIFOL(fd, 2) = acc; @@ -3984,6 +4078,15 @@ int parse_char(int fd) char_id = atoi(data); SQL->FreeResult(sql_handle); + /* 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); + WFIFOW(fd,0) = 0x6c; + WFIFOB(fd,2) = 0; // rejected from server + WFIFOSET(fd,3); + break; + } + /* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */ set_char_online(-2,char_id,sd->account_id); if( !mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */ diff --git a/src/char/char.h b/src/char/char.h index a3bbdd904..c7a387645 100644 --- a/src/char/char.h +++ b/src/char/char.h @@ -20,6 +20,7 @@ struct char_session_data { bool auth; // whether the session is authed or not int account_id, login_id1, login_id2, sex; int found_char[MAX_CHARS]; // ids of chars on this account + time_t unban_time[MAX_CHARS]; // char unban time array char email[40]; // e-mail (default: a@a.com) by [Yor] time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) int group_id; // permission diff --git a/src/common/showmsg.h b/src/common/showmsg.h index 59a0d9538..43d38973f 100644 --- a/src/common/showmsg.h +++ b/src/common/showmsg.h @@ -99,5 +99,6 @@ extern void ClearScreen(void); extern void ShowFatalError(const char *, ...); extern void ShowConfigWarning(config_setting_t *config, const char *string, ...); #endif +extern int _vShowMessage(enum msg_type flag, const char *string, va_list ap); #endif /* _SHOWMSG_H_ */ diff --git a/src/common/utils.c b/src/common/utils.c index 9e3dbac47..9a7d4971b 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -287,6 +287,17 @@ unsigned int get_percentage(const unsigned int A, const unsigned int B) return (unsigned int)floor(result); } +//----------------------------------------------------- +// custom timestamp formatting (from eApp) +//----------------------------------------------------- +const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format) +{ + size_t len = strftime(str, size, format, localtime(×tamp)); + memset(str + len, '\0', size - len); + return str; +} + + /* [Ind/Hercules] Caching */ bool HCache_check(const char *file) { struct stat bufa, bufb; diff --git a/src/common/utils.h b/src/common/utils.h index 32087d78f..3e1463d6b 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -25,6 +25,8 @@ bool exists(const char* filename); /// calculates the value of A / B, in percent (rounded down) unsigned int get_percentage(const unsigned int A, const unsigned int B); +const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format); + ////////////////////////////////////////////////////////////////////////// // byte word dword access [Shinomori] ////////////////////////////////////////////////////////////////////////// diff --git a/src/login/login.c b/src/login/login.c index 3da592ebc..75247845d 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -11,6 +11,7 @@ #include "../common/socket.h" #include "../common/strlib.h" #include "../common/timer.h" +#include "../common/utils.h" #include "../common/HPM.h" #include "account.h" #include "ipban.h" @@ -271,18 +272,6 @@ bool check_password(const char* md5key, int passwdenc, const char* passwd, const } } - -//----------------------------------------------------- -// custom timestamp formatting (from eApp) -//----------------------------------------------------- -const char* timestamp2string(char* str, size_t size, time_t timestamp, const char* format) -{ - size_t len = strftime(str, size, format, localtime(×tamp)); - memset(str + len, '\0', size - len); - return str; -} - - //-------------------------------------------- // Test to know if an IP come from LAN or WAN. //-------------------------------------------- diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 902d179db..a2bea32a8 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -2798,7 +2798,7 @@ ACMD(char_ban) return false; } - chrif->char_ask_name(sd->status.account_id, atcmd_player_name, 2, year, month, day, hour, minute, second); // type: 2 - ban + chrif->char_ask_name(sd->status.account_id, atcmd_player_name, !strcmpi(info->command,"charban") ? 6 : 2, year, month, day, hour, minute, second); // type: 2 - ban; 6 - charban clif->message(fd, msg_txt(88)); // Character name sent to char-server to ask it. return true; @@ -2838,7 +2838,7 @@ ACMD(char_unban) } // send answer to login server via char-server - chrif->char_ask_name(sd->status.account_id, atcmd_player_name, 4, 0, 0, 0, 0, 0, 0); // type: 4 - unban + chrif->char_ask_name(sd->status.account_id, atcmd_player_name, !strcmpi(info->command,"charunban") ? 7 : 4, 0, 0, 0, 0, 0, 0); // type: 4 - unban account; type 7 - unban character clif->message(fd, msg_txt(88)); // Character name sent to char-server to ask it. return true; @@ -3138,7 +3138,7 @@ ACMD(spiritball) if( !message || !*message || (number = atoi(message)) < 0 || number > max_spiritballs ) { char msg[CHAT_SIZE_MAX]; - safesnprintf(msg, sizeof(msg), msg_txt(1028), max_spiritballs); // Please enter a party name (usage: @party ). + safesnprintf(msg, sizeof(msg), msg_txt(1028), max_spiritballs); // Please enter an amount (usage: @spiritball ). clif->message(fd, msg); return false; } @@ -9448,7 +9448,9 @@ void atcommand_basecommands(void) { ACMD_DEF2("allstats", stat_all), ACMD_DEF2("block", char_block), ACMD_DEF2("ban", char_ban), + ACMD_DEF2("charban", char_ban),/* char-specific ban time */ ACMD_DEF2("unblock", char_unblock), + ACMD_DEF2("charunban", char_unban),/* char-specific ban time */ ACMD_DEF2("unban", char_unban), ACMD_DEF2("mount", mount_peco), ACMD_DEF(guildspy), diff --git a/src/map/chrif.c b/src/map/chrif.c index 87ec71ec5..56572d492 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -752,7 +752,7 @@ int chrif_changeemail(int id, const char *actual_email, const char *new_email) { * S 2b0e .l .24B .w { .w .w .w .w .w .w } * Send an account modification request to the login server (via char server). * type of operation: - * 1: block, 2: ban, 3: unblock, 4: unban, 5: changesex (use next function for 5) + * 1: block, 2: ban, 3: unblock, 4: unban, 5: changesex (use next function for 5), 6: charban *------------------------------------------*/ int chrif_char_ask_name(int acc, const char* character_name, unsigned short operation_type, int year, int month, int day, int hour, int minute, int second) { @@ -764,7 +764,7 @@ int chrif_char_ask_name(int acc, const char* character_name, unsigned short oper safestrncpy((char*)WFIFOP(chrif->fd,6), character_name, NAME_LENGTH); WFIFOW(chrif->fd,30) = operation_type; - if ( operation_type == 2 ) { + if ( operation_type == 2 || operation_type == 6 ) { WFIFOW(chrif->fd,32) = year; WFIFOW(chrif->fd,34) = month; WFIFOW(chrif->fd,36) = day; @@ -800,7 +800,7 @@ int chrif_changesex(struct map_session_data *sd) { * R 2b0f .l .24B .w .w * Processing a reply to chrif->char_ask_name() (request to modify an account). * type of operation: - * 1: block, 2: ban, 3: unblock, 4: unban, 5: changesex + * 1: block, 2: ban, 3: unblock, 4: unban, 5: changesex, 6: charban, 7: charunban * type of answer: * 0: login-server request done * 1: player not found @@ -811,6 +811,7 @@ void chrif_char_ask_name_answer(int acc, const char* player_name, uint16 type, u struct map_session_data* sd; char action[25]; char output[256]; + bool charsrv = ( type == 6 || type == 7 ) ? true : false; sd = map->id2sd(acc); @@ -819,13 +820,17 @@ void chrif_char_ask_name_answer(int acc, const char* player_name, uint16 type, u return; } + /* re-use previous msg_txt */ + if( type == 6 ) type = 2; + if( type == 7 ) type = 4; + if( type > 0 && type <= 5 ) snprintf(action,25,"%s",msg_txt(427+type)); //block|ban|unblock|unban|change the sex of else snprintf(action,25,"???"); switch( answer ) { - case 0 : sprintf(output, msg_txt(424), action, NAME_LENGTH, player_name); break; + case 0 : sprintf(output, msg_txt(charsrv?434:424), action, NAME_LENGTH, player_name); break; case 1 : sprintf(output, msg_txt(425), NAME_LENGTH, player_name); break; case 2 : sprintf(output, msg_txt(426), action, NAME_LENGTH, player_name); break; case 3 : sprintf(output, msg_txt(427), action, NAME_LENGTH, player_name); break; @@ -980,7 +985,7 @@ int chrif_accountban(int fd) { } sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters - if (RFIFOB(fd,6) == 0) { // 0: change of statut, 1: ban + if (RFIFOB(fd,6) == 0) { // 0: change of statut int ret_status = RFIFOL(fd,7); // status or final date of a banishment if(0message(sd->fd, msg_txt(411+ret_status)); @@ -988,13 +993,20 @@ int chrif_accountban(int fd) { clif->message(sd->fd, msg_txt(421)); else clif->message(sd->fd, msg_txt(420)); //"Your account has not more authorised." - } else if (RFIFOB(fd,6) == 1) { // 0: change of statut, 1: ban + } else if (RFIFOB(fd,6) == 1) { // 1: ban time_t timestamp; char tmpstr[2048]; timestamp = (time_t)RFIFOL(fd,7); // status or final date of a banishment strcpy(tmpstr, msg_txt(423)); //"Your account has been banished until " strftime(tmpstr + strlen(tmpstr), 24, "%d-%m-%Y %H:%M:%S", localtime(×tamp)); clif->message(sd->fd, tmpstr); + } else if (RFIFOB(fd,6) == 2) { // 2: change of status for character + time_t timestamp; + char tmpstr[2048]; + timestamp = (time_t)RFIFOL(fd,7); // status or final date of a banishment + strcpy(tmpstr, msg_txt(433)); //"This character has been banned until " + strftime(tmpstr + strlen(tmpstr), 24, "%d-%m-%Y %H:%M:%S", localtime(×tamp)); + clif->message(sd->fd, tmpstr); } set_eof(sd->fd); // forced to disconnect for the change diff --git a/src/map/clif.c b/src/map/clif.c index d84a0dea8..6740c7a74 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -5634,7 +5634,38 @@ void clif_displaymessage2(const int fd, const char* mes) { aFree(message); } } +/* oh noo! another version of 0x8e! */ +void clif_displaymessage_sprintf(const int fd, const char* mes, ...) { + va_list ap; + if( fd == -2 ) { + ShowInfo("HCP: "); + va_start(ap,mes); + _vShowMessage(MSG_NONE,mes,ap); + va_end(ap); + ShowMessage("\n"); + } else if ( fd > 0 ) { + int len = 1; + char *ptr; + + WFIFOHEAD(fd, 5 + 255);/* ensure the maximum */ + + /* process */ + va_start(ap,mes); + len += vsnprintf((char *)WFIFOP(fd,4), 255, mes, ap); + va_end(ap); + + /* adjusting */ + ptr = (char *)WFIFOP(fd,4); + ptr[len - 1] = '\0'; + + /* */ + WFIFOW(fd,0) = 0x8e; + WFIFOW(fd,2) = 5 + len; // 4 + len + NULL teminate + + WFIFOSET(fd, 5 + len); + } +} /// Send broadcast message in yellow or blue without font formatting (ZC_BROADCAST). /// 009a .W .?B void clif_broadcast(struct block_list* bl, const char* mes, int len, int type, enum send_target target) @@ -18407,6 +18438,7 @@ void clif_defaults(void) { clif->msgtable_num = clif_msgtable_num; clif->message = clif_displaymessage; clif->messageln = clif_displaymessage2; + clif->messages = clif_displaymessage_sprintf; clif->colormes = clif_colormes; clif->process_message = clif_process_message; clif->wisexin = clif_wisexin; diff --git a/src/map/clif.h b/src/map/clif.h index e50af7432..043f7dd3a 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -787,6 +787,8 @@ struct clif_interface { void (*msgtable_num) (int fd, int line, int num); void (*message) (const int fd, const char* mes); void (*messageln) (const int fd, const char* mes); + /* message+s(printf) */ + void (*messages) (const int fd, const char* mes, ...); int (*colormes) (int fd, enum clif_colors color, const char* msg); bool (*process_message) (struct map_session_data* sd, int format, char** name_, int* namelen_, char** message_, int* messagelen_); void (*wisexin) (struct map_session_data *sd,int type,int flag); -- cgit v1.2.3-70-g09d2 From cf19b26d50ac96111e44c33a80afd1f1ea935cec Mon Sep 17 00:00:00 2001 From: shennetsind Date: Tue, 24 Dec 2013 02:03:04 -0200 Subject: Christmas Patch - 2013-12-23 Support Info: http://hercules.ws/board/topic/3614-christmas-patch-gifto/ Signed-off-by: shennetsind --- db/const.txt | 6 + doc/sample/npc_trader_sample.txt | 58 + doc/script_commands.txt | 64 + npc/merchants/shops.txt | 2240 +++++++++++++++++++++++++++--- sql-files/main.sql | 12 + sql-files/upgrades/2013-12-24--00-15.sql | 8 + sql-files/upgrades/index.txt | 1 + src/common/mmo.h | 2 +- src/map/atcommand.c | 27 +- src/map/clif.c | 224 ++- src/map/clif.h | 8 + src/map/map.c | 3 +- src/map/npc.c | 566 ++++++-- src/map/npc.h | 46 +- src/map/packets.h | 43 + src/map/packets_struct.h | 44 + src/map/script.c | 277 +++- src/map/status.c | 324 ++--- src/map/status.h | 51 +- 19 files changed, 3500 insertions(+), 504 deletions(-) create mode 100644 doc/sample/npc_trader_sample.txt create mode 100644 sql-files/upgrades/2013-12-24--00-15.sql (limited to 'sql-files/main.sql') diff --git a/db/const.txt b/db/const.txt index 8e7807695..ab14afca2 100644 --- a/db/const.txt +++ b/db/const.txt @@ -1257,6 +1257,7 @@ SC_MTF_MLEATKED 569 SC_MTF_CRIDAMAGE 570 SC_MOONSTAR 571 SC_SUPER_STAR 572 +SC_OKTOBERFEST 573 e_gasp 0 e_what 1 @@ -3348,3 +3349,8 @@ IOT_GUILD 3 false 0 true 1 + +NST_ZENY 0 +NST_CASH 1 +NST_MARKET 2 +NST_CUSTOM 3 diff --git a/doc/sample/npc_trader_sample.txt b/doc/sample/npc_trader_sample.txt new file mode 100644 index 000000000..abc87f6b4 --- /dev/null +++ b/doc/sample/npc_trader_sample.txt @@ -0,0 +1,58 @@ +//===== Hercules Script ======================================= +//= Sample: NPC Trader +//===== By: ================================================== +//= Hercules Dev Team +//===== Current Version: ===================================== +//= 20131223 +//===== Description: ========================================= +//= Demonstrates NPC Trader. +//============================================================ + +/* ordinary zeny trader */ +prontera,152,151,1 trader TestTrader 952,{ + OnInit: + sellitem 2115; + end; +} +/* ordinary cash trader */ +prontera,152,152,1 trader TestTraderCash 952,{ + OnInit: + tradertype(NST_CASH); + sellitem 2115; + end; +} +/* custom npc trader */ +prontera,153,152,1 trader TestCustom2 952,{ + OnInit: + tradertype(NST_CUSTOM); + sellitem 501,2; + end; + +/* allows currency to be item 501 and 502 */ +OnCountFunds: + setcurrency(countitem(501),countitem(502)); + end; + +/* receives @price (total cost) and @points (the secondary input field for cash windows) */ +OnPayFunds: + dispbottom "Hi: price="+@price+" and points="+@points; + if( countitem(502) < @points || countitem(501) < @price-@points ) + end; + delitem 502,@points; + delitem 501,@price-@points; + purchaseok(); + end; +} +/* demonstrates Market Trader */ +prontera,150,160,6 trader HaiMarket 952,{ +OnInit: + tradertype(NST_MARKET); + sellitem 501,-1,49; + end; + +OnClock0000://resupplies red potions on midnight +OnMyResupply: + if( shopcount(501) < 20 ) + sellitem 501,-1,49; + end; +} \ No newline at end of file diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 9186ba714..f5f2d7d9c 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -1120,6 +1120,7 @@ From here on, we will have the commands sorted as follow: 9.- Battleground commands. 10.- Mercenary commands. 11.- Queue commands. +12.- NPC Trader commands ===================== @@ -8471,3 +8472,66 @@ Deletes a queue iterator from memory and returns 1 when it fails, otherwise 0 is returned. --------------------------------------- + +====================== +|12.- NPC Trader Commands.| +====================== +--------------------------------------- +Commands that control NPC Trader Shops +See /doc/sample/npc_trader_sample.txt + +--------------------------------------- + +*openshop({NPC_Name}); + +opens the trader shop from the currently-attached npc unless, +when the optional NPC_Name param is used. + +--------------------------------------- + +*sellitem {,{,}}; + +adds (or modifies) data to the shop, +when is not provided (or when it is -1) itemdb default is used. +qty is only necessary for NST_MARKET trader types. + +when is already in the shop, +the previous data (price/qty), is overwritten with the new. + +--------------------------------------- + +*stopselling ; + +attempts to remove from the current shop list. + +--------------------------------------- + +*setcurrency {,}; + +updates the currently attached player shop funds. + +--------------------------------------- + +*tradertype(); + +Modifies the npc trader type, item list is cleared upon modifiying the value. +By default, all npcs staart with tradertype(NST_ZENY); + +- NST_ZENY (0) Normal Zeny Shop +- NST_CASH (1) Normal Cash Shop +- NST_MARKET (2) Normal NPC Market Shop (where items have limited availability and need to be refurbished) +- NST_CUSTOM (3) Custom Shop (any currency, item/var/etca, check sample) + +--------------------------------------- + +*purchaseok(); + +Signs that the transaction (on a NST_CUSTOM trader) has been successful. + +--------------------------------------- + +*shopcount(); + +Returns the amount of still-available in the shop (on a NST_MARKET trader). + +--------------------------------------- diff --git a/npc/merchants/shops.txt b/npc/merchants/shops.txt index b20874ffb..a1ab894d0 100644 --- a/npc/merchants/shops.txt +++ b/npc/merchants/shops.txt @@ -1,9 +1,7 @@ //===== Hercules Script ====================================== //= Shops -//===== By: ================================================== -//= rAthena Dev Team //===== Current Version: ===================================== -//= 3.4 +//= 3.5 //===== Description: ========================================= //= Town shop NPCs. //===== Additional Comments: ================================= @@ -36,291 +34,2169 @@ //= 3.2 Added Missing Items to the pet Groomers in prontera, payon, and yuno. BugReport:6680[Spre] //= 3.3 Moved more shops to Renewal file. [Euphy] //= 3.4 Moved Izlude shops to pre-re/re paths. [Streusel] +//= 3.5 Converted to trader format [Yommy] //============================================================ //======================================================= // Alberta //======================================================= -alb2trea,87,65,5 shop Tool Dealer#alb 4_M_01,1750:-1,1751:-1,1752:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1 -alberta_in,165,96,0 shop Item Collector#alb 1_F_MERCHANT_02,911:-1,528:-1 -alberta_in,182,97,0 shop Tool Dealer#alb2 1_F_MERCHANT_01,1750:-1,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,2243:-1 -alberta_in,180,15,0 shop Armor Dealer#alb 4W_F_01,2101:-1,2103:-1,2401:-1,2403:-1,2405:-1,2501:-1,2503:-1,2505:-1,2203:-1,2201:-1,2205:-1,2226:-1,2301:-1,2303:-1,2305:-1,2321:-1,2328:-1,2332:-1,2307:-1,2309:-1,2312:-1,2314:-1,2628:-1 -alberta_in,188,21,0 shop Weapon Dealer#alb 1_M_03,1750:-1,1751:-1,1101:-1,1104:-1,1107:-1,1201:-1,1204:-1,1207:-1,1601:-1,1701:-1,1301:-1,1351:-1,1354:-1,1357:-1,1360:-1 -alberta_in,175,97,4 shop Weapon Dealer#alb2 4_KID01,1146:-1,1245:-1 -alberta_in,176,81,3 shop Trading Merchant#alb 4_M_HUMERCHANT,13200:-1,13201:-1,13202:-1,13150:-1,13102:-1,13151:-1,13154:-1,13155:-1,13163:-1,13165:-1,13168:-1 +alb2trea,87,65,5 trader Tool Dealer#alb 4_M_01,{ +OnInit: + sellitem Arrow; + sellitem Silver_Arrow; + sellitem Fire_Arrow; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; +} + +alberta_in,165,96,0 trader Item Collector#alb 1_F_MERCHANT_02,{ +OnInit: + sellitem Scell; + sellitem Monster's_Feed; +} + +alberta_in,182,97,0 trader Tool Dealer#alb2 1_F_MERCHANT_01,{ +OnInit: + sellitem Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Spinning_Eyes; +} + +alberta_in,180,15,0 trader Armor Dealer#alb 4W_F_01,{ +OnInit: + sellitem Guard; + sellitem Buckler; + sellitem Sandals; + sellitem Shoes; + sellitem Boots; + sellitem Hood; + sellitem Muffler; + sellitem Manteau; + sellitem Glasses; + sellitem Sunglasses; + sellitem Diver's_Goggles; + sellitem Cap; + sellitem Cotton_Shirt; + sellitem Leather_Jacket; + sellitem Adventure_Suit; + sellitem Silk_Robe; + sellitem Wooden_Mail; + sellitem Silver_Robe; + sellitem Mantle; + sellitem Coat; + sellitem Padded_Armor; + sellitem Chain_Mail; + sellitem Novice_Armlet; +} + +alberta_in,188,21,0 trader Weapon Dealer#alb 1_M_03,{ +OnInit: + sellitem Arrow; + sellitem Silver_Arrow; + sellitem Sword; + sellitem Falchion; + sellitem Blade; + sellitem Knife; + sellitem Cutter; + sellitem Main_Gauche; + sellitem Rod; + sellitem Bow; + sellitem Axe; + sellitem Battle_Axe; + sellitem Hammer; + sellitem Buster; + sellitem Two_Handed_Axe; +} + +alberta_in,175,97,4 trader Weapon Dealer#alb2 4_KID01,{ +OnInit: + sellitem Town_Sword; + sellitem Cinquedea; +} + +alberta_in,176,81,3 trader Trading Merchant#alb 4_M_HUMERCHANT,{ +OnInit: + sellitem Bullet; + sellitem Silver_Bullet; + sellitem Shell_Of_Blood; + sellitem Branch; + sellitem Crimson_Bolt; + sellitem The_Cyclone; + sellitem Rolling_Stone; + sellitem Black_Rose; + sellitem Long_Barrel; + sellitem Jungle_Carbine; + sellitem Thunder_P; +} + //======================================================= // Al De Baran //======================================================= -aldeba_in,20,60,0 shop Armor Dealer#alde 4W_F_01,2228:-1,2103:-1,2105:-1,2307:-1,2309:-1,2312:-1,2314:-1,2316:-1,2505:-1,2405:-1,2628:-1,2627:-1 -aldeba_in,28,54,0 shop Weapon Dealer#alde 1_M_03,1201:-1,1204:-1,1207:-1,1210:-1,1213:-1,1216:-1,1219:-1,1222:-1 -aldeba_in,22,47,4 shop Weapon Dealer#alde2 4_M_06,1146:-1,1245:-1 -aldeba_in,94,56,5 shop Tool Dealer#alde 4_M_01,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,611:-1,610:-1 -alde_alche,38,184,3 shop Material Seller#alche 4_M_SAGE_C,7143:-1,7141:-1,7140:-1,6248:-1,6250:-1,6251:-1,6255:-1,6261:-1,6262:-1,6297:-1 +aldeba_in,20,60,0 trader Armor Dealer#alde 4W_F_01,{ +OnInit: + sellitem Helm; + sellitem Buckler; + sellitem Shield; + sellitem Mantle; + sellitem Coat; + sellitem Padded_Armor; + sellitem Chain_Mail; + sellitem Plate_Armor; + sellitem Manteau; + sellitem Boots; + sellitem Novice_Armlet; + sellitem Belt; +} + +aldeba_in,28,54,0 trader Weapon Dealer#alde 1_M_03,{ +OnInit: + sellitem Knife; + sellitem Cutter; + sellitem Main_Gauche; + sellitem Dirk; + sellitem Dagger; + sellitem Stiletto; + sellitem Gladius; + sellitem Damascus; +} + +aldeba_in,22,47,4 trader Weapon Dealer#alde2 4_M_06,{ +OnInit: + sellitem Town_Sword; + sellitem Cinquedea; +} + +aldeba_in,94,56,5 trader Tool Dealer#alde 4_M_01,{ +OnInit: + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Spectacles; + sellitem Leaf_Of_Yggdrasil; +} + +alde_alche,38,184,3 trader Material Seller#alche 4_M_SAGE_C,{ +OnInit: + sellitem Life_Force_Pot; + sellitem Yggdrasilberry_Dew; + sellitem Seed_Of_Life; + sellitem Melange_Pot; + sellitem Cooking_Skewer; + sellitem Black_Charcoal; + sellitem Large_Cookpot; + sellitem Fine_Noodle; + sellitem Cool_Gravy; + sellitem Bottle_To_Throw; +} + //======================================================= // Amatsu //======================================================= -ama_in01,89,28,5 shop Armor Dealer#ama 4_F_JPN2,2211:-1,2401:-1,2403:-1,2501:-1,2503:-1,2101:-1,2103:-1,2305:-1,2321:-1,2332:-1,2328:-1,2627:-1 -ama_in01,102,28,3 shop Weapon Dealer#ama 4_M_JPNOJI,1207:-1,1216:-1,1107:-1,1122:-1,1116:-1,1154:-1,1407:-1,1457:-1,1354:-1,1519:-1 -ama_in01,24,30,5 shop Tool Dealer#ama 4_M_JPN,1750:-1,1770:-1,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,1065:-1 +ama_in01,89,28,5 trader Armor Dealer#ama 4_F_JPN2,{ +OnInit: + sellitem Bandana; + sellitem Sandals; + sellitem Shoes; + sellitem Hood; + sellitem Muffler; + sellitem Guard; + sellitem Buckler; + sellitem Adventure_Suit; + sellitem Silk_Robe; + sellitem Silver_Robe; + sellitem Wooden_Mail; + sellitem Belt; +} + +ama_in01,102,28,3 trader Weapon Dealer#ama 4_M_JPNOJI,{ +OnInit: + sellitem Main_Gauche; + sellitem Stiletto; + sellitem Blade; + sellitem Ring_Pommel_Saber; + sellitem Katana; + sellitem Bastard_Sword; + sellitem Pike; + sellitem Partizan; + sellitem Hammer; + sellitem Chain; +} + +ama_in01,24,30,5 trader Tool Dealer#ama 4_M_JPN,{ +OnInit: + sellitem Arrow; + sellitem Iron_Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Booby_Trap; +} + // Ninja Shops -que_ng,72,31,2 shop Boonji#nin 4_M_01,13250:-1,13251:-1,13252:-1,13253:-1,13254:-1 -que_ng,73,26,5 shop Boonray#nin 4_M_01,2117:-1,7521:-1,7522:-1,7523:-1,7524:-1 +que_ng,72,31,2 trader Boonji#nin 4_M_01,{ +OnInit: + sellitem Shuriken; + sellitem Nimbus_Shuriken; + sellitem Flash_Shuriken; + sellitem Sharp_Leaf_Shuriken; + sellitem Thorn_Needle_Shuriken; +} + +que_ng,73,26,5 trader Boonray#nin 4_M_01,{ +OnInit: + sellitem Arm_Guard; + sellitem Flame_Stone; + sellitem Ice_Stone; + sellitem Wind_Stone; + sellitem Shadow_Orb; +} + //======================================================= // Ayothaya //======================================================= -ayo_in01,18,182,1 shop Tool Dealer#ayo 4_F_THAISHAMAN,1750:-1,1770:-1,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,1065:-1 -ayo_in01,90,192,3 shop Weapon Dealer#ayo 4_M_THAIONGBAK,1207:-1,1216:-1,1107:-1,1122:-1,1116:-1,1154:-1,1407:-1,1457:-1,1354:-1,1519:-1 -ayo_in01,90,160,1 shop Armor Dealer#ayo 4_M_THAIOLD,2211:-1,2401:-1,2403:-1,2501:-1,2503:-1,2101:-1,2103:-1,2305:-1,2321:-1,2332:-1,2328:-1,2627:-1 +ayo_in01,18,182,1 trader Tool Dealer#ayo 4_F_THAISHAMAN,{ +OnInit: + sellitem Arrow; + sellitem Iron_Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Booby_Trap; +} + +ayo_in01,90,192,3 trader Weapon Dealer#ayo 4_M_THAIONGBAK,{ +OnInit: + sellitem Main_Gauche; + sellitem Stiletto; + sellitem Blade; + sellitem Ring_Pommel_Saber; + sellitem Katana; + sellitem Bastard_Sword; + sellitem Pike; + sellitem Partizan; + sellitem Hammer; + sellitem Chain; +} + +ayo_in01,90,160,1 trader Armor Dealer#ayo 4_M_THAIOLD,{ +OnInit: + sellitem Bandana; + sellitem Sandals; + sellitem Shoes; + sellitem Hood; + sellitem Muffler; + sellitem Guard; + sellitem Buckler; + sellitem Adventure_Suit; + sellitem Silk_Robe; + sellitem Silver_Robe; + sellitem Wooden_Mail; + sellitem Belt; +} + //======================================================= // Brasilis //======================================================= -brasilis,252,257,3 shop Tool Dealer#bra 4_F_BRZ_WOMAN,645:-1,656:-1,601:-1,602:-1,611:-1,1065:-1,610:-1 -brasilis,244,243,3 shop Weapon Dealer#bra 4_M_BRZ_MAN2,1407:-1,1457:-1,1354:-1,1519:-1,13003:-1 -brasilis,201,309,3 shop Pet Groomer#bra 4_M_BRZ_MAN1,537:-1,643:-1 -brasilis,221,128,3 shop Fruit Gardener#bra 4_M_BRZ_MAN2,11515:-1,513:-1,11516:-1 +brasilis,252,257,3 trader Tool Dealer#bra 4_F_BRZ_WOMAN,{ +OnInit: + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Spectacles; + sellitem Booby_Trap; + sellitem Leaf_Of_Yggdrasil; +} + +brasilis,244,243,3 trader Weapon Dealer#bra 4_M_BRZ_MAN2,{ +OnInit: + sellitem Pike; + sellitem Partizan; + sellitem Hammer; + sellitem Chain; + sellitem Coward; +} + +brasilis,201,309,3 trader Pet Groomer#bra 4_M_BRZ_MAN1,{ +OnInit: + sellitem Pet_Food; + sellitem Pet_Incubator; +} + +brasilis,221,128,3 trader Fruit Gardener#bra 4_M_BRZ_MAN2,{ +OnInit: + sellitem Coconut; + sellitem Banana; + sellitem Asai_Fruit; +} + //======================================================= // Comodo //======================================================= -cmd_in01,117,165,4 shop Armor Dealer#cmd 4W_F_01,2226:-1,2228:-1,2103:-1,2105:-1,2405:-1,2503:-1,2505:-1,2305:-1,2321:-1,2307:-1,2309:-1,2335:-1,2312:-1,2314:-1,2316:-1 -cmd_in01,128,165,2 shop Weapon Dealer#cmd 1_M_03,1901:-1,1903:-1,1905:-1,1909:-1,1911:-1,1907:-1,1950:-1,1952:-1,1954:-1,1958:-1,1960:-1,1956:-1 -cmd_in01,79,182,5 shop Tool Dealer#cmd 4_M_01,1770:-1,501:-1,502:-1,503:-1,504:-1,645:-1,656:-1,657:-1,601:-1,602:-1,611:-1,1065:-1 -comodo,296,125,4 shop Souvenir Vendor#cmd 4W_F_01,965:-1,964:-1 -cmd_fild07,257,126,5 shop Tool Dealer#cmd2 4_M_01,1770:-1,501:-1,502:-1,503:-1,504:-1,645:-1,656:-1,601:-1,602:-1,611:-1,1065:-1 -cmd_fild07,250,98,2 shop Weapon Dealer#cmd2 1_M_03,1401:-1,1404:-1,1407:-1,1451:-1,1454:-1,1457:-1,1460:-1,1463:-1,1410:-1 -cmd_fild07,277,85,4 shop Armor Dealer#cmd2 4W_F_01,2226:-1,2228:-1,2103:-1,2105:-1,2405:-1,2503:-1,2505:-1,2305:-1,2321:-1,2307:-1,2309:-1,2335:-1,2312:-1,2314:-1,2316:-1 +cmd_in01,117,165,4 trader Armor Dealer#cmd 4W_F_01,{ +OnInit: + sellitem Cap; + sellitem Helm; + sellitem Buckler; + sellitem Shield; + sellitem Boots; + sellitem Muffler; + sellitem Manteau; + sellitem Adventure_Suit; + sellitem Silk_Robe; + sellitem Mantle; + sellitem Coat; + sellitem Thief_Clothes; + sellitem Padded_Armor; + sellitem Chain_Mail; + sellitem Plate_Armor; +} + +cmd_in01,128,165,2 trader Weapon Dealer#cmd 1_M_03,{ +OnInit: + sellitem Violin; + sellitem Mandolin; + sellitem Lute; + sellitem Harp; + sellitem Guh_Moon_Goh; + sellitem Guitar; + sellitem Rope; + sellitem Line; + sellitem Wire; + sellitem Tail; + sellitem Whip; + sellitem Rante; +} + +cmd_in01,79,182,5 trader Tool Dealer#cmd 4_M_01,{ +OnInit: + sellitem Iron_Arrow; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Berserk_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Spectacles; + sellitem Booby_Trap; +} + +comodo,296,125,4 trader Souvenir Vendor#cmd 4W_F_01,{ +OnInit: + sellitem Clam_Shell; + sellitem Crap_Shell; +} + +cmd_fild07,257,126,5 trader Tool Dealer#cmd2 4_M_01,{ +OnInit: + sellitem Iron_Arrow; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Spectacles; + sellitem Booby_Trap; +} + +cmd_fild07,250,98,2 trader Weapon Dealer#cmd2 1_M_03,{ +OnInit: + sellitem Javelin; + sellitem Spear; + sellitem Pike; + sellitem Guisarme; + sellitem Glaive; + sellitem Partizan; + sellitem Trident; + sellitem Halberd; + sellitem Lance; +} + +cmd_fild07,277,85,4 trader Armor Dealer#cmd2 4W_F_01,{ +OnInit: + sellitem Cap; + sellitem Helm; + sellitem Buckler; + sellitem Shield; + sellitem Boots; + sellitem Muffler; + sellitem Manteau; + sellitem Adventure_Suit; + sellitem Silk_Robe; + sellitem Mantle; + sellitem Coat; + sellitem Thief_Clothes; + sellitem Padded_Armor; + sellitem Chain_Mail; + sellitem Plate_Armor; +} + //======================================================= // Einbroch //======================================================= -ein_in01,106,27,4 shop One Hand Weapon Dealer 4_F_EINWOMAN,1101:-1,1104:-1,1107:-1,1110:-1,1113:-1,1119:-1,1122:-1,1123:-1,1126:-1,1129:-1,1201:-1,1204:-1,1207:-1,1210:-1,1213:-1,1216:-1,1219:-1,1222:-1,1301:-1,1401:-1,1404:-1,1407:-1,1501:-1,1504:-1,1507:-1,1510:-1,1513:-1,1516:-1,1519:-1,1522:-1,1801:-1,1803:-1,1805:-1,1807:-1,1809:-1,1811:-1 -ein_in01,109,27,4 shop Two Hand Weapon Dealer 4_F_EINWOMAN,1116:-1,1151:-1,1154:-1,1157:-1,1160:-1,1351:-1,1354:-1,1357:-1,1360:-1,1410:-1,1451:-1,1454:-1,1457:-1,1460:-1,1463:-1,1250:-1,1252:-1,1254:-1 -ein_in01,119,26,4 shop Weapon Dealer#ein 4_M_EINMAN,1247:-1,1248:-1,1249:-1,13000:-1 -ein_in01,189,15,1 shop Tool Dealer#ein 4_F_EINWOMAN,1750:-1,1752:-1,1751:-1,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,1065:-1 -einbroch,138,66,4 shop Flu Mask Dealer#ein 4_F_EINWOMAN,5114:-1,2218:-1 -einbroch,82,199,4 shop Paddler#ein 4_M_EINMAN,512:-1,645:-1,1750:-1,501:-1 +ein_in01,106,27,4 trader One Hand Weapon Dealer 4_F_EINWOMAN,{ +OnInit: + sellitem Sword; + sellitem Falchion; + sellitem Blade; + sellitem Lapier; + sellitem Scimiter; + sellitem Tsurugi; + sellitem Ring_Pommel_Saber; + sellitem Haedonggum; + sellitem Saber; + sellitem Flamberge; + sellitem Knife; + sellitem Cutter; + sellitem Main_Gauche; + sellitem Dirk; + sellitem Dagger; + sellitem Stiletto; + sellitem Gladius; + sellitem Damascus; + sellitem Axe; + sellitem Javelin; + sellitem Spear; + sellitem Pike; + sellitem Club; + sellitem Mace; + sellitem Smasher; + sellitem Flail; + sellitem Morning_Star; + sellitem Sword_Mace; + sellitem Chain; + sellitem Stunner; + sellitem Waghnakh; + sellitem Knuckle_Duster; + sellitem Hora; + sellitem Fist; + sellitem Claw; + sellitem Finger; +} + +ein_in01,109,27,4 trader Two Hand Weapon Dealer 4_F_EINWOMAN,{ +OnInit: + sellitem Katana; + sellitem Slayer; + sellitem Bastard_Sword; + sellitem Two_Hand_Sword; + sellitem Broad_Sword; + sellitem Battle_Axe; + sellitem Hammer; + sellitem Buster; + sellitem Two_Handed_Axe; + sellitem Lance; + sellitem Guisarme; + sellitem Glaive; + sellitem Partizan; + sellitem Trident; + sellitem Halberd; + sellitem Jur; + sellitem Katar; + sellitem Jamadhar; +} + +ein_in01,119,26,4 trader Weapon Dealer#ein 4_M_EINMAN,{ +OnInit: + sellitem Kindling_Dagger; + sellitem Obsidian_Dagger; + sellitem Fisherman's_Dagger; + sellitem Jujube_Dagger; +} + +ein_in01,189,15,1 trader Tool Dealer#ein 4_F_EINWOMAN,{ +OnInit: + sellitem Arrow; + sellitem Fire_Arrow; + sellitem Silver_Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Booby_Trap; +} + +einbroch,138,66,4 trader Flu Mask Dealer#ein 4_F_EINWOMAN,{ +OnInit: + sellitem Fedora; + sellitem Flu_Mask; +} + +einbroch,82,199,4 trader Paddler#ein 4_M_EINMAN,{ +OnInit: + sellitem Apple; + sellitem Center_Potion; + sellitem Arrow; + sellitem Red_Potion; +} + //Official Gunslingers shops. -que_ng,179,91,3 shop Chivas Lugal 4_M_HUMERCHANT,13150:-1,13102:-1,13151:-1,13154:-1,13155:-1,13163:-1,13165:-1,13168:-1 -que_ng,180,79,3 shop Johnny Waiker 4_M_HUMERCHANT,13200:-1,13201:-1,13202:-1 +que_ng,179,91,3 trader Chivas Lugal 4_M_HUMERCHANT,{ +OnInit: + sellitem Branch; + sellitem Crimson_Bolt; + sellitem The_Cyclone; + sellitem Rolling_Stone; + sellitem Black_Rose; + sellitem Long_Barrel; + sellitem Jungle_Carbine; + sellitem Thunder_P; +} + +que_ng,180,79,3 trader Johnny Waiker 4_M_HUMERCHANT,{ +OnInit: + sellitem Bullet; + sellitem Silver_Bullet; + sellitem Shell_Of_Blood; +} + //======================================================= // Geffen //======================================================= -geffen_in,26,178,4 shop Armor Dealer#gef 1_F_01,2628:-1,2101:-1,2107:-1,2401:-1,2501:-1,2230:-1,2301:-1,2303:-1,2305:-1,2321:-1,2332:-1 -geffen_in,30,178,4 shop Weapon Dealer#gef2 1_M_01,1750:-1,1751:-1,1101:-1,1701:-1,1201:-1,1204:-1,1207:-1,1210:-1,1213:-1,1216:-1,1601:-1,1604:-1,1607:-1,1610:-1 -geffen_in,22,171,7 shop Weapon Dealer#gef 4_M_02,1146:-1,1245:-1 -geffen_in,74,144,0 shop Trader#gef 1_F_01,911:-1,910:-1,912:-1 -geffen_in,77,167,0 shop Tool Dealer#gef 1_F_03,1750:-1,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,2241:-1 -geffen_in,77,173,0 shop Magical Item Seller#gef 1_M_WIZARD,717:-1,1601:-1,1604:-1,1607:-1,1610:-1,2232:-1,2321:-1,2332:-1 -geffen_in,171,123,4 shop Tool Dealer#gef2 1_M_WIZARD,1092:-1,1093:-1 -geffen,193,152,4 shop Pet Groomer#gef 4_F_TELEPORTER,537:-1,643:-1,10013:-1,10014:-1,554:-1,6113:-1,6114:-1,6115:-1 +geffen_in,26,178,4 trader Armor Dealer#gef 1_F_01,{ +OnInit: + sellitem Novice_Armlet; + sellitem Guard; + sellitem Mirror_Shield; + sellitem Sandals; + sellitem Hood; + sellitem Gemmed_Sallet; + sellitem Cotton_Shirt; + sellitem Leather_Jacket; + sellitem Adventure_Suit; + sellitem Silk_Robe; + sellitem Silver_Robe; +} + +geffen_in,30,178,4 trader Weapon Dealer#gef2 1_M_01,{ +OnInit: + sellitem Arrow; + sellitem Silver_Arrow; + sellitem Sword; + sellitem Bow; + sellitem Knife; + sellitem Cutter; + sellitem Main_Gauche; + sellitem Dirk; + sellitem Dagger; + sellitem Stiletto; + sellitem Rod; + sellitem Wand; + sellitem Staff; + sellitem Arc_Wand; +} + +geffen_in,22,171,7 trader Weapon Dealer#gef 4_M_02,{ +OnInit: + sellitem Town_Sword; + sellitem Cinquedea; +} + +geffen_in,74,144,0 trader Trader#gef 1_F_01,{ +OnInit: + sellitem Scell; + sellitem Garlet; + sellitem Zargon; +} + +geffen_in,77,167,0 trader Tool Dealer#gef 1_F_03,{ +OnInit: + sellitem Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Granpa_Beard; +} + +geffen_in,77,173,0 trader Magical Item Seller#gef 1_M_WIZARD,{ +OnInit: + sellitem Blue_Gemstone; + sellitem Rod; + sellitem Wand; + sellitem Staff; + sellitem Arc_Wand; + sellitem Circlet; + sellitem Silk_Robe; + sellitem Silver_Robe; +} + +geffen_in,171,123,4 trader Tool Dealer#gef2 1_M_WIZARD,{ +OnInit: + sellitem Empty_Cylinder; + sellitem Empty_Potion; +} + +geffen,193,152,4 trader Pet Groomer#gef 4_F_TELEPORTER,{ +OnInit: + sellitem Pet_Food; + sellitem Pet_Incubator; + sellitem Backpack; + sellitem Rocker_Glasses; + sellitem Mojji; + sellitem Vital_Flower_; + sellitem Flame_Gemstone; + sellitem Bun_; +} + //======================================================= // Gonryun //======================================================= -gonryun,147,84,5 shop Tool Dealer#gon 4_M_TWOLDMAN,1750:-1,1770:-1,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,1065:-1 -gonryun,174,101,3 shop Weapon Dealer#gon 4_M_TWBOY,1207:-1,1216:-1,1107:-1,1122:-1,1116:-1,1154:-1,1407:-1,1457:-1,1354:-1,1519:-1 -gonryun,173,84,3 shop Armor Dealer#gon 4_F_TWGIRL,2211:-1,2401:-1,2403:-1,2501:-1,2503:-1,2101:-1,2103:-1,2305:-1,2321:-1,2332:-1,2328:-1,2627:-1 +gonryun,147,84,5 trader Tool Dealer#gon 4_M_TWOLDMAN,{ +OnInit: + sellitem Arrow; + sellitem Iron_Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Booby_Trap; +} + +gonryun,174,101,3 trader Weapon Dealer#gon 4_M_TWBOY,{ +OnInit: + sellitem Main_Gauche; + sellitem Stiletto; + sellitem Blade; + sellitem Ring_Pommel_Saber; + sellitem Katana; + sellitem Bastard_Sword; + sellitem Pike; + sellitem Partizan; + sellitem Hammer; + sellitem Chain; +} + +gonryun,173,84,3 trader Armor Dealer#gon 4_F_TWGIRL,{ +OnInit: + sellitem Bandana; + sellitem Sandals; + sellitem Shoes; + sellitem Hood; + sellitem Muffler; + sellitem Guard; + sellitem Buckler; + sellitem Adventure_Suit; + sellitem Silk_Robe; + sellitem Silver_Robe; + sellitem Wooden_Mail; + sellitem Belt; +} + //======================================================= // Hugel //======================================================= -hugel,105,169,5 shop Vendor from Milk Ranch#h 4_F_01,519:-1 -hugel,77,167,3 shop Vegetable Gardener#hu 4_F_HUGRANMA,522:-1,512:-1,513:-1,515:-1,516:-1,535:-1 -hu_in01,241,368,2 shop Tool Dealer#hu 1_M_INNKEEPER,1750:-1,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,1065:-1 -hu_in01,252,368,3 shop Tool Dealer#hu2 4_F_01,717:-1,2201:-1,910:-1,528:-1 -hu_in01,100,390,3 shop Bow Dealer#hu 4_M_04,1701:-1,1707:-1,1718:-1,1714:-1 -hu_in01,94,390,3 shop Weapon Dealer#hu 4_M_HUMAN_01,1116:-1,1154:-1,1354:-1,1201:-1 -hu_in01,94,313,3 shop Armor Dealer#hu 4_M_04,2224:-1,2232:-1,2226:-1,2101:-1,2103:-1,2401:-1,2501:-1,2307:-1,2105:-1 +hugel,105,169,5 trader Vendor from Milk Ranch#h 4_F_01,{ +OnInit: + sellitem Milk; +} + +hugel,77,167,3 trader Vegetable Gardener#hu 4_F_HUGRANMA,{ +OnInit: + sellitem Fruit_Of_Mastela; + sellitem Apple; + sellitem Banana; + sellitem Carrot; + sellitem Sweet_Potato; + sellitem Pumpkin; +} + +hu_in01,241,368,2 trader Tool Dealer#hu 1_M_INNKEEPER,{ +OnInit: + sellitem Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Booby_Trap; +} + +hu_in01,252,368,3 trader Tool Dealer#hu2 4_F_01,{ +OnInit: + sellitem Blue_Gemstone; + sellitem Sunglasses; + sellitem Garlet; + sellitem Monster's_Feed; +} + +hu_in01,100,390,3 trader Bow Dealer#hu 4_M_04,{ +OnInit: + sellitem Bow; + sellitem Great_Bow; + sellitem Hunter_Bow; + sellitem Kakkung; +} + +hu_in01,94,390,3 trader Weapon Dealer#hu 4_M_HUMAN_01,{ +OnInit: + sellitem Katana; + sellitem Bastard_Sword; + sellitem Hammer; + sellitem Knife; +} + +hu_in01,94,313,3 trader Armor Dealer#hu 4_M_04,{ +OnInit: + sellitem Goggle; + sellitem Circlet; + sellitem Cap; + sellitem Guard; + sellitem Buckler; + sellitem Sandals; + sellitem Hood; + sellitem Mantle; + sellitem Shield; +} + //======================================================= // Izlude //======================================================= -izlude_in,60,127,4 shop Weapon Dealer#iz 1_F_MARIA,1750:-1,1751:-1,1701:-1,1601:-1,1201:-1,1204:-1,1207:-1,1101:-1,1104:-1,1107:-1,1116:-1,1151:-1,1154:-1,1157:-1,1160:-1,1301:-1 -izlude_in,70,127,4 shop Armor Dealer#iz 1_M_SIZ,2103:-1,2105:-1,2403:-1,2405:-1,2503:-1,2505:-1,2226:-1,2228:-1,2303:-1,2305:-1,2328:-1,2307:-1,2309:-1,2312:-1,2314:-1,2316:-1,2628:-1 +izlude_in,60,127,4 trader Weapon Dealer#iz 1_F_MARIA,{ +OnInit: + sellitem Arrow; + sellitem Silver_Arrow; + sellitem Bow; + sellitem Rod; + sellitem Knife; + sellitem Cutter; + sellitem Main_Gauche; + sellitem Sword; + sellitem Falchion; + sellitem Blade; + sellitem Katana; + sellitem Slayer; + sellitem Bastard_Sword; + sellitem Two_Hand_Sword; + sellitem Broad_Sword; + sellitem Axe; +} + +izlude_in,70,127,4 trader Armor Dealer#iz 1_M_SIZ,{ +OnInit: + sellitem Buckler; + sellitem Shield; + sellitem Shoes; + sellitem Boots; + sellitem Muffler; + sellitem Manteau; + sellitem Cap; + sellitem Helm; + sellitem Leather_Jacket; + sellitem Adventure_Suit; + sellitem Wooden_Mail; + sellitem Mantle; + sellitem Coat; + sellitem Padded_Armor; + sellitem Chain_Mail; + sellitem Plate_Armor; + sellitem Novice_Armlet; +} + //======================================================= // Jawaii //======================================================= -jawaii,186,174,3 shop Ice Cream Guy#ja 4_M_03,536:-1,536:-1,536:-1,536:-1,536:-1,536:-1,536:-1 +jawaii,186,174,3 trader Ice Cream Guy#ja 4_M_03,{ +OnInit: + sellitem Ice_Cream; + sellitem Ice_Cream; + sellitem Ice_Cream; + sellitem Ice_Cream; + sellitem Ice_Cream; + sellitem Ice_Cream; + sellitem Ice_Cream; +} + //======================================================= // Juno //======================================================= -yuno,218,97,5 shop Tool Dealer#yuno 4_M_02,1750:-1,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1 -yuno,226,107,5 shop Tool Dealer#yuno1 4_M_01,911:-1,910:-1,912:-1 -yuno,197,114,4 shop Pet Groomer#yuno 4_F_TELEPORTER,537:-1,643:-1,10013:-1,10014:-1,6115:-1,554:-1,6114:-1,6113:-1,6110:-1,6115:-1,6100:-1,6098:-1,6112:-1,6104:-1,6108:-1,6111:-1,6095:-1,6099:-1,6096:-1,6097:-1 -yuno,205,103,4 shop Mr. King's Shop#yuno 4_M_TELEPORTER,2340:-1,2341:-1,2411:-1,2222:-1,2230:-1,1721:-1 -yuno,163,187,5 shop Magical Item Seller#yuno 4_F_01,717:-1,1601:-1,1604:-1,1607:-1,1610:-1,2232:-1,2321:-1,2332:-1 -yuno_in01,25,34,5 shop Tool Dealer#yuno2 4_M_01,1750:-1,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1 -yuno_in01,103,35,2 shop Weapon Dealer#yuno 1_M_03,1750:-1,1751:-1,1101:-1,1701:-1,1201:-1,1204:-1,1207:-1,1210:-1,1213:-1,1216:-1,1601:-1,1604:-1,1607:-1,1610:-1 -yuno_in01,112,26,4 shop Armor Dealer#yuno 4W_F_01,2628:-1,2101:-1,2107:-1,2401:-1,2501:-1,2230:-1,2301:-1,2303:-1,2305:-1,2321:-1,2332:-1 -yuno_in03,176,22,3 shop Scroll Merchant#yuno03 4_M_ORIENT02,7433:-1 //Temp shop in Yuno that sells Blank Scrolls +yuno,218,97,5 trader Tool Dealer#yuno 4_M_02,{ +OnInit: + sellitem Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; +} + +yuno,226,107,5 trader Tool Dealer#yuno1 4_M_01,{ +OnInit: + sellitem Scell; + sellitem Garlet; + sellitem Zargon; +} + +yuno,197,114,4 trader Pet Groomer#yuno 4_F_TELEPORTER,{ +OnInit: + sellitem Pet_Food; + sellitem Pet_Incubator; + sellitem Backpack; + sellitem Rocker_Glasses; + sellitem Bun_; + sellitem Mojji; + sellitem Flame_Gemstone; + sellitem Vital_Flower_; + sellitem Vital_Flower; + sellitem Bun_; + sellitem Damp_Darkness; + sellitem Small_Snow_Flower; + sellitem Fresh_Plant; + sellitem Big_Cell; + sellitem Apple_Pudding; + sellitem Mystic_Stone; + sellitem Flavored_Alcohol; + sellitem Grilled_Rice_Cake; + sellitem Fish_With_Blue_Back; + sellitem Pumpkin_Pie_; +} + +yuno,205,103,4 trader Mr. King's Shop#yuno 4_M_TELEPORTER,{ +OnInit: + sellitem Novice_Breast; + sellitem Full_Plate_Armor; + sellitem Grave; + sellitem Turban; + sellitem Gemmed_Sallet; + sellitem Repeting_CrossBow; +} + +yuno,163,187,5 trader Magical Item Seller#yuno 4_F_01,{ +OnInit: + sellitem Blue_Gemstone; + sellitem Rod; + sellitem Wand; + sellitem Staff; + sellitem Arc_Wand; + sellitem Circlet; + sellitem Silk_Robe; + sellitem Silver_Robe; +} + +yuno_in01,25,34,5 trader Tool Dealer#yuno2 4_M_01,{ +OnInit: + sellitem Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; +} + +yuno_in01,103,35,2 trader Weapon Dealer#yuno 1_M_03,{ +OnInit: + sellitem Arrow; + sellitem Silver_Arrow; + sellitem Sword; + sellitem Bow; + sellitem Knife; + sellitem Cutter; + sellitem Main_Gauche; + sellitem Dirk; + sellitem Dagger; + sellitem Stiletto; + sellitem Rod; + sellitem Wand; + sellitem Staff; + sellitem Arc_Wand; +} + +yuno_in01,112,26,4 trader Armor Dealer#yuno 4W_F_01,{ +OnInit: + sellitem Novice_Armlet; + sellitem Guard; + sellitem Mirror_Shield; + sellitem Sandals; + sellitem Hood; + sellitem Gemmed_Sallet; + sellitem Cotton_Shirt; + sellitem Leather_Jacket; + sellitem Adventure_Suit; + sellitem Silk_Robe; + sellitem Silver_Robe; +} + +yuno_in03,176,22,3 trader Scroll Merchant#yuno03 4_M_ORIENT02,{ +OnInit: + sellitem Scroll; //Temp shop in Yuno that sells Blank Scrolls +} + //======================================================= // Lighthalzen //======================================================= -lighthalzen,69,75,5 shop Fruit Gardener#lhz 8_F,512:-1,513:-1 -lighthalzen,112,44,0 shop Flower Girl#lhz 4_F_01,712:-1,744:-1,748:-1 -lighthalzen,124,129,0 shop Vegetable Gardener#lhz 4_F_02,515:-1,516:-1,535:-1 -lighthalzen,220,122,3 shop Vendor from Milk Ranch#l 4_F_01,519:-1 -lighthalzen,222,191,4 shop Pet Groomer#lhz 4_M_TELEPORTER,537:-1,643:-1,10013:-1,10014:-1,554:-1,6113:-1,6114:-1,6115:-1 -lhz_in02,286,95,4 shop Beginner's Merchant#lhz 1_M_SIZ,5112:-1,2416:-1,2113:-1,2512:-1 -lhz_in02,271,99,5 shop Armor Dealer#lhz 4_M_REPAIR,2101:-1,2103:-1,2403:-1,2405:-1,2503:-1,2321:-1,2314:-1,2309:-1,2335:-1,2628:-1 -lhz_in02,276,99,4 shop Weapon Dealer#lhz 4_M_REPAIR,1201:-1,1207:-1,1216:-1,1107:-1,1122:-1,1116:-1,1154:-1,1407:-1,1457:-1,1354:-1,1519:-1,13003:-1 -lhz_in02,273,35,4 shop Wand Dealer#lhz 4_M_EINMAN2,1601:-1,1604:-1,1607:-1,1617:-1,1619:-1 -lhz_in02,105,21,3 shop Jeweler#lhz 4_F_02,721:-1,723:-1,726:-1,728:-1,729:-1,730:-1,2613:-1 -lhz_in02,17,220,5 shop Vegetable Gardener#lhz2 4_F_02,515:-1,516:-1,535:-1 -lhz_in02,21,220,5 shop Fruit Gardener#lhz2 8_F,512:-1,513:-1 -lhz_in02,32,219,5 shop Butcher#lhz 1_M_JOBGUIDER,517:-1 -lhz_in02,38,145,5 shop Gift Merchant#lhz 4_F_02,734:-1,735:-1,736:-1,737:-1,746:-1 -lhz_in02,47,148,3 shop Wedding Shop Dealer#lhz 1_F_LIBRARYGIRL,744:-1,745:-1,2338:-1,2206:-1,7170:-1 -lhz_in02,31,145,4 shop Tool Dealer#lhz 4_F_01,611:-1,503:-1,504:-1,506:-1,657:-1,656:-1,601:-1,602:-1,1065:-1,610:-1,1770:-1 -lhz_in02,85,216,5 shop Doll Supplier#lhz 4_F_LGTGIRL,740:-1,741:-1,742:-1 -lhz_in02,87,208,3 shop Toy Supplier#lhz 4_M_PIERROT,2243:-1,2212:-1,2242:-1,2241:-1 -lhz_in03,239,106,5 shop Tool Dealer#lhz2 4_F_EINWOMAN,501:-1,502:-1,506:-1,645:-1,656:-1,601:-1,602:-1,1065:-1,611:-1 -lhz_in03,258,101,3 shop Arrow Merchant#lhz 4_M_EINMAN,1750:-1,1770:-1,1752:-1,1751:-1 -lhz_in03,249,24,4 shop Merchant#lhz 4_M_EINMAN,911:-1,910:-1,912:-1,528:-1 +lighthalzen,69,75,5 trader Fruit Gardener#lhz 8_F,{ +OnInit: + sellitem Apple; + sellitem Banana; +} + +lighthalzen,112,44,0 trader Flower Girl#lhz 4_F_01,{ +OnInit: + sellitem Flower; + sellitem Bunch_Of_Flowers; + sellitem Witherless_Rose; +} + +lighthalzen,124,129,0 trader Vegetable Gardener#lhz 4_F_02,{ +OnInit: + sellitem Carrot; + sellitem Sweet_Potato; + sellitem Pumpkin; +} + +lighthalzen,220,122,3 trader Vendor from Milk Ranch#l 4_F_01,{ +OnInit: + sellitem Milk; +} + +lighthalzen,222,191,4 trader Pet Groomer#lhz 4_M_TELEPORTER,{ +OnInit: + sellitem Pet_Food; + sellitem Pet_Incubator; + sellitem Backpack; + sellitem Rocker_Glasses; + sellitem Mojji; + sellitem Vital_Flower_; + sellitem Flame_Gemstone; + sellitem Bun_; +} + +lhz_in02,286,95,4 trader Beginner's Merchant#lhz 1_M_SIZ,{ +OnInit: + sellitem Super_Novice_Hat; + sellitem Novice_Shoes; + sellitem Novice_Shield; + sellitem Novice_Manteau; +} + +lhz_in02,271,99,5 trader Armor Dealer#lhz 4_M_REPAIR,{ +OnInit: + sellitem Guard; + sellitem Buckler; + sellitem Shoes; + sellitem Boots; + sellitem Muffler; + sellitem Silk_Robe; + sellitem Chain_Mail; + sellitem Coat; + sellitem Thief_Clothes; + sellitem Novice_Armlet; +} + +lhz_in02,276,99,4 trader Weapon Dealer#lhz 4_M_REPAIR,{ +OnInit: + sellitem Knife; + sellitem Main_Gauche; + sellitem Stiletto; + sellitem Blade; + sellitem Ring_Pommel_Saber; + sellitem Katana; + sellitem Bastard_Sword; + sellitem Pike; + sellitem Partizan; + sellitem Hammer; + sellitem Chain; + sellitem Coward; +} + +lhz_in02,273,35,4 trader Wand Dealer#lhz 4_M_EINMAN2,{ +OnInit: + sellitem Rod; + sellitem Wand; + sellitem Staff; + sellitem Survival_Rod; + sellitem Survival_Rod2; +} + +lhz_in02,105,21,3 trader Jeweler#lhz 4_F_02,{ +OnInit: + sellitem Azure_Jewel; + sellitem Cardinal_Jewel; + sellitem Blue_Jewel; + sellitem Golden_Jewel; + sellitem Bluish_Green_Jewel; + sellitem Crystal_Jewel; + sellitem Diamond_Ring; +} + +lhz_in02,17,220,5 trader Vegetable Gardener#lhz2 4_F_02,{ +OnInit: + sellitem Carrot; + sellitem Sweet_Potato; + sellitem Pumpkin; +} + +lhz_in02,21,220,5 trader Fruit Gardener#lhz2 8_F,{ +OnInit: + sellitem Apple; + sellitem Banana; +} + +lhz_in02,32,219,5 trader Butcher#lhz 1_M_JOBGUIDER,{ +OnInit: + sellitem Meat; +} + +lhz_in02,38,145,5 trader Gift Merchant#lhz 4_F_02,{ +OnInit: + sellitem Red_Frame; + sellitem Blue_Porcelain; + sellitem White_Platter; + sellitem Black_Ladle; + sellitem Glass_Bead; +} + +lhz_in02,47,148,3 trader Wedding Shop Dealer#lhz 1_F_LIBRARYGIRL,{ +OnInit: + sellitem Bunch_Of_Flowers; + sellitem Wedding_Bouquet; + sellitem Wedding_Dress; + sellitem Wedding_Veil; + sellitem Tuxedo; +} + +lhz_in02,31,145,4 trader Tool Dealer#lhz 4_F_01,{ +OnInit: + sellitem Spectacles; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Berserk_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Booby_Trap; + sellitem Leaf_Of_Yggdrasil; + sellitem Iron_Arrow; +} + +lhz_in02,85,216,5 trader Doll Supplier#lhz 4_F_LGTGIRL,{ +OnInit: + sellitem Stuffed_Doll; + sellitem Poring_Doll; + sellitem Chonchon_Doll; +} + +lhz_in02,87,208,3 trader Toy Supplier#lhz 4_M_PIERROT,{ +OnInit: + sellitem Spinning_Eyes; + sellitem Eye_Bandage; + sellitem Luxury_Sunglasses; + sellitem Granpa_Beard; +} + +lhz_in03,239,106,5 trader Tool Dealer#lhz2 4_F_EINWOMAN,{ +OnInit: + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Booby_Trap; + sellitem Spectacles; +} + +lhz_in03,258,101,3 trader Arrow Merchant#lhz 4_M_EINMAN,{ +OnInit: + sellitem Arrow; + sellitem Iron_Arrow; + sellitem Fire_Arrow; + sellitem Silver_Arrow; +} + +lhz_in03,249,24,4 trader Merchant#lhz 4_M_EINMAN,{ +OnInit: + sellitem Scell; + sellitem Garlet; + sellitem Zargon; + sellitem Monster's_Feed; +} + //======================================================= // Louyang //======================================================= -lou_in02,121,182,5 shop Armor Dealer#lou 4_F_CHNWOMAN,2211:-1,2401:-1,2403:-1,2501:-1,2503:-1,2101:-1,2103:-1,2305:-1,2321:-1,2332:-1,2328:-1,2627:-1 -lou_in02,130,182,5 shop Weapon Dealer#lou 4_M_CHNMAN,1207:-1,1216:-1,1107:-1,1122:-1,1116:-1,1154:-1,1407:-1,1457:-1,1354:-1,1519:-1 -lou_in02,239,176,5 shop Tool Dealer#lou 4_F_CHNWOMAN,1750:-1,1770:-1,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,1065:-1 +lou_in02,121,182,5 trader Armor Dealer#lou 4_F_CHNWOMAN,{ +OnInit: + sellitem Bandana; + sellitem Sandals; + sellitem Shoes; + sellitem Hood; + sellitem Muffler; + sellitem Guard; + sellitem Buckler; + sellitem Adventure_Suit; + sellitem Silk_Robe; + sellitem Silver_Robe; + sellitem Wooden_Mail; + sellitem Belt; +} + +lou_in02,130,182,5 trader Weapon Dealer#lou 4_M_CHNMAN,{ +OnInit: + sellitem Main_Gauche; + sellitem Stiletto; + sellitem Blade; + sellitem Ring_Pommel_Saber; + sellitem Katana; + sellitem Bastard_Sword; + sellitem Pike; + sellitem Partizan; + sellitem Hammer; + sellitem Chain; +} + +lou_in02,239,176,5 trader Tool Dealer#lou 4_F_CHNWOMAN,{ +OnInit: + sellitem Arrow; + sellitem Iron_Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Booby_Trap; +} + //======================================================= // Lutie //======================================================= -xmas_in,40,38,5 shop Tool Dealer#xmas 4_M_01,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,611:-1,610:-1 -xmas_in,168,104,4 shop Armor Dealer#xmas 4W_F_01,2228:-1,2103:-1,2105:-1,2307:-1,2309:-1,2312:-1,2314:-1,2316:-1,2505:-1,2405:-1 -xmas_in,169,34,2 shop Gift Seller#xmas 4_F_GON,2612:-1,744:-1,748:-1,736:-1,746:-1,740:-1,2613:-1 -xmas_in,174,98,2 shop Weapon Dealer#xmas 1_M_03,1201:-1,1204:-1,1207:-1,1210:-1,1213:-1,1216:-1,1219:-1,1222:-1 +xmas_in,40,38,5 trader Tool Dealer#xmas 4_M_01,{ +OnInit: + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Spectacles; + sellitem Leaf_Of_Yggdrasil; +} + +xmas_in,168,104,4 trader Armor Dealer#xmas 4W_F_01,{ +OnInit: + sellitem Helm; + sellitem Buckler; + sellitem Shield; + sellitem Mantle; + sellitem Coat; + sellitem Padded_Armor; + sellitem Chain_Mail; + sellitem Plate_Armor; + sellitem Manteau; + sellitem Boots; +} + +xmas_in,169,34,2 trader Gift Seller#xmas 4_F_GON,{ +OnInit: + sellitem Flower_Ring; + sellitem Bunch_Of_Flowers; + sellitem Witherless_Rose; + sellitem White_Platter; + sellitem Glass_Bead; + sellitem Stuffed_Doll; + sellitem Diamond_Ring; +} + +xmas_in,174,98,2 trader Weapon Dealer#xmas 1_M_03,{ +OnInit: + sellitem Knife; + sellitem Cutter; + sellitem Main_Gauche; + sellitem Dirk; + sellitem Dagger; + sellitem Stiletto; + sellitem Gladius; + sellitem Damascus; +} + //======================================================= // Morroc - Post Ep. 12.1 //======================================================= -in_moc_16,22,20,7 shop Sepulchral Merchant#moc 4_M_MASKMAN,1771:-1 -moc_ruins,91,128,4 shop Tool Dealer#moc1 4_F_04,1750:-1,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,1065:-1 -moc_ruins,114,63,6 shop Tool Dealer#moc2 4W_M_03,1750:-1,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,1065:-1,2242:-1 -moc_ruins,93,53,2 shop Item Collector#moc1 4_M_03,911:-1,528:-1,919:-1,925:-1 -moc_ruins,81,113,0 shop Item Collector#moc2 4_M_03,911:-1,528:-1,919:-1,925:-1 -moc_ruins,110,105,2 shop Jeweler#moc1 8_F,721:-1,723:-1,726:-1,728:-1,729:-1 -moc_ruins,52,85,6 shop Jeweler#moc2 4W_M_03,730:-1,2613:-1 -moc_ruins,113,126,4 shop Trader#moc1 4W_M_03,747:-1 -moc_ruins,131,138,0 shop Trader#moc2 4_F_04,748:-1 -moc_ruins,71,139,5 shop Trader#moc3 4_F_04,2612:-1 -moc_ruins,125,135,6 shop Trader#moc4 4_M_ORIENT02,2609:-1,1516:-1,1522:-1 -moc_ruins,87,109,0 shop Butcher#moc 1_M_MERCHANT,517:-1 -moc_ruins,90,149,6 shop Trader#moc5 4W_M_03,513:-1,513:-1,513:-1,513:-1,513:-1,513:-1 -moc_ruins,118,170,4 shop Pet Groomer#moc 4_M_TELEPORTER,537:-1,643:-1,10013:-1,10014:-1,554:-1,6113:-1,6114:-1,6115:-1 -morocc_in,141,67,0 shop Weapon Dealer#moc1 1_M_MERCHANT,1750:-1,1751:-1,1701:-1,1601:-1,1201:-1,1204:-1,1207:-1,1210:-1,1213:-1,1216:-1,1219:-1,1222:-1,1250:-1,1252:-1,1254:-1 -morocc_in,141,60,0 shop Armor Dealer#moc 1_M_MERCHANT,2101:-1,2103:-1,2401:-1,2403:-1,2405:-1,2501:-1,2503:-1,2218:-1,2301:-1,2303:-1,2305:-1,2321:-1,2328:-1,2332:-1,2307:-1,2309:-1,2335:-1,2628:-1 -morocc_in,132,57,0 shop Weapon Dealer#moc2 4W_M_03,1146:-1,1245:-1 +in_moc_16,22,20,7 trader Sepulchral Merchant#moc 4_M_MASKMAN,{ +OnInit: + sellitem Venom_Knife; +} + +moc_ruins,91,128,4 trader Tool Dealer#moc1 4_F_04,{ +OnInit: + sellitem Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Booby_Trap; +} + +moc_ruins,114,63,6 trader Tool Dealer#moc2 4W_M_03,{ +OnInit: + sellitem Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Booby_Trap; + sellitem Luxury_Sunglasses; +} + +moc_ruins,93,53,2 trader Item Collector#moc1 4_M_03,{ +OnInit: + sellitem Scell; + sellitem Monster's_Feed; + sellitem Animal's_Skin; + sellitem Bill_Of_Birds; +} + +moc_ruins,81,113,0 trader Item Collector#moc2 4_M_03,{ +OnInit: + sellitem Scell; + sellitem Monster's_Feed; + sellitem Animal's_Skin; + sellitem Bill_Of_Birds; +} + +moc_ruins,110,105,2 trader Jeweler#moc1 8_F,{ +OnInit: + sellitem Azure_Jewel; + sellitem Cardinal_Jewel; + sellitem Blue_Jewel; + sellitem Golden_Jewel; + sellitem Bluish_Green_Jewel; +} + +moc_ruins,52,85,6 trader Jeweler#moc2 4W_M_03,{ +OnInit: + sellitem Crystal_Jewel; + sellitem Diamond_Ring; +} + +moc_ruins,113,126,4 trader Trader#moc1 4W_M_03,{ +OnInit: + sellitem Crystal_Mirror; +} + +moc_ruins,131,138,0 trader Trader#moc2 4_F_04,{ +OnInit: + sellitem Witherless_Rose; +} + +moc_ruins,71,139,5 trader Trader#moc3 4_F_04,{ +OnInit: + sellitem Flower_Ring; +} + +moc_ruins,125,135,6 trader Trader#moc4 4_M_ORIENT02,{ +OnInit: + sellitem Skul_Ring; + sellitem Sword_Mace; + sellitem Stunner; +} + +moc_ruins,87,109,0 trader Butcher#moc 1_M_MERCHANT,{ +OnInit: + sellitem Meat; +} + +moc_ruins,90,149,6 trader Trader#moc5 4W_M_03,{ +OnInit: + sellitem Banana; + sellitem Banana; + sellitem Banana; + sellitem Banana; + sellitem Banana; + sellitem Banana; +} + +moc_ruins,118,170,4 trader Pet Groomer#moc 4_M_TELEPORTER,{ +OnInit: + sellitem Pet_Food; + sellitem Pet_Incubator; + sellitem Backpack; + sellitem Rocker_Glasses; + sellitem Mojji; + sellitem Vital_Flower_; + sellitem Flame_Gemstone; + sellitem Bun_; +} + +morocc_in,141,67,0 trader Weapon Dealer#moc1 1_M_MERCHANT,{ +OnInit: + sellitem Arrow; + sellitem Silver_Arrow; + sellitem Bow; + sellitem Rod; + sellitem Knife; + sellitem Cutter; + sellitem Main_Gauche; + sellitem Dirk; + sellitem Dagger; + sellitem Stiletto; + sellitem Gladius; + sellitem Damascus; + sellitem Jur; + sellitem Katar; + sellitem Jamadhar; +} + +morocc_in,141,60,0 trader Armor Dealer#moc 1_M_MERCHANT,{ +OnInit: + sellitem Guard; + sellitem Buckler; + sellitem Sandals; + sellitem Shoes; + sellitem Boots; + sellitem Hood; + sellitem Muffler; + sellitem Flu_Mask; + sellitem Cotton_Shirt; + sellitem Leather_Jacket; + sellitem Adventure_Suit; + sellitem Silk_Robe; + sellitem Wooden_Mail; + sellitem Silver_Robe; + sellitem Mantle; + sellitem Coat; + sellitem Thief_Clothes; + sellitem Novice_Armlet; +} + +morocc_in,132,57,0 trader Weapon Dealer#moc2 4W_M_03,{ +OnInit: + sellitem Town_Sword; + sellitem Cinquedea; +} + //======================================================= // Moscovia //======================================================= -mosk_in,21,254,5 shop Tool Dealer#mosk 4_M_RUSMAN2,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,1065:-1,1750:-1 -mosk_in,31,180,3 shop Weapon Dealer#mosk 4_M_RUSMAN2,1207:-1,1216:-1,1107:-1,1122:-1,1116:-1,1154:-1,1407:-1,1457:-1,1354:-1,1519:-1 -mosk_in,79,178,1 shop Armor Dealer#mosk 4_F_RUSWOMAN3,2211:-1,2401:-1,2403:-1,2501:-1,2503:-1,2101:-1,2103:-1,2305:-1,2321:-1,2332:-1,2328:-1,2627:-1 -moscovia,152,71,4 shop Fruit Gardener#mosk 4_M_RUSMAN2,512:-1,513:-1,515:-1,516:-1 -moscovia,199,110,3 shop Vendor from Milk Ranch#m 4_F_RUSWOMAN1,519:-1 +mosk_in,21,254,5 trader Tool Dealer#mosk 4_M_RUSMAN2,{ +OnInit: + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Booby_Trap; + sellitem Arrow; +} + +mosk_in,31,180,3 trader Weapon Dealer#mosk 4_M_RUSMAN2,{ +OnInit: + sellitem Main_Gauche; + sellitem Stiletto; + sellitem Blade; + sellitem Ring_Pommel_Saber; + sellitem Katana; + sellitem Bastard_Sword; + sellitem Pike; + sellitem Partizan; + sellitem Hammer; + sellitem Chain; +} + +mosk_in,79,178,1 trader Armor Dealer#mosk 4_F_RUSWOMAN3,{ +OnInit: + sellitem Bandana; + sellitem Sandals; + sellitem Shoes; + sellitem Hood; + sellitem Muffler; + sellitem Guard; + sellitem Buckler; + sellitem Adventure_Suit; + sellitem Silk_Robe; + sellitem Silver_Robe; + sellitem Wooden_Mail; + sellitem Belt; +} + +moscovia,152,71,4 trader Fruit Gardener#mosk 4_M_RUSMAN2,{ +OnInit: + sellitem Apple; + sellitem Banana; + sellitem Carrot; + sellitem Sweet_Potato; +} + +moscovia,199,110,3 trader Vendor from Milk Ranch#m 4_F_RUSWOMAN1,{ +OnInit: + sellitem Milk; +} + //======================================================= // Niflheim //======================================================= -nif_in,37,93,1 shop Axe Dealer#nif 4_NFCOFFIN,1301:-1,1351:-1,1354:-1,1357:-1,1360:-1 -nif_in,37,84,1 shop Armor Dealer#nif 4_NFCOFFIN,2501:-1,2501:-1,2503:-1,2503:-1,2505:-1,2505:-1 -nif_in,145,23,1 shop Tool Dealer#nif 4_NFCOFFIN,535:-1,1062:-1,902:-1,7106:-1,537:-1,7154:-1,1052:-1,934:-1 +nif_in,37,93,1 trader Axe Dealer#nif 4_NFCOFFIN,{ +OnInit: + sellitem Axe; + sellitem Battle_Axe; + sellitem Hammer; + sellitem Buster; + sellitem Two_Handed_Axe; +} + +nif_in,37,84,1 trader Armor Dealer#nif 4_NFCOFFIN,{ +OnInit: + sellitem Hood; + sellitem Hood; + sellitem Muffler; + sellitem Muffler; + sellitem Manteau; + sellitem Manteau; +} + +nif_in,145,23,1 trader Tool Dealer#nif 4_NFCOFFIN,{ +OnInit: + sellitem Pumpkin; + sellitem Pumpkin_Head; + sellitem Tree_Root; + sellitem Goat's_Horn; + sellitem Pet_Food; + sellitem Poison_Powder; + sellitem Single_Cell; + sellitem Mementos; +} + //======================================================= // Payon //======================================================= -payon_in01,15,119,0 shop Weapon Dealer#pay 1_F_ORIENT_03,1750:-1,1751:-1,1101:-1,1104:-1,1107:-1,1201:-1,1204:-1,1207:-1,1601:-1,1701:-1,1704:-1,1707:-1,1710:-1,1713:-1,1714:-1,1718:-1 -payon_in01,5,129,7 shop Weapon Dealer#pay2 4_F_KID2,1146:-1,1245:-1 -payon_in01,7,119,2 shop Armor Dealer#pay 1_F_ORIENT_02,2401:-1,2403:-1,2405:-1,2501:-1,2503:-1,2505:-1,2208:-1,2211:-1,2212:-1,2301:-1,2303:-1,2305:-1,2321:-1,2328:-1,2332:-1,2307:-1,2309:-1,2330:-1,2628:-1 -payon_in01,5,49,7 shop Tool Dealer#pay 4_M_ORIENT01,1750:-1,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,1065:-1 -payon_in02,87,34,0 shop Tool Dealer#pay2 1_F_ORIENT_01,1750:-1,1751:-1,611:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,1065:-1 -payon,159,96,4 shop Tool Dealer#pay3 4_M_ORIENT01,1750:-1,501:-1,645:-1,601:-1,602:-1 -payon,177,131,4 shop Pet Groomer#pay 4_F_TELEPORTER,537:-1,643:-1,10013:-1,10014:-1,554:-1,6114:-1,6113:-1,6110:-1,6115:-1,6100:-1,6098:-1,6112:-1,6104:-1,6108:-1,6111:-1,6095:-1,6099:-1,6096:-1,6097:-1,6094:-1 +payon_in01,15,119,0 trader Weapon Dealer#pay 1_F_ORIENT_03,{ +OnInit: + sellitem Arrow; + sellitem Silver_Arrow; + sellitem Sword; + sellitem Falchion; + sellitem Blade; + sellitem Knife; + sellitem Cutter; + sellitem Main_Gauche; + sellitem Rod; + sellitem Bow; + sellitem Composite_Bow; + sellitem Great_Bow; + sellitem CrossBow; + sellitem Arbalest; + sellitem Kakkung; + sellitem Hunter_Bow; +} + +payon_in01,5,129,7 trader Weapon Dealer#pay2 4_F_KID2,{ +OnInit: + sellitem Town_Sword; + sellitem Cinquedea; +} + +payon_in01,7,119,2 trader Armor Dealer#pay 1_F_ORIENT_02,{ +OnInit: + sellitem Sandals; + sellitem Shoes; + sellitem Boots; + sellitem Hood; + sellitem Muffler; + sellitem Manteau; + sellitem Ribbon; + sellitem Bandana; + sellitem Eye_Bandage; + sellitem Cotton_Shirt; + sellitem Leather_Jacket; + sellitem Adventure_Suit; + sellitem Silk_Robe; + sellitem Wooden_Mail; + sellitem Silver_Robe; + sellitem Mantle; + sellitem Coat; + sellitem Tights; + sellitem Novice_Armlet; +} + +payon_in01,5,49,7 trader Tool Dealer#pay 4_M_ORIENT01,{ +OnInit: + sellitem Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Booby_Trap; +} + +payon_in02,87,34,0 trader Tool Dealer#pay2 1_F_ORIENT_01,{ +OnInit: + sellitem Arrow; + sellitem Silver_Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Booby_Trap; +} + +payon,159,96,4 trader Tool Dealer#pay3 4_M_ORIENT01,{ +OnInit: + sellitem Arrow; + sellitem Red_Potion; + sellitem Center_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; +} + +payon,177,131,4 trader Pet Groomer#pay 4_F_TELEPORTER,{ +OnInit: + sellitem Pet_Food; + sellitem Pet_Incubator; + sellitem Backpack; + sellitem Rocker_Glasses; + sellitem Mojji; + sellitem Flame_Gemstone; + sellitem Vital_Flower_; + sellitem Vital_Flower; + sellitem Bun_; + sellitem Damp_Darkness; + sellitem Small_Snow_Flower; + sellitem Fresh_Plant; + sellitem Big_Cell; + sellitem Apple_Pudding; + sellitem Mystic_Stone; + sellitem Flavored_Alcohol; + sellitem Grilled_Rice_Cake; + sellitem Fish_With_Blue_Back; + sellitem Pumpkin_Pie_; + sellitem Traditional_Cookie; +} + //======================================================= // Prontera //======================================================= -prontera,73,134,0 shop Vendor from Milk Ranch#p 4_F_01,519:-1 -prontera,104,49,0 shop Fruit Gardener#prt 8_F,512:-1,513:-1 -prontera,64,125,0 shop Butcher#prt 4_M_BARBER,517:-1,528:-1 -prontera,58,182,0 shop Flower Girl#prt 4W_KID,712:-1,744:-1 -prontera,113,42,0 shop Flower Lady#prt 4_F_01,712:-1,744:-1 -prontera,105,87,0 shop Gift Merchant#prt 4_F_02,734:-1,735:-1,736:-1,737:-1,746:-1 -prontera,218,211,4 shop Pet Groomer#prt 4_M_TELEPORTER,537:-1,643:-1,10013:-1,10014:-1,554:-1,6114:-1,6113:-1,6110:-1,6115:-1,6100:-1,6098:-1,6112:-1,6104:-1,6108:-1,6111:-1,6095:-1,6099:-1,6096:-1,6097:-1,6094:-1 -prontera,248,153,0 shop Doll Supplier#prt 4_M_03,740:-1,741:-1,742:-1 -prontera,48,58,0 shop Vegetable Gardener#prt 4_F_02,515:-1,516:-1,535:-1 -prt_church,108,124,4 shop Nun#prt 1_F_PRIEST,2608:-1,2216:-1,5092:-1,2323:-1,2325:-1,1501:-1,1504:-1,1507:-1,1510:-1,1513:-1,1519:-1 -prt_fild05,290,221,2 shop Tool Dealer#prt 4_M_01,1750:-1,611:-1,501:-1,502:-1,506:-1,645:-1,601:-1,602:-1 -prt_in,211,169,0 shop Wedding Shop Dealer#prt 1_F_LIBRARYGIRL,744:-1,745:-1,2338:-1,2206:-1,7170:-1 -prt_in,126,76,0 shop Tool Dealer#prt1 1_M_INNKEEPER,611:-1,1750:-1,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,1065:-1,2239:-1 -prt_in,172,130,0 shop Weapon Dealer#prt 1_M_JOBGUIDER,1750:-1,1751:-1,1701:-1,1201:-1,1204:-1,1207:-1,1601:-1,1101:-1,1104:-1,1107:-1,1110:-1,1113:-1,1122:-1,1119:-1,1123:-1,1126:-1,1129:-1,1116:-1,1301:-1 -prt_in,172,132,0 shop Armor Dealer#prt 1_M_02,2101:-1,2103:-1,2401:-1,2403:-1,2501:-1,2503:-1,2220:-1,2226:-1,2301:-1,2303:-1,2305:-1,2328:-1,2307:-1,2309:-1,2312:-1,2314:-1,2628:-1,2627:-1 -prt_in,171,140,0 shop Weapon Dealer#prt2 1_M_01,1401:-1,1404:-1,1407:-1,1451:-1,1454:-1,1457:-1,1460:-1,1463:-1,1410:-1 -prt_in,165,140,4 shop Weapon Dealer#prt3 1_F_01,1146:-1,1245:-1 -prt_monk,135,263,5 shop Weapon Dealer#prt4 4_F_JOB_BLACKSMITH,1801:-1,1803:-1,1805:-1 +prontera,73,134,0 trader Vendor from Milk Ranch#p 4_F_01,{ +OnInit: + sellitem Milk; +} + +prontera,104,49,0 trader Fruit Gardener#prt 8_F,{ +OnInit: + sellitem Apple; + sellitem Banana; +} + +prontera,64,125,0 trader Butcher#prt 4_M_BARBER,{ +OnInit: + sellitem Meat; + sellitem Monster's_Feed; +} + +prontera,58,182,0 trader Flower Girl#prt 4W_KID,{ +OnInit: + sellitem Flower; + sellitem Bunch_Of_Flowers; +} + +prontera,113,42,0 trader Flower Lady#prt 4_F_01,{ +OnInit: + sellitem Flower; + sellitem Bunch_Of_Flowers; +} + +prontera,105,87,0 trader Gift Merchant#prt 4_F_02,{ +OnInit: + sellitem Red_Frame; + sellitem Blue_Porcelain; + sellitem White_Platter; + sellitem Black_Ladle; + sellitem Glass_Bead; +} + +prontera,218,211,4 trader Pet Groomer#prt 4_M_TELEPORTER,{ +OnInit: + sellitem Pet_Food; + sellitem Pet_Incubator; + sellitem Backpack; + sellitem Rocker_Glasses; + sellitem Mojji; + sellitem Flame_Gemstone; + sellitem Vital_Flower_; + sellitem Vital_Flower; + sellitem Bun_; + sellitem Damp_Darkness; + sellitem Small_Snow_Flower; + sellitem Fresh_Plant; + sellitem Big_Cell; + sellitem Apple_Pudding; + sellitem Mystic_Stone; + sellitem Flavored_Alcohol; + sellitem Grilled_Rice_Cake; + sellitem Fish_With_Blue_Back; + sellitem Pumpkin_Pie_; + sellitem Traditional_Cookie; +} + +prontera,248,153,0 trader Doll Supplier#prt 4_M_03,{ +OnInit: + sellitem Stuffed_Doll; + sellitem Poring_Doll; + sellitem Chonchon_Doll; +} + +prontera,48,58,0 trader Vegetable Gardener#prt 4_F_02,{ +OnInit: + sellitem Carrot; + sellitem Sweet_Potato; + sellitem Pumpkin; +} + +prt_church,108,124,4 trader Nun#prt 1_F_PRIEST,{ +OnInit: + sellitem Rosary; + sellitem Biretta; + sellitem Blue_Coif; + sellitem Scapulare; + sellitem Saint_Robe; + sellitem Club; + sellitem Mace; + sellitem Smasher; + sellitem Flail; + sellitem Morning_Star; + sellitem Chain; +} + +prt_fild05,290,221,2 trader Tool Dealer#prt 4_M_01,{ +OnInit: + sellitem Arrow; + sellitem Spectacles; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; +} + +prt_in,211,169,0 trader Wedding Shop Dealer#prt 1_F_LIBRARYGIRL,{ +OnInit: + sellitem Bunch_Of_Flowers; + sellitem Wedding_Bouquet; + sellitem Wedding_Dress; + sellitem Wedding_Veil; + sellitem Tuxedo; +} + +prt_in,126,76,0 trader Tool Dealer#prt1 1_M_INNKEEPER,{ +OnInit: + sellitem Spectacles; + sellitem Arrow; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Booby_Trap; + sellitem One_Eyed_Glass; +} + +prt_in,172,130,0 trader Weapon Dealer#prt 1_M_JOBGUIDER,{ +OnInit: + sellitem Arrow; + sellitem Silver_Arrow; + sellitem Bow; + sellitem Knife; + sellitem Cutter; + sellitem Main_Gauche; + sellitem Rod; + sellitem Sword; + sellitem Falchion; + sellitem Blade; + sellitem Lapier; + sellitem Scimiter; + sellitem Ring_Pommel_Saber; + sellitem Tsurugi; + sellitem Haedonggum; + sellitem Saber; + sellitem Flamberge; + sellitem Katana; + sellitem Axe; +} + +prt_in,172,132,0 trader Armor Dealer#prt 1_M_02,{ +OnInit: + sellitem Guard; + sellitem Buckler; + sellitem Sandals; + sellitem Shoes; + sellitem Hood; + sellitem Muffler; + sellitem Hat; + sellitem Cap; + sellitem Cotton_Shirt; + sellitem Leather_Jacket; + sellitem Adventure_Suit; + sellitem Wooden_Mail; + sellitem Mantle; + sellitem Coat; + sellitem Padded_Armor; + sellitem Chain_Mail; + sellitem Novice_Armlet; + sellitem Belt; +} + +prt_in,171,140,0 trader Weapon Dealer#prt2 1_M_01,{ +OnInit: + sellitem Javelin; + sellitem Spear; + sellitem Pike; + sellitem Guisarme; + sellitem Glaive; + sellitem Partizan; + sellitem Trident; + sellitem Halberd; + sellitem Lance; +} + +prt_in,165,140,4 trader Weapon Dealer#prt3 1_F_01,{ +OnInit: + sellitem Town_Sword; + sellitem Cinquedea; +} + +prt_monk,135,263,5 trader Weapon Dealer#prt4 4_F_JOB_BLACKSMITH,{ +OnInit: + sellitem Waghnakh; + sellitem Knuckle_Duster; + sellitem Hora; +} + //======================================================= // Rachel //======================================================= -ra_in01,175,364,3 shop Armor Dealer#ra 4_F_SHABBY,2101:-1,2103:-1,2403:-1,2405:-1,2503:-1,2321:-1,2314:-1,2309:-1,2335:-1,2628:-1 -ra_in01,257,269,3 shop Tool Dealer#ra 4_F_SHABBY,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,611:-1,1065:-1,610:-1 -ra_in01,176,389,3 shop Weapon Dealer#ra 4_M_RACHMAN1,1201:-1,1207:-1,1216:-1,1107:-1,1122:-1,1116:-1,1154:-1,1407:-1,1457:-1,1354:-1,1519:-1,13003:-1,1601:-1,1604:-1,1607:-1 -ra_in01,254,300,3 shop Fruit Gardener#ra 4_M_RACHMAN1,512:-1,513:-1 -rachel,65,80,1 shop Vegetable Gardener#ra 4_F_SHABBY,515:-1,535:-1,516:-1 +ra_in01,175,364,3 trader Armor Dealer#ra 4_F_SHABBY,{ +OnInit: + sellitem Guard; + sellitem Buckler; + sellitem Shoes; + sellitem Boots; + sellitem Muffler; + sellitem Silk_Robe; + sellitem Chain_Mail; + sellitem Coat; + sellitem Thief_Clothes; + sellitem Novice_Armlet; +} + +ra_in01,257,269,3 trader Tool Dealer#ra 4_F_SHABBY,{ +OnInit: + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Spectacles; + sellitem Booby_Trap; + sellitem Leaf_Of_Yggdrasil; +} + +ra_in01,176,389,3 trader Weapon Dealer#ra 4_M_RACHMAN1,{ +OnInit: + sellitem Knife; + sellitem Main_Gauche; + sellitem Stiletto; + sellitem Blade; + sellitem Ring_Pommel_Saber; + sellitem Katana; + sellitem Bastard_Sword; + sellitem Pike; + sellitem Partizan; + sellitem Hammer; + sellitem Chain; + sellitem Coward; + sellitem Rod; + sellitem Wand; + sellitem Staff; +} + +ra_in01,254,300,3 trader Fruit Gardener#ra 4_M_RACHMAN1,{ +OnInit: + sellitem Apple; + sellitem Banana; +} + +rachel,65,80,1 trader Vegetable Gardener#ra 4_F_SHABBY,{ +OnInit: + sellitem Carrot; + sellitem Pumpkin; + sellitem Sweet_Potato; +} + //======================================================= // Turtle Island //======================================================= -tur_dun01,158,54,6 shop Tool Dealer#tu 4W_M_03,1750:-1,501:-1,502:-1,503:-1,504:-1,506:-1,601:-1,602:-1,645:-1,656:-1,2242:-1 +tur_dun01,158,54,6 trader Tool Dealer#tu 4W_M_03,{ +OnInit: + sellitem Arrow; + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Luxury_Sunglasses; +} + //======================================================= // Umbala //======================================================= -um_in,104,124,3 shop Tool Dealer#um 4_M_UMOLDMAN,512:-1,515:-1,535:-1,516:-1,513:-1,517:-1,528:-1,537:-1,601:-1,602:-1,645:-1,656:-1,610:-1 -um_in,160,125,3 shop Weapon Dealer#um 4_M_UMSOLDIER,1501:-1,1504:-1,1507:-1,1510:-1,1513:-1,1519:-1,1807:-1,1811:-1,1809:-1 +um_in,104,124,3 trader Tool Dealer#um 4_M_UMOLDMAN,{ +OnInit: + sellitem Apple; + sellitem Carrot; + sellitem Pumpkin; + sellitem Sweet_Potato; + sellitem Banana; + sellitem Meat; + sellitem Monster's_Feed; + sellitem Pet_Food; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Leaf_Of_Yggdrasil; +} + +um_in,160,125,3 trader Weapon Dealer#um 4_M_UMSOLDIER,{ +OnInit: + sellitem Club; + sellitem Mace; + sellitem Smasher; + sellitem Flail; + sellitem Morning_Star; + sellitem Chain; + sellitem Fist; + sellitem Finger; + sellitem Claw; +} + //======================================================= // Veins //======================================================= -ve_in,386,245,3 shop Weapon Dealer#ve 4_M_RACHMAN1,1201:-1,1207:-1,1216:-1,1107:-1,1122:-1,1116:-1,1154:-1 -ve_in,336,243,3 shop Weapon Dealer#ve2 4_M_RACHMAN1,1407:-1,1457:-1,1354:-1,1519:-1,13003:-1 -ve_in,374,230,3 shop Armor Dealer#ve 4_F_SHABBY,2101:-1,2103:-1,2403:-1,2405:-1,2503:-1,2321:-1,2314:-1,2309:-1,2335:-1,2628:-1 -ve_in,243,303,5 shop Tool Dealer#ve 4_M_DESERT,501:-1,502:-1,503:-1,504:-1,506:-1,645:-1,656:-1,601:-1,602:-1,611:-1,1065:-1,610:-1 -ve_in,253,304,5 shop Fruit Gardener#ve 4_F_DST_CHILD,512:-1,513:-1 -ve_in,252,313,0 shop Magical Item Seller#ve 4_F_DST_GRAND,717:-1,1601:-1,1604:-1,1607:-1,1610:-1,2232:-1,2321:-1,2332:-1 +ve_in,386,245,3 trader Weapon Dealer#ve 4_M_RACHMAN1,{ +OnInit: + sellitem Knife; + sellitem Main_Gauche; + sellitem Stiletto; + sellitem Blade; + sellitem Ring_Pommel_Saber; + sellitem Katana; + sellitem Bastard_Sword; +} + +ve_in,336,243,3 trader Weapon Dealer#ve2 4_M_RACHMAN1,{ +OnInit: + sellitem Pike; + sellitem Partizan; + sellitem Hammer; + sellitem Chain; + sellitem Coward; +} + +ve_in,374,230,3 trader Armor Dealer#ve 4_F_SHABBY,{ +OnInit: + sellitem Guard; + sellitem Buckler; + sellitem Shoes; + sellitem Boots; + sellitem Muffler; + sellitem Silk_Robe; + sellitem Chain_Mail; + sellitem Coat; + sellitem Thief_Clothes; + sellitem Novice_Armlet; +} + +ve_in,243,303,5 trader Tool Dealer#ve 4_M_DESERT,{ +OnInit: + sellitem Red_Potion; + sellitem Orange_Potion; + sellitem Yellow_Potion; + sellitem White_Potion; + sellitem Green_Potion; + sellitem Center_Potion; + sellitem Awakening_Potion; + sellitem Wing_Of_Fly; + sellitem Wing_Of_Butterfly; + sellitem Spectacles; + sellitem Booby_Trap; + sellitem Leaf_Of_Yggdrasil; +} + +ve_in,253,304,5 trader Fruit Gardener#ve 4_F_DST_CHILD,{ +OnInit: + sellitem Apple; + sellitem Banana; +} + +ve_in,252,313,0 trader Magical Item Seller#ve 4_F_DST_GRAND,{ +OnInit: + sellitem Blue_Gemstone; + sellitem Rod; + sellitem Wand; + sellitem Staff; + sellitem Arc_Wand; + sellitem Circlet; + sellitem Silk_Robe; + sellitem Silver_Robe; +} + //======================================================= // Cooking Addition //======================================================= -prontera,156,212,1 shop Chef Assistant#prt 8_F_GIRL,7454:-1,7456:-1,7482:-1,580:-1 -payon,206,119,5 shop Chef Assistant#pay 4_M_ORIENT02,7455:-1 -moc_ruins,115,123,5 shop Chef Assistant#moc 4_M_04,7455:-1,7453:-1,7454:-1,7456:-1,7452:-1 -geffen,196,111,3 shop Chef Assistant#gef 4_M_03,7482:-1 -alberta,167,135,5 shop Chef Assistant#alb 4_M_05,579:-1 -aldebaran,165,107,2 shop Chef Assistant#alde 4W_M_01,7456:-1,7452:-1,580:-1 -comodo,225,164,3 shop Chef Assistant#cmd 4_M_01,7455:-1,7453:-1,7454:-1,579:-1 -umbala,102,154,3 shop Chef Assistant#um 4_M_01,7456:-1,577:-1 -yuno,130,173,3 shop Chef Assistant#yuno 4_M_01,7457:-1,7482:-1 -einbroch,224,207,5 shop Chef Assistant#ein 4_M_01,7457:-1 -lighthalzen,126,126,3 shop Chef Assistant#lhz 4_M_01,7456:-1,7452:-1 -amatsu,206,150,3 shop Chef Assistant#ama 4_M_01,7453:-1,579:-1 -louyang,256,123,5 shop Chef Assistant#lou 4_M_CHNCOOK,7454:-1,577:-1 -gonryun,147,101,5 shop Chef Assistant#gon 4_M_01,7452:-1,580:-1 -ayothaya,203,178,3 shop Chef Assistant#ayo 4_M_01,7455:-1,577:-1 -xmas,152,137,5 shop Chef Assistant#xmas 4_M_01,7457:-1,577:-1 -niflheim,209,180,5 shop Chef Assistant#nif 4_M_01,581:-1 +prontera,156,212,1 trader Chef Assistant#prt 8_F_GIRL,{ +OnInit: + sellitem Plain_Sauce; + sellitem Red_Spice; + sellitem Pot; + sellitem Bread; +} + +payon,206,119,5 trader Chef Assistant#pay 4_M_ORIENT02,{ +OnInit: + sellitem Hot_Sauce; +} + +moc_ruins,115,123,5 trader Chef Assistant#moc 4_M_04,{ +OnInit: + sellitem Hot_Sauce; + sellitem Sweet_Sauce; + sellitem Plain_Sauce; + sellitem Red_Spice; + sellitem Yellow_Spice; +} + +geffen,196,111,3 trader Chef Assistant#gef 4_M_03,{ +OnInit: + sellitem Pot; +} + +alberta,167,135,5 trader Chef Assistant#alb 4_M_05,{ +OnInit: + sellitem Delicious_Fish; +} + +aldebaran,165,107,2 trader Chef Assistant#alde 4W_M_01,{ +OnInit: + sellitem Red_Spice; + sellitem Yellow_Spice; + sellitem Bread; +} + +comodo,225,164,3 trader Chef Assistant#cmd 4_M_01,{ +OnInit: + sellitem Hot_Sauce; + sellitem Sweet_Sauce; + sellitem Plain_Sauce; + sellitem Delicious_Fish; +} + +umbala,102,154,3 trader Chef Assistant#um 4_M_01,{ +OnInit: + sellitem Red_Spice; + sellitem Grain; +} + +yuno,130,173,3 trader Chef Assistant#yuno 4_M_01,{ +OnInit: + sellitem Cooking_Oil; + sellitem Pot; +} + +einbroch,224,207,5 trader Chef Assistant#ein 4_M_01,{ +OnInit: + sellitem Cooking_Oil; +} + +lighthalzen,126,126,3 trader Chef Assistant#lhz 4_M_01,{ +OnInit: + sellitem Red_Spice; + sellitem Yellow_Spice; +} + +amatsu,206,150,3 trader Chef Assistant#ama 4_M_01,{ +OnInit: + sellitem Sweet_Sauce; + sellitem Delicious_Fish; +} + +louyang,256,123,5 trader Chef Assistant#lou 4_M_CHNCOOK,{ +OnInit: + sellitem Plain_Sauce; + sellitem Grain; +} + +gonryun,147,101,5 trader Chef Assistant#gon 4_M_01,{ +OnInit: + sellitem Yellow_Spice; + sellitem Bread; +} + +ayothaya,203,178,3 trader Chef Assistant#ayo 4_M_01,{ +OnInit: + sellitem Hot_Sauce; + sellitem Grain; +} + +xmas,152,137,5 trader Chef Assistant#xmas 4_M_01,{ +OnInit: + sellitem Cooking_Oil; + sellitem Grain; +} + +niflheim,209,180,5 trader Chef Assistant#nif 4_M_01,{ +OnInit: + sellitem Mushroom; +} + //===== Additional Comments(old): ================================= //= swapped shop titles in GONRYUN, thanks to Kashy @@ -364,4 +2240,4 @@ niflheim,209,180,5 shop Chef Assistant#nif 4_M_01,581:-1 //= 1.9a Pet Merchant -> Lighthalzen [erKURITA] //= 1.9b Added items to Chivas Regal //= 1.9c Slight update for Rachel shop: Tool Dealer -> Fruit Gardener [L0ne_W0lf] -//============================================================ +//============================================================ \ No newline at end of file diff --git a/sql-files/main.sql b/sql-files/main.sql index 60b21285d..906c329fa 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -671,6 +671,7 @@ INSERT INTO `sql_updates` (`timestamp`) VALUES (1383205740); INSERT INTO `sql_updates` (`timestamp`) VALUES (1383955424); INSERT INTO `sql_updates` (`timestamp`) VALUES (1384545461); INSERT INTO `sql_updates` (`timestamp`) VALUES (1384588175); +INSERT INTO `sql_updates` (`timestamp`) VALUES (1387844126); -- -- Table structure for table `sstatus` @@ -731,3 +732,14 @@ CREATE TABLE IF NOT EXISTS `account_data` ( PRIMARY KEY (`account_id`) ) ENGINE=MyISAM; +-- +-- Table structure for table `npc_market_data` +-- + +CREATE TABLE IF NOT EXISTS `npc_market_data` ( + `name` varchar(24) NOT NULL default '', + `itemid` int(11) unsigned NOT NULL default '0', + `amount` int(11) unsigned NOT NULL default '0', + PRIMARY KEY (`name`,`itemid`) +) ENGINE=MyISAM; + diff --git a/sql-files/upgrades/2013-12-24--00-15.sql b/sql-files/upgrades/2013-12-24--00-15.sql new file mode 100644 index 000000000..b1f8d019d --- /dev/null +++ b/sql-files/upgrades/2013-12-24--00-15.sql @@ -0,0 +1,8 @@ +#1387844126 +CREATE TABLE IF NOT EXISTS `npc_market_data` ( + `name` varchar(24) NOT NULL default '', + `itemid` int(11) unsigned NOT NULL default '0', + `amount` int(11) unsigned NOT NULL default '0', + PRIMARY KEY (`name`,`itemid`) +) ENGINE=MyISAM; +INSERT INTO `sql_updates` (`timestamp`) VALUES (1387844126); diff --git a/sql-files/upgrades/index.txt b/sql-files/upgrades/index.txt index 9b7ad20d8..0c4ac87e5 100644 --- a/sql-files/upgrades/index.txt +++ b/sql-files/upgrades/index.txt @@ -15,3 +15,4 @@ 2013-11-15--19-57.sql 2013-11-16--07-49.sql 2013-11-18--08-23.sql +2013-12-24--00-15.sql \ No newline at end of file diff --git a/src/common/mmo.h b/src/common/mmo.h index b33b01fa7..bd5da6a9f 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -48,7 +48,7 @@ // 20120307 - 2012-03-07aRagexeRE+ - 0x970 #ifndef PACKETVER -#define PACKETVER 20120418 + #define PACKETVER 20131223 #endif // PACKETVER #ifndef DISABLE_PACKETVER_RE diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 953f1a0dc..ce73319e2 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -9273,17 +9273,28 @@ ACMD(searchstore){ return true; } ACMD(costume){ - const char* names[4] = { + const char* names[] = { "Wedding", "Xmas", "Summer", "Hanbok", +#if PACKETVER >= 20131218 + "Oktoberfest", +#endif + }; + const int name2id[] = { + SC_WEDDING, + SC_XMAS, + SC_SUMMER, + SC_HANBOK, +#if PACKETVER >= 20131218 + SC_OKTOBERFEST, +#endif }; - const int name2id[4] = { SC_WEDDING, SC_XMAS, SC_SUMMER, SC_HANBOK }; - unsigned short k = 0; + unsigned short k = 0, len = ARRAYLENGTH(names); if( !message || !*message ) { - for( k = 0; k < 4; k++ ) { + for( k = 0; k < len; k++ ) { if( sd->sc.data[name2id[k]] ) { sprintf(atcmd_output,msg_txt(1473),names[k]);//Costume '%s' removed. clif->message(sd->fd,atcmd_output); @@ -9293,14 +9304,14 @@ ACMD(costume){ } clif->message(sd->fd,msg_txt(1472)); - for( k = 0; k < 4; k++ ) { + for( k = 0; k < len; k++ ) { sprintf(atcmd_output,msg_txt(1471),names[k]);//-- %s clif->message(sd->fd,atcmd_output); } return false; } - for( k = 0; k < 4; k++ ) { + for( k = 0; k < len; k++ ) { if( sd->sc.data[name2id[k]] ) { sprintf(atcmd_output,msg_txt(1470),names[k]);// You're already with a '%s' costume, type '@costume' to remove it. clif->message(sd->fd,atcmd_output); @@ -9308,11 +9319,11 @@ ACMD(costume){ } } - for( k = 0; k < 4; k++ ) { + for( k = 0; k < len; k++ ) { if( strcmpi(message,names[k]) == 0 ) break; } - if( k == 4 ) { + if( k == len ) { sprintf(atcmd_output,msg_txt(1469),message);// '%s' is not a known costume clif->message(sd->fd,atcmd_output); return false; diff --git a/src/map/clif.c b/src/map/clif.c index 6a55ad344..b442d6279 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -61,7 +61,8 @@ static struct packet_itemlist_equip itemlist_equip; static struct packet_storelist_normal storelist_normal; static struct packet_storelist_equip storelist_equip; static struct packet_viewequip_ack viewequip_list; - +static struct packet_npc_market_result_ack npcmarket_result; +static struct packet_npc_market_open npcmarket_open; //#define DUMP_UNKNOWN_PACKET //#define DUMP_INVALID_PACKET @@ -811,7 +812,7 @@ void clif_clearunit_delayed(struct block_list* bl, clr_type type, int64 tick) { void clif_get_weapon_view(struct map_session_data* sd, unsigned short *rhand, unsigned short *lhand) { - if(sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK)) { + if(sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK|OPTION_OKTOBERFEST)) { *rhand = *lhand = 0; return; } @@ -1743,29 +1744,40 @@ void clif_npcbuysell(struct map_session_data* sd, int id) /// Presents list of items, that can be bought in an NPC shop (ZC_PC_PURCHASE_ITEMLIST). /// 00c6 .W { .L .L .B .W }* -void clif_buylist(struct map_session_data *sd, struct npc_data *nd) -{ +void clif_buylist(struct map_session_data *sd, struct npc_data *nd) { + struct npc_item_list *shop = NULL; + unsigned short shop_size = 0; int fd,i,c; - + nullpo_retv(sd); nullpo_retv(nd); + if( nd->subtype == SCRIPT ) { + shop = nd->u.scr.shop->item; + shop_size = nd->u.scr.shop->items; + } else { + shop = nd->u.shop.shop_item; + shop_size = nd->u.shop.count; + } + fd = sd->fd; - WFIFOHEAD(fd, 4 + nd->u.shop.count * 11); + + WFIFOHEAD(fd, 4 + shop_size * 11); WFIFOW(fd,0) = 0xc6; c = 0; - for( i = 0; i < nd->u.shop.count; i++ ) - { - struct item_data* id = itemdb->exists(nd->u.shop.shop_item[i].nameid); - int val = nd->u.shop.shop_item[i].value; - if( id == NULL ) - continue; - WFIFOL(fd, 4+c*11) = val; - WFIFOL(fd, 8+c*11) = pc->modifybuyvalue(sd,val); - WFIFOB(fd,12+c*11) = itemtype(id->type); - WFIFOW(fd,13+c*11) = ( id->view_id > 0 ) ? id->view_id : id->nameid; - c++; + for( i = 0; i < shop_size; i++ ) { + if( shop[i].nameid ) { + struct item_data* id = itemdb->exists(shop[i].nameid); + int val = shop[i].value; + if( id == NULL ) + continue; + WFIFOL(fd, 4+c*11) = val; + WFIFOL(fd, 8+c*11) = pc->modifybuyvalue(sd,val); + WFIFOB(fd,12+c*11) = itemtype(id->type); + WFIFOW(fd,13+c*11) = ( id->view_id > 0 ) ? id->view_id : id->nameid; + c++; + } } WFIFOW(fd,2) = 4 + c*11; @@ -3170,7 +3182,7 @@ void clif_changelook(struct block_list *bl,int type,int val) case LOOK_BASE: if( !sd ) break; - if( sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK) ) + if( sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK|OPTION_OKTOBERFEST) ) vd->weapon = vd->shield = 0; if( !vd->cloth_color ) @@ -3185,6 +3197,8 @@ void clif_changelook(struct block_list *bl,int type,int val) vd->cloth_color = 0; if( sd->sc.option&OPTION_HANBOK && battle_config.hanbok_ignorepalette ) vd->cloth_color = 0; + if( sd->sc.option&OPTION_OKTOBERFEST /* TODO: config? */ ) + vd->cloth_color = 0; } break; case LOOK_HAIR: @@ -3212,6 +3226,8 @@ void clif_changelook(struct block_list *bl,int type,int val) val = 0; if( sd->sc.option&OPTION_HANBOK && battle_config.hanbok_ignorepalette ) val = 0; + if( sd->sc.option&OPTION_OKTOBERFEST /* TODO: config? */ ) + val = 0; } vd->cloth_color = val; break; @@ -9616,6 +9632,7 @@ void clif_parse_Hotkey(int fd, struct map_session_data *sd) { /// Displays cast-like progress bar (ZC_PROGRESS). /// 02f0 .L