diff --git a/conf/msg_conf/map_msg.conf b/conf/msg_conf/map_msg.conf index 48d2562fd0..e6dfbc4de1 100644 --- a/conf/msg_conf/map_msg.conf +++ b/conf/msg_conf/map_msg.conf @@ -742,8 +742,7 @@ 715: Point Shop List: '%s' 716: Your '%s' now: %d -// Item Group -717: [%s] has won [%s] from '%s' +//717: Free // @showrate 718: Personal rate information is not displayed now. diff --git a/db/packet_db.txt b/db/packet_db.txt index b355f59518..405e59b9be 100644 --- a/db/packet_db.txt +++ b/db/packet_db.txt @@ -1477,7 +1477,7 @@ packet_ver: 25 //2009-12-01aRagexeRE 0x07fc,10 -//0x07fd,-1 +0x07fd,-1,ZC_BROADCASTING_SPECIAL_ITEM_OBTAIN,0 0x07fe,26 //0x07ff,-1 diff --git a/db/pre-re/item_flag.txt b/db/pre-re/item_flag.txt index 4158de0521..4639dc22f0 100644 --- a/db/pre-re/item_flag.txt +++ b/db/pre-re/item_flag.txt @@ -2,10 +2,11 @@ // , // // : -// 1 - As Dead Branch item (will be logged at `branchlog` table and cannot be used at 'nobranch' mapflag) -// 2 - As item group container, check player's inventory and weight before consumed -// 4 - GUID Item: When this item is obtained, will generates GUID that cannot be stacked even same or stackable item -// 8 - Item will be bound item when equipped +// 1 - As Dead Branch item (will be logged at `branchlog` table and cannot be used at 'nobranch' mapflag) +// 2 - As item group container, check player's inventory and weight before consumed +// 4 - GUID Item: When this item is obtained, will generates GUID that cannot be stacked even same or stackable item +// 8 - Item will be bound item when equipped +// 16 - Special Broadcast: When item dropped by monster and player loot it, will be broadcasted! // NOTE: For removing flag by import file, use "-" to remove the flag. Example, 604,-1 will removes flag 1 from Branch_Of_Dead_Tree // Logged as Dead Branch item diff --git a/db/re/item_db.txt b/db/re/item_db.txt index 8ef3360b21..8a8b4811e7 100644 --- a/db/re/item_db.txt +++ b/db/re/item_db.txt @@ -8213,7 +8213,7 @@ 14682,Sealed_Beelzebub_Scroll,Sealed Beelzebub Scroll,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{},{},{} 14689,Sealed_Kiel-D-01_Scroll,Sealed Kiel-D-01 Scroll,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{},{},{} 14695,Costume_Enchant_Stone_Box_3,Costume Enchant Stone Box III,18,0,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem rand(6790,6792),1; getitem 4936,1; getitem 4937,1; getitem 4938,1; },{},{} -14696,Sealed_Gloom_Under_Night_Gachapon,Sealed Gloom Under Night Gachapon,18,0,,10,,,,,,,,,,,,,{ /* getitem callfunc("F_Rand",Sealed Cards Gloom Under Night, 9 weapons smelting ticket, Armor 9 smelting ticket, medium armor Shadow, Shadow Weapon Medium, costume Wings of the Kirin, costume enchant stone box); */ },{},{} +14696,Sealed_Gloom_Under_Night_Gachapon,Sealed Gloom Under Night Gachapon,18,0,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ /* getitem callfunc("F_Rand",Sealed Cards Gloom Under Night, 9 weapons smelting ticket, Armor 9 smelting ticket, medium armor Shadow, Shadow Weapon Medium, costume Wings of the Kirin, costume enchant stone box); */ },{},{} 14699,Memorial_Garuda_Lucky_Egg,Memorial Garuda Lucky Egg,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,1,,,{ getgroupitem(IG_Memorial_Garuda_Lucky_Egg); },{},{} 14701,Rune_Midgard_Imortal_Lucky_Egg,Rune Midgard Imortal Lucky Egg,18,0,,0,,,,0,,,,,,,,,{ getgroupitem(IG_Rune_Midgard_Imortal_Lucky_Egg); },{},{} 14704,Gemstone_Shadow_Box,Gemstone Shadow Box,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 24084,1; getitem 24085,1; getitem 24086,1; getitem 24087,1; getitem 24088,1; getitem 24089,1; },{},{} @@ -8232,12 +8232,12 @@ 14731,Teleport_Shadow_Box,Teleport Shadow Box,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 24138,1; getitem 24139,1; getitem 24140,1; getitem 24141,1; getitem 24142,1; getitem 24143,1; },{},{} 14732,Steal_Shadow_Box,Steal Shadow Box,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 24144,1; getitem 24145,1; getitem 24146,1; getitem 24147,1; getitem 24148,1; getitem 24149,1; },{},{} 14733,Sealed_Pharaoh_Scroll,Sealed Pharaoh Scroll,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ /*TODO: Confirm the rates*/ getitem callfunc("F_Rand",6228,6232,14726,20034,17474),1; },{},{} -14739,Sealed_General_Egnigem_Cenia_Scroll,Sealed General Egnigem Cenia Scroll,18,10,,10,,,,,,,,,,,,,{ /*TODO: Confirm the rates*/ getitem callfunc("F_Rand",4482,6228,6232,24156,19935),1; },{},{} -14740,Sealed_Vesper_Scroll,Sealed Vesper Scroll,18,10,,10,,,,,,,,,,,,,{},{},{} -14741,Midgard_Celebration_Lucky_Egg,Midgard Celebration Lucky Egg,18,0,,10,,,,0,,,,,,,,,{ getgroupitem(IG_Midgard_Celebration_Lucky_Egg); },{},{} -14753,Hero_Midgard_Egg,Hero Midgard Egg,18,0,,10,,,,0,,,,,,,,,{ getgroupitem(IG_Hero_Midgard_Egg); },{},{} -14758,Safe_To_Smelting_Scroll,Safe To Smelting Scroll,18,10,,10,,,,,,,,,,,,,{ getitem callfunc("F_Rand",6238,6239,6228,6232,24216,17474,969),1; },{},{} -14765,Limited_Edition_JOB_Battle_Manual,Limited Edition JOB Battle Manual,18,10,,10,,,,,,,,,,,,,{ sc_start SC_JEXPBOOST,3600000,35; },{},{} +14739,Sealed_General_Egnigem_Cenia_Scroll,Sealed General Egnigem Cenia Scroll,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ /*TODO: Confirm the rates*/ getitem callfunc("F_Rand",4482,6228,6232,24156,19935),1; },{},{} +14740,Sealed_Vesper_Scroll,Sealed Vesper Scroll,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{},{},{} +14741,Midgard_Celebration_Lucky_Egg,Midgard Celebration Lucky Egg,18,0,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Midgard_Celebration_Lucky_Egg); },{},{} +14753,Hero_Midgard_Egg,Hero Midgard Egg,18,0,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Hero_Midgard_Egg); },{},{} +14758,Safe_To_Smelting_Scroll,Safe To Smelting Scroll,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem callfunc("F_Rand",6238,6239,6228,6232,24216,17474,969),1; },{},{} +14765,Limited_Edition_JOB_Battle_Manual,Limited Edition JOB Battle Manual,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ sc_start SC_JEXPBOOST,3600000,35; },{},{} 14766,Limited_Power_Booster,Limited Power Booster,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ bonus_script "{ bonus bBaseAtk,30; bonus bMatk,30; bonus bAtkRate,1; bonus bMatkRate,1; bonus bHit,30; bonus bFlee,30; bonus bAspd,1; bonus bUseSPrate,-5; bonus bFixedCastrate,-30; }",1800,1,1; },{},{} // More Armors 15000,Bone_Plate,Bone Plate,4,20,,1000,,60,,1,0x000654E2,18,2,16,,85,1,0,{ bonus bStr,1; bonus bMdef,3; bonus2 bIgnoreDefRaceRate,RC_DemiHuman,10; bonus2 bIgnoreDefRaceRate,RC_Player,10; bonus2 bIgnoreDefRaceRate,RC_Brute,10; bonus3 bAutoSpellWhenHit,"NPC_WIDEBLEEDING",1,10; },{},{} @@ -9005,9 +9005,9 @@ 17490,Time_Travel_Lucky_Egg,Time Travel Lucky Egg,2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Time_Travel_Lucky_Egg); },{},{} 17491,Refinement_Ore_Box_VII,Refinement Ore Box VII,3,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 7619,5; getitem 7620,5; getitem 4482,1; },{},{} 17492,Refinement_Ore_Box_VII(10),Refinement Ore Box VII(10),3,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 7619,50; getitem 7620,50; getitem 4482,11; },{},{} -17494,Rise_Midgard_Lucky_Egg,Rise Midgard Lucky Egg,18,10,,10,,,,,,,,,,,,,{ getgroupitem(IG_Rise_Midgard_Lucky_Egg); },{},{} -17495,Lucky_Silvervine_Fruit_Box_III10,Lucky Silvervine Fruit Box III(10),18,10,,10,,,,,,,,,,,,,{ getgroupitem(IG_Lucky_Silvervine_Fruit_Box_III10); },{},{} -17496,Lucky_Silvervine_Fruit_Box_III110,Lucky Silvervine Fruit Box III(110),18,10,,10,,,,,,,,,,,,,{ getgroupitem(IG_Lucky_Silvervine_Fruit_Box_III110); },{},{} +17494,Rise_Midgard_Lucky_Egg,Rise Midgard Lucky Egg,18,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Rise_Midgard_Lucky_Egg); },{},{} +17495,Lucky_Silvervine_Fruit_Box_III10,Lucky Silvervine Fruit Box III(10),18,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Lucky_Silvervine_Fruit_Box_III10); },{},{} +17496,Lucky_Silvervine_Fruit_Box_III110,Lucky Silvervine Fruit Box III(110),18,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Lucky_Silvervine_Fruit_Box_III110); },{},{} 17498,Three_Master_Package_IV,Three Master Package IV,2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 14534,20; getitem 14535,20; getitem 12578,20; getitem 22812,1; },{},{} 17499,Three_Master_Package_IV(10),Three Master Package IV(10),2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 14534,200; getitem 14535,200; getitem 12578,200; getitem 22812,11; },{},{} 17501,Support_Package_IV,Support Package IV,2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 12208,2; getitem 12210,2; getitem 12883,2; getitem 14600,2; /*getitem Mysterious Water of Life,6;*/ if(!rand(100)) getitem 22823,1; },{},{} @@ -9021,13 +9021,13 @@ 17513,(Limited)Purified_Oridecon_Box(30),(Limited) Purified Oridecon Box(30),2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 6910,30; getitem 6635,1; },{},{} 17515,Unlimited_Box_III,Unlimited Box III,2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 12684,5; getitem 12796,10; if(!rand(30)) getitem 14758,1; },{},{} 17516,Unlimited_Box_III(10),Unlimited Box III(10),2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 12684,50; getitem 12796,100; if(!rand(30)) getitem 14758,11; },{},{} -17519,Epic_Heroes_Scroll,Epic Heroes Scroll,18,0,,10,,,,0,,,,,,,,,{ getgroupitem(IG_Epic_Heroes_Lucky_Egg); },{},{} +17519,Epic_Heroes_Scroll,Epic Heroes Scroll,18,0,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Epic_Heroes_Lucky_Egg); },{},{} 17520,Limited_Edition_Manual_Box,Limited Edition Manual Box,2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 14765,3; /*getitem (limited edition battle manual),2;*/ },{},{} 17521,Three_Master_Package_V,Three Master Package V,2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 14534,20; getitem 14535,20; /*getitem Mysterious Water of Life,20;*/ getitem 22842,1; },{},{} 17522,Three_Master_Package_V(10),Three Master Package V(10),2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 14534,200; getitem 14535,200; /*getitem Mysterious Water of Life,200;*/ getitem 22842,11; },{},{} 17524,Limited_Power_Booster_Box,Limited Power Booster Box,2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 14766,1; getitem 22873,1; },{},{} 17525,Limited_Power_Booster_Box(100),Limited Power Booster Box(100),2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 14766,100; getitem 22873,11; },{},{} -17526,Majestic_Lucky_Egg,Majestic Lucky Egg,18,0,,10,,,,0,,,,,,,,,{ getgroupitem(IG_Majestic_Lucky_Egg); },{},{} +17526,Majestic_Lucky_Egg,Majestic Lucky Egg,18,0,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Majestic_Lucky_Egg); },{},{} 17527,Actinidia_Cat_Fruit_Box(200),Actinidia Cat Fruit Box(200),2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 6909,200; getitem 12636,rand(1,5); /*TODO: Fix the 12636 amount*/},{},{} 17532,Blessing_Lucky_Egg,Blessing Lucky Egg,18,0,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Blessing_Lucky_Egg); },{},{} 17544,Smelting_Ore_Box_IX,Smelting Ore Box IX,2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ getitem 7619,5; getitem 7620,5; getitem 22888,1; },{},{} diff --git a/db/re/item_flag.txt b/db/re/item_flag.txt index 8ca9a385a2..49f2717392 100644 --- a/db/re/item_flag.txt +++ b/db/re/item_flag.txt @@ -2,10 +2,11 @@ // , // // : -// 1 - As Dead Branch item (will be logged at `branchlog` table and cannot be used at 'nobranch' mapflag) -// 2 - As item group container, check player's inventory and weight before consumed -// 4 - GUID Item: When this item is obtained, will generates GUID that cannot be stacked even same or stackable item -// 8 - Item will be bound item when equipped +// 1 - As Dead Branch item (will be logged at `branchlog` table and cannot be used at 'nobranch' mapflag) +// 2 - As item group container, check player's inventory and weight before consumed +// 4 - GUID Item: When this item is obtained, will generates GUID that cannot be stacked even same or stackable item +// 8 - Item will be bound item when equipped +// 16 - Special Broadcast: When item dropped by monster and player loot it, will be broadcasted! // NOTE: For removing flag by import file, use "-" to remove the flag. Example, 604,-1 will removes flag 1 from Branch_Of_Dead_Tree // Logged as Dead Branch item @@ -1698,3 +1699,7 @@ //17330,4 //Fashion_Costume_Box4 //17335,4 //Mysterious_Ingredient_B 22558,4 //Lucky_Bag + +// Special Broadcast +7782,16 //Gold_Key77 +7783,16 //Silver_Key77 diff --git a/doc/packet_interserv.txt b/doc/packet_interserv.txt index fb6403748c..ed24145440 100644 --- a/doc/packet_interserv.txt +++ b/doc/packet_interserv.txt @@ -594,6 +594,22 @@ Currently the max packet size is 0xFFFF (see 'WFIFOSET()' in 'src/common/socket. desc: - Request acc info +0x3009 + Type: ZI + Structure: .W .W .W .W .B .24B .24B + index: 0,2,6,4,8,9,24 + len: 9+NAME_LENGTH+NAME_LENGTH + parameter: + - cmd : packet identification (0x3009) + - len : Packet length + - nameid : ID of obtained item + - source : Source from where the item obtained + - type : Obtained type. 0: Box/Package, 1: Monster, 2: NPC + - name : Name of player who obtained the item + - srcname : Source name as alternative of source id + desc: + - Send broadcasts request if player get special items. + 0x3018 Type: ZI Structure: .W .L .L @@ -1477,6 +1493,22 @@ Currently the max packet size is 0xFFFF (see 'WFIFOSET()' in 'src/common/socket. desc: - Transmit the result of a account_information request from map-serv, with type 1 +0x3809 + Type: IZ + Structure: .W .W .W .W .B .24B .24B + index: 0,2,6,4,8,9,24 + len: 9+NAME_LENGTH+NAME_LENGTH + parameter: + - cmd : packet identification (0x3809) + - len : Packet length + - nameid : ID of obtained item + - source : Source from where the item obtained + - type : Obtained type. 0: Box/Package, 1: Monster, 2: NPC + - name : Name of player who obtained the item + - srcname : Source name as alternative of source + desc: + - Broadcasts if player get special items. + 0x3818 Type: IZ Structure: .W .W .L .L .B .?B diff --git a/sql-files/item_db_re.sql b/sql-files/item_db_re.sql index e309254614..5fce1ca396 100644 --- a/sql-files/item_db_re.sql +++ b/sql-files/item_db_re.sql @@ -8244,7 +8244,7 @@ REPLACE INTO `item_db_re` VALUES (14681,'Costume_Enchantment_Stone_Box_II','Cost REPLACE INTO `item_db_re` VALUES (14682,'Sealed_Beelzebub_Scroll','Sealed Beelzebub Scroll',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); REPLACE INTO `item_db_re` VALUES (14689,'Sealed_Kiel-D-01_Scroll','Sealed Kiel-D-01 Scroll',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); REPLACE INTO `item_db_re` VALUES (14695,'Costume_Enchant_Stone_Box_3','Costume Enchant Stone Box III',18,0,NULL,10,NULL,NULL,NULL,NULL,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem rand(6790,6792),1; getitem 4936,1; getitem 4937,1; getitem 4938,1;',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (14696,'Sealed_Gloom_Under_Night_Gachapon','Sealed Gloom Under Night Gachapon',18,0,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'/* getitem callfunc("F_Rand",Sealed Cards Gloom Under Night, 9 weapons smelting ticket, Armor 9 smelting ticket, medium armor Shadow, Shadow Weapon Medium, costume Wings of the Kirin, costume enchant stone box); */',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (14696,'Sealed_Gloom_Under_Night_Gachapon','Sealed Gloom Under Night Gachapon',18,0,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'/* getitem callfunc("F_Rand",Sealed Cards Gloom Under Night, 9 weapons smelting ticket, Armor 9 smelting ticket, medium armor Shadow, Shadow Weapon Medium, costume Wings of the Kirin, costume enchant stone box); */',NULL,NULL); REPLACE INTO `item_db_re` VALUES (14699,'Memorial_Garuda_Lucky_Egg','Memorial Garuda Lucky Egg',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,'1',NULL,NULL,'getgroupitem(IG_Memorial_Garuda_Lucky_Egg);',NULL,NULL); REPLACE INTO `item_db_re` VALUES (14701,'Rune_Midgard_Imortal_Lucky_Egg','Rune Midgard Imortal Lucky Egg',18,0,NULL,0,NULL,NULL,NULL,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Rune_Midgard_Imortal_Lucky_Egg);',NULL,NULL); REPLACE INTO `item_db_re` VALUES (14704,'Gemstone_Shadow_Box','Gemstone Shadow Box',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 24084,1; getitem 24085,1; getitem 24086,1; getitem 24087,1; getitem 24088,1; getitem 24089,1;',NULL,NULL); @@ -8263,12 +8263,12 @@ REPLACE INTO `item_db_re` VALUES (14730,'Costume_Festival_Box_II','Costume Festi REPLACE INTO `item_db_re` VALUES (14731,'Teleport_Shadow_Box','Teleport Shadow Box',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 24138,1; getitem 24139,1; getitem 24140,1; getitem 24141,1; getitem 24142,1; getitem 24143,1;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (14732,'Steal_Shadow_Box','Steal Shadow Box',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 24144,1; getitem 24145,1; getitem 24146,1; getitem 24147,1; getitem 24148,1; getitem 24149,1;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (14733,'Sealed_Pharaoh_Scroll','Sealed Pharaoh Scroll',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'/*TODO: Confirm the rates*/ getitem callfunc("F_Rand",6228,6232,14726,20034,17474),1;',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (14739,'Sealed_General_Egnigem_Cenia_Scroll','Sealed General Egnigem Cenia Scroll',18,10,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'/*TODO: Confirm the rates*/ getitem callfunc("F_Rand",4482,6228,6232,24156,19935),1;',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (14740,'Sealed_Vesper_Scroll','Sealed Vesper Scroll',18,10,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); -REPLACE INTO `item_db_re` VALUES (14741,'Midgard_Celebration_Lucky_Egg','Midgard Celebration Lucky Egg',18,0,NULL,10,NULL,NULL,NULL,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Midgard_Celebration_Lucky_Egg);',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (14753,'Hero_Midgard_Egg','Hero Midgard Egg',18,0,NULL,10,NULL,NULL,NULL,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Hero_Midgard_Egg);',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (14758,'Safe_To_Smelting_Scroll','Safe To Smelting Scroll',18,10,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'getitem callfunc("F_Rand",6238,6239,6228,6232,24216,17474,969),1;',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (14765,'Limited_Edition_JOB_Battle_Manual','Limited Edition JOB Battle Manual',18,10,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'sc_start SC_JEXPBOOST,3600000,35;',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (14739,'Sealed_General_Egnigem_Cenia_Scroll','Sealed General Egnigem Cenia Scroll',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'/*TODO: Confirm the rates*/ getitem callfunc("F_Rand",4482,6228,6232,24156,19935),1;',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (14740,'Sealed_Vesper_Scroll','Sealed Vesper Scroll',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); +REPLACE INTO `item_db_re` VALUES (14741,'Midgard_Celebration_Lucky_Egg','Midgard Celebration Lucky Egg',18,0,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Midgard_Celebration_Lucky_Egg);',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (14753,'Hero_Midgard_Egg','Hero Midgard Egg',18,0,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Hero_Midgard_Egg);',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (14758,'Safe_To_Smelting_Scroll','Safe To Smelting Scroll',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem callfunc("F_Rand",6238,6239,6228,6232,24216,17474,969),1;',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (14765,'Limited_Edition_JOB_Battle_Manual','Limited Edition JOB Battle Manual',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'sc_start SC_JEXPBOOST,3600000,35;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (14766,'Limited_Power_Booster','Limited Power Booster',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'bonus_script "{ bonus bBaseAtk,30; bonus bMatk,30; bonus bAtkRate,1; bonus bMatkRate,1; bonus bHit,30; bonus bFlee,30; bonus bAspd,1; bonus bUseSPrate,-5; bonus bFixedCastrate,-30; }",1800,1,1;',NULL,NULL); # More Armors REPLACE INTO `item_db_re` VALUES (15000,'Bone_Plate','Bone Plate',4,20,NULL,1000,NULL,60,NULL,1,0x000654E2,18,2,16,NULL,'85',1,0,'bonus bStr,1; bonus bMdef,3; bonus2 bIgnoreDefRaceRate,RC_DemiHuman,10; bonus2 bIgnoreDefRaceRate,RC_Player,10; bonus2 bIgnoreDefRaceRate,RC_Brute,10; bonus3 bAutoSpellWhenHit,"NPC_WIDEBLEEDING",1,10;',NULL,NULL); @@ -9036,9 +9036,9 @@ REPLACE INTO `item_db_re` VALUES (17484,'Three_Master_Package_III(10)','Three Ma REPLACE INTO `item_db_re` VALUES (17490,'Time_Travel_Lucky_Egg','Time Travel Lucky Egg',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Time_Travel_Lucky_Egg);',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17491,'Refinement_Ore_Box_VII','Refinement Ore Box VII',3,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 7619,5; getitem 7620,5; getitem 4482,1;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17492,'Refinement_Ore_Box_VII(10)','Refinement Ore Box VII(10)',3,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 7619,50; getitem 7620,50; getitem 4482,11;',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (17494,'Rise_Midgard_Lucky_Egg','Rise Midgard Lucky Egg',18,10,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Rise_Midgard_Lucky_Egg);',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (17495,'Lucky_Silvervine_Fruit_Box_III10','Lucky Silvervine Fruit Box III(10)',18,10,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Lucky_Silvervine_Fruit_Box_III10);',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (17496,'Lucky_Silvervine_Fruit_Box_III110','Lucky Silvervine Fruit Box III(110)',18,10,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Lucky_Silvervine_Fruit_Box_III110);',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (17494,'Rise_Midgard_Lucky_Egg','Rise Midgard Lucky Egg',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Rise_Midgard_Lucky_Egg);',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (17495,'Lucky_Silvervine_Fruit_Box_III10','Lucky Silvervine Fruit Box III(10)',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Lucky_Silvervine_Fruit_Box_III10);',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (17496,'Lucky_Silvervine_Fruit_Box_III110','Lucky Silvervine Fruit Box III(110)',18,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Lucky_Silvervine_Fruit_Box_III110);',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17498,'Three_Master_Package_IV','Three Master Package IV',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 14534,20; getitem 14535,20; getitem 12578,20; getitem 22812,1;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17499,'Three_Master_Package_IV(10)','Three Master Package IV(10)',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 14534,200; getitem 14535,200; getitem 12578,200; getitem 22812,11;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17501,'Support_Package_IV','Support Package IV',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 12208,2; getitem 12210,2; getitem 12883,2; getitem 14600,2; /*getitem Mysterious Water of Life,6;*/ if(!rand(100)) getitem 22823,1;',NULL,NULL); @@ -9052,13 +9052,13 @@ REPLACE INTO `item_db_re` VALUES (17512,'(Limited)Purified_Eluminium_Box(30)','( REPLACE INTO `item_db_re` VALUES (17513,'(Limited)Purified_Oridecon_Box(30)','(Limited) Purified Oridecon Box(30)',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 6910,30; getitem 6635,1;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17515,'Unlimited_Box_III','Unlimited Box III',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 12684,5; getitem 12796,10; if(!rand(30)) getitem 14758,1;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17516,'Unlimited_Box_III(10)','Unlimited Box III(10)',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 12684,50; getitem 12796,100; if(!rand(30)) getitem 14758,11;',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (17519,'Epic_Heroes_Scroll','Epic Heroes Scroll',18,0,NULL,10,NULL,NULL,NULL,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Epic_Heroes_Lucky_Egg);',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (17519,'Epic_Heroes_Scroll','Epic Heroes Scroll',18,0,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Epic_Heroes_Lucky_Egg);',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17520,'Limited_Edition_Manual_Box','Limited Edition Manual Box',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 14765,3; /*getitem (limited edition battle manual),2;*/',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17521,'Three_Master_Package_V','Three Master Package V',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 14534,20; getitem 14535,20; /*getitem Mysterious Water of Life,20;*/ getitem 22842,1;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17522,'Three_Master_Package_V(10)','Three Master Package V(10)',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 14534,200; getitem 14535,200; /*getitem Mysterious Water of Life,200;*/ getitem 22842,11;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17524,'Limited_Power_Booster_Box','Limited Power Booster Box',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 14766,1; getitem 22873,1;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17525,'Limited_Power_Booster_Box(100)','Limited Power Booster Box(100)',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 14766,100; getitem 22873,11;',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (17526,'Majestic_Lucky_Egg','Majestic Lucky Egg',18,0,NULL,10,NULL,NULL,NULL,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Majestic_Lucky_Egg);',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (17526,'Majestic_Lucky_Egg','Majestic Lucky Egg',18,0,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Majestic_Lucky_Egg);',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17527,'Actinidia_Cat_Fruit_Box(200)','Actinidia Cat Fruit Box(200)',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 6909,200; getitem 12636,rand(1,5); /*TODO: Fix the 12636 amount*/',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17532,'Blessing_Lucky_Egg','Blessing Lucky Egg',18,0,NULL,10,NULL,NULL,NULL,NULL,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getgroupitem(IG_Blessing_Lucky_Egg);',NULL,NULL); REPLACE INTO `item_db_re` VALUES (17544,'Smelting_Ore_Box_IX','Smelting Ore Box IX',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 7619,5; getitem 7620,5; getitem 22888,1;',NULL,NULL); diff --git a/src/char/inter.c b/src/char/inter.c index f6585b0569..8dd5b7098f 100644 --- a/src/char/inter.c +++ b/src/char/inter.c @@ -45,7 +45,7 @@ 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+1+NAME_LENGTH), 0, 0, 0, 0, 0, 0, 0, 0, // 3000- + -1,-1, 7,-1, -1,13,36, (2+4+4+4+1+NAME_LENGTH), 0,-1, 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, 6, 0, 0, 0, 0, 0, // 3020- Party -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030- @@ -908,6 +908,23 @@ int mapif_parse_broadcast(int fd) return 0; } +/** + * Parse received item broadcast and sends it to all connected map-serves + * ZI 3009 .W .W .W .W .B .24B .24B + * IZ 3809 .W .W .W .W .B .24B .24B + * @param fd + * @return + **/ +int mapif_parse_broadcast_item(int fd) { + unsigned char buf[9 + NAME_LENGTH*2]; + + memcpy(WBUFP(buf, 0), RFIFOP(fd, 0), RFIFOW(fd,2)); + WBUFW(buf, 0) = 0x3809; + chmapif_sendallwos(fd, buf, RFIFOW(fd,2)); + + return 0; +} + // Wisp/page request to send int mapif_parse_WisRequest(int fd) @@ -1154,6 +1171,7 @@ int inter_parse_frommap(int fd) case 0x3006: mapif_parse_NameChangeRequest(fd); break; case 0x3007: mapif_parse_accinfo(fd); break; /* 0x3008 is used by the report stuff */ + case 0x3009: mapif_parse_broadcast_item(fd); break; default: if( inter_party_parse_frommap(fd) || inter_guild_parse_frommap(fd) diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 31cd57a8c6..8584acf501 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -5673,7 +5673,7 @@ void getring (struct map_session_data* sd) if((flag = pc_additem(sd,&item_tmp,1,LOG_TYPE_COMMAND))) { clif_additem(sd,0,0,flag); - map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,4); + map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,4,0); } } diff --git a/src/map/clif.c b/src/map/clif.c index 150549eb43..30dd9eb918 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -17703,12 +17703,6 @@ static unsigned short clif_parse_cmd(int fd, struct map_session_data *sd) { #endif } -/** -* !TODO: Special item that obtained, must be broadcasted by this packet -* 07fd ?? (ZC_BROADCASTING_SPECIAL_ITEM_OBTAIN) -*/ -//void clif_broadcast_obtain_special_item() {} - #ifdef DUMP_UNKNOWN_PACKET void DumpUnknown(int fd,TBL_PC *sd,int cmd,int packet_len) { @@ -18187,6 +18181,54 @@ void clif_parse_merge_item_cancel(int fd, struct map_session_data* sd) { return; // Nothing todo yet } +/** + * 07fd .W .B .W .B .24B .B .W (ZC_BROADCASTING_SPECIAL_ITEM_OBTAIN) + * 07fd .W .B .W .B .24B .B .24B (ZC_BROADCASTING_SPECIAL_ITEM_OBTAIN) + * type: ITEMOBTAIN_TYPE_BOXITEM & ITEMOBTAIN_TYPE_MONSTER_ITEM "[playername] ... [surcename] ... [itemname]" -> MsgStringTable[1629] + * type: ITEMOBTAIN_TYPE_NPC "[playername] ... [itemname]" -> MsgStringTable[1870] + **/ +void clif_broadcast_obtain_special_item(const char *char_name, unsigned short nameid, unsigned short container, enum BROADCASTING_SPECIAL_ITEM_OBTAIN type, const char *srcname) { + unsigned char buf[9 + NAME_LENGTH * 2]; + unsigned short pos = 0, cmd = 0; + struct s_packet_db *info = NULL; + + if (!(cmd = packet_db_ack[clif_config.packet_db_ver][ZC_BROADCASTING_SPECIAL_ITEM_OBTAIN])) + return; + + if (!(info = &packet_db[clif_config.packet_db_ver][cmd]) || info->len == 0) + return; + + WBUFW(buf, 0) = 0x7fd; + WBUFB(buf, 4) = type; + WBUFW(buf, 5) = nameid; + WBUFB(buf, 7) = NAME_LENGTH; + safestrncpy((char *)WBUFP(buf, 8), char_name, NAME_LENGTH); + + switch (type) { + case ITEMOBTAIN_TYPE_BOXITEM: + WBUFW(buf, 2) = 11 + NAME_LENGTH; + WBUFB(buf, 8 + NAME_LENGTH) = 0; + WBUFW(buf, 9 + NAME_LENGTH) = container; + break; + + case ITEMOBTAIN_TYPE_MONSTER_ITEM: + { + struct mob_db *db = mob_db(container); + WBUFW(buf, 2) = 9 + NAME_LENGTH * 2; + WBUFB(buf, 8 + NAME_LENGTH) = NAME_LENGTH; + safestrncpy((char *)WBUFP(buf, 9 + NAME_LENGTH), db->name, NAME_LENGTH); + } + break; + + case ITEMOBTAIN_TYPE_NPC: + default: + WBUFW(buf, 2) = 8 + NAME_LENGTH; + break; + } + + clif_send(buf, WBUFW(buf, 2), NULL, ALL_CLIENT); +} + /*========================================== * Main client packet processing function *------------------------------------------*/ @@ -18842,6 +18884,7 @@ void packetdb_readdb(bool reload) { "ZC_WEAR_EQUIP_ACK", ZC_WEAR_EQUIP_ACK }, { "ZC_MERGE_ITEM_OPEN", ZC_MERGE_ITEM_OPEN }, { "ZC_ACK_MERGE_ITEM", ZC_ACK_MERGE_ITEM }, + { "ZC_BROADCASTING_SPECIAL_ITEM_OBTAIN", ZC_BROADCASTING_SPECIAL_ITEM_OBTAIN }, }; const char *filename[] = { "packet_db.txt", DBIMPORT"/packet_db.txt"}; int f; diff --git a/src/map/clif.h b/src/map/clif.h index 9b6c798216..43c7e69f4f 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -52,6 +52,7 @@ enum e_packet_ack { ZC_WEAR_EQUIP_ACK, ZC_MERGE_ITEM_OPEN, ZC_ACK_MERGE_ITEM, + ZC_BROADCASTING_SPECIAL_ITEM_OBTAIN, //add other here MAX_ACK_FUNC //auto upd len }; @@ -117,6 +118,12 @@ enum MERGE_ITEM_ACK { MERGE_ITEM_FAILED_MAX_COUNT = 0x2, }; +enum BROADCASTING_SPECIAL_ITEM_OBTAIN { + ITEMOBTAIN_TYPE_BOXITEM = 0x0, + ITEMOBTAIN_TYPE_MONSTER_ITEM = 0x1, + ITEMOBTAIN_TYPE_NPC = 0x2, +}; + // packet_db[SERVER] is reserved for server use #define SERVER 0 #define packet_len(cmd) packet_db[SERVER][cmd].len @@ -959,6 +966,6 @@ void clif_notify_bindOnEquip(struct map_session_data *sd, int n); void clif_merge_item_open(struct map_session_data *sd); -//void clif_broadcast_obtain_special_item(); ///TODO! +void clif_broadcast_obtain_special_item(const char *char_name, unsigned short nameid, unsigned short container, enum BROADCASTING_SPECIAL_ITEM_OBTAIN type, const char *srcname); #endif /* _CLIF_H_ */ diff --git a/src/map/intif.c b/src/map/intif.c index 8ee77fb64e..192da14093 100644 --- a/src/map/intif.c +++ b/src/map/intif.c @@ -25,7 +25,7 @@ #include static const int packet_len_table[]={ - -1,-1,27,-1, -1, 0,37,-1, 10+NAME_LENGTH, 0, 0, 0, 0, 0, 0, 0, //0x3800-0x380f + -1,-1,27,-1, -1, 0,37,-1, 10+NAME_LENGTH,-1, 0, 0, 0, 0, 0, 0, //0x3800-0x380f 0, 0, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0, //0x3810 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 @@ -2868,6 +2868,97 @@ void intif_parse_MessageToFD(int fd) { return; } +/// BROADCAST OBTAIN SPECIAL ITEM + +/** + * Request to send broadcast item to all servers + * ZI 3009 .W .W .W .W .B .?B + * @param sd Player who obtain the item + * @param nameid Obtained item + * @param sourceid Source of item, another item ID or monster ID + * @param type Obtain type @see enum BROADCASTING_SPECIAL_ITEM_OBTAIN + * @return + **/ +int intif_broadcast_obtain_special_item(struct map_session_data *sd, unsigned short nameid, unsigned int sourceid, unsigned char type) { + nullpo_retr(0, sd); + + // Should not be here! + if (type == ITEMOBTAIN_TYPE_NPC) { + intif_broadcast_obtain_special_item_npc(sd, nameid, NULL /*wisp_server_name*/); + return 0; + } + + // Send local + clif_broadcast_obtain_special_item(sd->status.name, nameid, sourceid, (enum BROADCASTING_SPECIAL_ITEM_OBTAIN)type, NULL); + + if (CheckForCharServer()) + return 0; + + if (other_mapserver_count < 1) + return 0; + + WFIFOHEAD(inter_fd, 9 + NAME_LENGTH); + WFIFOW(inter_fd, 0) = 0x3009; + WFIFOW(inter_fd, 2) = 9 + NAME_LENGTH; + WFIFOW(inter_fd, 4) = nameid; + WFIFOW(inter_fd, 6) = sourceid; + WFIFOB(inter_fd, 8) = type; + safestrncpy((char *)WFIFOP(inter_fd, 9), sd->status.name, NAME_LENGTH); + WFIFOSET(inter_fd, WFIFOW(inter_fd, 2)); + + return 1; +} + +/** + * Request to send broadcast item to all servers. + * TODO: Confirm the usage. Maybe on getitem-like command? + * ZI 3009 .W .W .W .W .B .24B .24B + * @param sd Player who obtain the item + * @param nameid Obtained item + * @param srcname Source name + * @return + **/ +int intif_broadcast_obtain_special_item_npc(struct map_session_data *sd, unsigned short nameid, const char *srcname) { + nullpo_retr(0, sd); + + // Send local + clif_broadcast_obtain_special_item(sd->status.name, nameid, 0, ITEMOBTAIN_TYPE_NPC, srcname); + + if (CheckForCharServer()) + return 0; + + if (other_mapserver_count < 1) + return 0; + + WFIFOHEAD(inter_fd, 9 + NAME_LENGTH*2); + WFIFOW(inter_fd, 0) = 0x3009; + WFIFOW(inter_fd, 2) = 9 + NAME_LENGTH*2; + WFIFOW(inter_fd, 4) = nameid; + WFIFOW(inter_fd, 6) = 0; + WFIFOB(inter_fd, 8) = ITEMOBTAIN_TYPE_NPC; + safestrncpy((char *)WFIFOP(inter_fd, 9), sd->status.name, NAME_LENGTH); + safestrncpy((char *)WFIFOP(inter_fd, 9 + NAME_LENGTH), srcname, NAME_LENGTH); + WFIFOSET(inter_fd, WFIFOW(inter_fd, 2)); + + return 1; +} + +/** + * Received broadcast item and broadcast on local map. + * IZ 3809 .W .W .W .W .B .24B .24B + * @param fd + **/ +void intif_parse_broadcast_obtain_special_item(int fd) { + int type = RFIFOB(fd, 8); + char name[NAME_LENGTH], srcname[NAME_LENGTH]; + + safestrncpy(name, (char *)RFIFOP(fd, 9), NAME_LENGTH); + if (type == ITEMOBTAIN_TYPE_NPC) + safestrncpy(name, (char *)RFIFOP(fd, 9 + NAME_LENGTH), NAME_LENGTH); + + clif_broadcast_obtain_special_item(name, RFIFOW(fd, 4), RFIFOW(fd, 6), (enum BROADCASTING_SPECIAL_ITEM_OBTAIN)type, srcname); +} + /*========================================== * Item Bound System *------------------------------------------*/ @@ -2985,6 +3076,7 @@ int intif_parse(int fd) case 0x3806: intif_parse_ChangeNameOk(fd); break; case 0x3807: intif_parse_MessageToFD(fd); break; case 0x3808: intif_parse_accinfo_ack(fd); break; + case 0x3809: intif_parse_broadcast_obtain_special_item(fd); break; case 0x3818: intif_parse_LoadGuildStorage(fd); break; case 0x3819: intif_parse_SaveGuildStorage(fd); break; case 0x3820: intif_parse_PartyCreated(fd); break; diff --git a/src/map/intif.h b/src/map/intif.h index fd40d1f9f1..708ce7389a 100644 --- a/src/map/intif.h +++ b/src/map/intif.h @@ -19,6 +19,8 @@ int intif_parse(int fd); int intif_broadcast(const char* mes, int len, int type); int intif_broadcast2(const char* mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY); +int intif_broadcast_obtain_special_item(struct map_session_data *sd, unsigned short nameid, unsigned int sourceid, unsigned char type); +int intif_broadcast_obtain_special_item_npc(struct map_session_data *sd, unsigned short nameid, const char *srcname); int intif_main_message(struct map_session_data* sd, const char* message); int intif_wis_message(struct map_session_data *sd,char *nick,char *mes,int mes_len); diff --git a/src/map/itemdb.c b/src/map/itemdb.c index b19db9d777..5b6e55eafe 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -160,15 +160,16 @@ unsigned short itemdb_searchrandomid(uint16 group_id, uint8 sub_group) { * @param *group: struct s_item_group from itemgroup_db[group_id].random[idx] or itemgroup_db[group_id].must[sub_group][idx] */ static void itemdb_pc_get_itemgroup_sub(struct map_session_data *sd, struct s_item_group_entry *data) { - uint16 i; + uint16 i, get_amt = 0; struct item tmp; + struct item_data *id = NULL; nullpo_retv(data); memset(&tmp, 0, sizeof(tmp)); + id = itemdb_search(data->nameid); tmp.nameid = data->nameid; - tmp.amount = (itemdb_isstackable(data->nameid)) ? data->amount : 1; tmp.bound = data->bound; tmp.identify = 1; tmp.expire_time = (data->duration) ? (unsigned int)(time(NULL) + data->duration*60) : 0; @@ -178,24 +179,23 @@ static void itemdb_pc_get_itemgroup_sub(struct map_session_data *sd, struct s_it tmp.card[2] = GetWord(sd->status.char_id, 0); tmp.card[3] = GetWord(sd->status.char_id, 1); } + + if (!itemdb_isstackable(data->nameid)) + get_amt = 1; + else + get_amt = data->amount; + // Do loop for non-stackable item - for (i = 0; i < data->amount; i++) { + for (i = 0; i < data->amount; i += get_amt) { char flag = 0; - tmp.unique_id = data->GUID ? pc_generate_unique_id(sd) : 0; // Generate UID - if ((flag = pc_additem(sd, &tmp, tmp.amount, LOG_TYPE_SCRIPT))) { + tmp.unique_id = data->GUID ? pc_generate_unique_id(sd) : 0; // Generate GUID + if ((flag = pc_additem(sd, &tmp, get_amt, LOG_TYPE_SCRIPT))) { clif_additem(sd, 0, 0, flag); if (pc_candrop(sd, &tmp)) - map_addflooritem(&tmp, tmp.amount, sd->bl.m, sd->bl.x,sd->bl.y, 0, 0, 0, 0); + map_addflooritem(&tmp, tmp.amount, sd->bl.m, sd->bl.x,sd->bl.y, 0, 0, 0, 0, 0); } - else if (!flag && data->isAnnounced) { - char output[CHAT_SIZE_MAX]; - sprintf(output, msg_txt(NULL, 717), sd->status.name, itemdb_jname(data->nameid), itemdb_jname(sd->itemid)); - - //! TODO: Move this broadcast to proper packet. ZI -> IZ (all Zones) -> ZC (clif_broadcast_obtain_special_item) - intif_broadcast(output, strlen(output) + 1, BC_DEFAULT); - } - if (itemdb_isstackable(data->nameid)) - break; + else if (!flag && data->isAnnounced) + intif_broadcast_obtain_special_item(sd, data->nameid, sd->itemid, ITEMOBTAIN_TYPE_BOXITEM); } } @@ -904,6 +904,7 @@ static bool itemdb_read_flag(char* fields[], int columns, int current) { if (flag&2) id->flag.group = set ? 1 : 0; if (flag&4 && itemdb_isstackable2(id)) id->flag.guid = set ? 1 : 0; if (flag&8) id->flag.bindOnEquip = true; + if (flag&16) id->flag.broadcast = 1; return true; } diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 415d982f3b..a9653e17dd 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -433,6 +433,7 @@ struct item_data unsigned dead_branch : 1; // As dead branch item. Logged at `branchlog` table and cannot be used at 'nobranch' mapflag [Cydh] unsigned group : 1; // As item group container [Cydh] unsigned guid : 1; // This item always be attached with GUID and make it as bound item! [Cydh] + unsigned broadcast : 1; ///< Will be broadcasted if someone obtain the item [Cydh] bool bindOnEquip; ///< Set item as bound when equipped } flag; struct {// item stacking limitation diff --git a/src/map/map.c b/src/map/map.c index daa5158564..a2dd3080fc 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1528,9 +1528,10 @@ bool map_closest_freecell(int16 m, int16 *x, int16 *y, int type, int flag) * @param second_charid : 2nd player that could loot the item (2nd charid that could loot for second_get_charid duration) * @param third_charid : 3rd player that could loot the item (3rd charid that could loot for third_get_charid duration) * @param flag: &1 MVP item. &2 do stacking check. &4 bypass droppable check. + * @param mob_id: Monster ID if dropped by monster * @return 0:failure, x:item_gid [MIN_FLOORITEM;MAX_FLOORITEM]==[2;START_ACCOUNT_NUM] *------------------------------------------*/ -int map_addflooritem(struct item *item,int amount,int16 m,int16 x,int16 y,int first_charid,int second_charid,int third_charid,int flags) +int map_addflooritem(struct item *item, int amount, int16 m, int16 x, int16 y, int first_charid, int second_charid, int third_charid, int flags, unsigned short mob_id) { int r; struct flooritem_data *fitem = NULL; @@ -1562,6 +1563,7 @@ int map_addflooritem(struct item *item,int amount,int16 m,int16 x,int16 y,int fi fitem->second_get_tick = fitem->first_get_tick + (flags&1 ? battle_config.mvp_item_second_get_time : battle_config.item_second_get_time); fitem->third_get_charid = third_charid; fitem->third_get_tick = fitem->second_get_tick + (flags&1 ? battle_config.mvp_item_third_get_time : battle_config.item_third_get_time); + fitem->mob_id = mob_id; memcpy(&fitem->item,item,sizeof(*item)); fitem->item.amount = amount; diff --git a/src/map/map.h b/src/map/map.h index f2b5f0941f..4785c7982a 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -437,6 +437,7 @@ struct flooritem_data { int first_get_charid,second_get_charid,third_get_charid; unsigned int first_get_tick,second_get_tick,third_get_tick; struct item item; + unsigned short mob_id; ///< ID of monster who dropped it. 0 for non-monster who dropped it. }; enum _sp { @@ -833,7 +834,7 @@ bool map_addnpc(int16 m,struct npc_data *); int map_clearflooritem_timer(int tid, unsigned int tick, int id, intptr_t data); int map_removemobs_timer(int tid, unsigned int tick, int id, intptr_t data); void map_clearflooritem(struct block_list* bl); -int map_addflooritem(struct item *item,int amount,int16 m,int16 x,int16 y,int first_charid,int second_charid,int third_charid,int flags); +int map_addflooritem(struct item *item, int amount, int16 m, int16 x, int16 y, int first_charid, int second_charid, int third_charid, int flags, unsigned short mob_id); // instances int map_addinstancemap(const char*,int); diff --git a/src/map/mob.c b/src/map/mob.c index 8300025e0a..3fb487880f 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -297,7 +297,7 @@ struct mob_data* mob_spawn_dataset(struct spawn_data *data) if (data->eventname[0] && strlen(data->eventname) >= 4) memcpy(md->npc_event, data->eventname, 50); if(md->db->status.mode&MD_LOOTER) - md->lootitem = (struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item)); + md->lootitems = (struct s_mob_lootitem *)aCalloc(LOOTITEM_SIZE,sizeof(struct s_mob_lootitem)); md->spawn_timer = INVALID_TIMER; md->deletetimer = INVALID_TIMER; md->skill_idx = -1; @@ -999,8 +999,8 @@ int mob_spawn (struct mob_data *md) memset(md->dmglog, 0, sizeof(md->dmglog)); md->tdmg = 0; - if (md->lootitem) - memset(md->lootitem, 0, sizeof(*md->lootitem)); + if (md->lootitems) + memset(md->lootitems, 0, sizeof(*md->lootitems)); md->lootitem_count = 0; @@ -1582,7 +1582,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) return true; // Scan area for targets - if (!tbl && can_move && mode&MD_LOOTER && md->lootitem && DIFF_TICK(tick, md->ud.canact_tick) > 0 && + if (!tbl && can_move && mode&MD_LOOTER && md->lootitems && DIFF_TICK(tick, md->ud.canact_tick) > 0 && (md->lootitem_count < LOOTITEM_SIZE || battle_config.monster_loot_type != 1)) { // Scan area for items to loot, avoid trying to loot if the mob is full and can't consume the items. map_foreachinshootrange (mob_ai_sub_hard_lootsearch, &md->bl, view_range, BL_ITEM, md, &tbl); @@ -1626,7 +1626,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) struct flooritem_data *fitem; if (md->ud.target == tbl->id && md->ud.walktimer != INVALID_TIMER) return true; //Already locked. - if (md->lootitem == NULL) + if (md->lootitems == NULL) { //Can't loot... mob_unlocktarget(md, tick); return true; @@ -1654,13 +1654,17 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) log_pick_mob(md, LOG_TYPE_LOOT, fitem->item.amount, &fitem->item); if (md->lootitem_count < LOOTITEM_SIZE) { - memcpy (&md->lootitem[md->lootitem_count++], &fitem->item, sizeof(md->lootitem[0])); + memcpy (&md->lootitems[md->lootitem_count].item, &fitem->item, sizeof(md->lootitems[0].item)); + md->lootitems[md->lootitem_count].mob_id = fitem->mob_id; + md->lootitem_count++; } else { //Destroy first looted item... - if (md->lootitem[0].card[0] == CARD0_PET) - intif_delete_petdata( MakeDWord(md->lootitem[0].card[1],md->lootitem[0].card[2]) ); - memmove(&md->lootitem[0], &md->lootitem[1], (LOOTITEM_SIZE-1)*sizeof(md->lootitem[0])); - memcpy (&md->lootitem[LOOTITEM_SIZE-1], &fitem->item, sizeof(md->lootitem[0])); + if (md->lootitems[0].item.card[0] == CARD0_PET) + intif_delete_petdata(MakeDWord(md->lootitems[0].item.card[1],md->lootitems[0].item.card[2])); + memmove(&md->lootitems[0], &md->lootitems[1], (LOOTITEM_SIZE-1)*sizeof(md->lootitems[0])); + memcpy (&md->lootitems[LOOTITEM_SIZE-1].item, &fitem->item, sizeof(md->lootitems[0].item)); + md->lootitems[LOOTITEM_SIZE-1].mob_id = fitem->mob_id; } + if (pcdb_checkid(md->vd->class_)) { //Give them walk act/delay to properly mimic players. [Skotlex] clif_takeitem(&md->bl,tbl); @@ -1857,13 +1861,14 @@ static int mob_ai_hard(int tid, unsigned int tick, int id, intptr_t data) /*========================================== * Initializes the delay drop structure for mob-dropped items. *------------------------------------------*/ -static struct item_drop* mob_setdropitem(unsigned short nameid, int qty) +static struct item_drop* mob_setdropitem(unsigned short nameid, int qty, unsigned short mob_id) { struct item_drop *drop = ers_alloc(item_drop_ers, struct item_drop); memset(&drop->item_data, 0, sizeof(struct item)); drop->item_data.nameid = nameid; drop->item_data.amount = qty; drop->item_data.identify = itemdb_isidentified(nameid); + drop->mob_id = mob_id; drop->next = NULL; return drop; } @@ -1871,10 +1876,18 @@ static struct item_drop* mob_setdropitem(unsigned short nameid, int qty) /*========================================== * Initializes the delay drop structure for mob-looted items. *------------------------------------------*/ -static struct item_drop* mob_setlootitem(struct item* item) +static struct item_drop* mob_setlootitem(struct s_mob_lootitem *item, unsigned short mob_id) { struct item_drop *drop = ers_alloc(item_drop_ers, struct item_drop); memcpy(&drop->item_data, item, sizeof(struct item)); + + /** + * Conditions for lotted item, so it can be announced when player pick it up + * 1. Not-dropped other than monster. (This will be done later on pc_takeitem/party_share_loot) + * 2. The mob_id is become the last lootter, instead of the real monster who drop it. + **/ + drop->mob_id = item->mob_id; + drop->next = NULL; return drop; } @@ -1886,17 +1899,20 @@ static int mob_delay_item_drop(int tid, unsigned int tick, int id, intptr_t data { struct item_drop_list *list; struct item_drop *ditem; - list=(struct item_drop_list *)data; + + list = (struct item_drop_list *)data; ditem = list->item; + while (ditem) { struct item_drop *ditem_prev; map_addflooritem(&ditem->item_data,ditem->item_data.amount, list->m,list->x,list->y, - list->first_charid,list->second_charid,list->third_charid,4); + list->first_charid,list->second_charid,list->third_charid,4,ditem->mob_id); ditem_prev = ditem; ditem = ditem->next; ers_free(item_drop_ers, ditem_prev); } + ers_free(item_drop_list_ers, list); return 0; } @@ -1927,12 +1943,19 @@ static void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, str && check_distance_blxy(&sd->bl, dlist->x, dlist->y, AUTOLOOT_DISTANCE) #endif ) { //Autoloot. + struct party_data *p = party_search(sd->status.party_id); + if (party_share_loot(party_search(sd->status.party_id), sd, &ditem->item_data, sd->status.char_id) == 0 ) { ers_free(item_drop_ers, ditem); return; } + + if ((itemdb_search(ditem->item_data.nameid))->flag.broadcast && + (!p || !(p->party.item&2)) // Somehow, if party's pickup distribution is 'Even Share', no announcemet + ) + intif_broadcast_obtain_special_item(sd, ditem->item_data.nameid, md->mob_id, ITEMOBTAIN_TYPE_MONSTER_ITEM); } ditem->next = dlist->item; dlist->item = ditem; @@ -2473,7 +2496,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) continue; } - ditem = mob_setdropitem(md->db->dropitem[i].nameid, 1); + ditem = mob_setdropitem(md->db->dropitem[i].nameid, 1, md->mob_id); //A Rare Drop Global Announce by Lupus if( mvp_sd && drop_rate <= battle_config.rare_drop_announce ) { @@ -2489,7 +2512,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) // Ore Discovery [Celest] if (sd == mvp_sd && pc_checkskill(sd,BS_FINDINGORE)>0 && battle_config.finding_ore_rate/10 >= rnd()%10000) { - ditem = mob_setdropitem(itemdb_searchrandomid(IG_FINDINGORE,1), 1); + ditem = mob_setdropitem(itemdb_searchrandomid(IG_FINDINGORE,1), 1, md->mob_id); mob_item_drop(md, dlist, ditem, 0, battle_config.finding_ore_rate/10, homkillonly); } @@ -2519,7 +2542,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) continue; dropid = (sd->add_drop[i].nameid > 0) ? sd->add_drop[i].nameid : itemdb_searchrandomid(sd->add_drop[i].group,1); - mob_item_drop(md, dlist, mob_setdropitem(dropid,1), 0, drop_rate, homkillonly); + mob_item_drop(md, dlist, mob_setdropitem(dropid,1,md->mob_id), 0, drop_rate, homkillonly); } } @@ -2532,15 +2555,15 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) } // process items looted by the mob - if(md->lootitem) { - for(i = 0; i < md->lootitem_count; i++) - mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, homkillonly); + if (md->lootitems) { + for (i = 0; i < md->lootitem_count; i++) + mob_item_drop(md, dlist, mob_setlootitem(&md->lootitems[i], md->mob_id), 1, 10000, homkillonly); } if (dlist->item) //There are drop items. add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr_t)dlist); else //No drops ers_free(item_drop_list_ers, dlist); - } else if (md->lootitem && md->lootitem_count) { //Loot MUST drop! + } else if (md->lootitems && md->lootitem_count) { //Loot MUST drop! struct item_drop_list *dlist = ers_alloc(item_drop_list_ers, struct item_drop_list); dlist->m = md->bl.m; dlist->x = md->bl.x; @@ -2549,8 +2572,8 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) dlist->second_charid = (second_sd ? second_sd->status.char_id : 0); dlist->third_charid = (third_sd ? third_sd->status.char_id : 0); dlist->item = NULL; - for(i = 0; i < md->lootitem_count; i++) - mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, homkillonly); + for (i = 0; i < md->lootitem_count; i++) + mob_item_drop(md, dlist, mob_setlootitem(&md->lootitems[i], md->mob_id), 1, 10000, homkillonly); add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr_t)dlist); } @@ -2613,6 +2636,8 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) } for(i = 0; i < MAX_MVP_DROP; i++) { + struct item_data *i_data; + if(mdrop_id[i] <= 0 || !itemdb_exists(mdrop_id[i])) continue; @@ -2630,11 +2655,11 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) clif_mvp_item(mvp_sd,item.nameid); log_mvp[0] = item.nameid; + i_data = itemdb_exists(item.nameid); + //A Rare MVP Drop Global Announce by Lupus if(temp<=battle_config.rare_drop_announce) { - struct item_data *i_data; char message[128]; - i_data = itemdb_exists(item.nameid); sprintf (message, msg_txt(NULL,541), mvp_sd->status.name, md->name, i_data->jname, temp/100.); //MSG: "'%s' won %s's %s (chance: %0.02f%%)" intif_broadcast(message,strlen(message)+1,BC_DEFAULT); @@ -2642,9 +2667,12 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) if((temp = pc_additem(mvp_sd,&item,1,LOG_TYPE_PICKDROP_PLAYER)) != 0) { clif_additem(mvp_sd,0,0,temp); - map_addflooritem(&item,1,mvp_sd->bl.m,mvp_sd->bl.x,mvp_sd->bl.y,mvp_sd->status.char_id,(second_sd?second_sd->status.char_id:0),(third_sd?third_sd->status.char_id:0),1); + map_addflooritem(&item,1,mvp_sd->bl.m,mvp_sd->bl.x,mvp_sd->bl.y,mvp_sd->status.char_id,(second_sd?second_sd->status.char_id:0),(third_sd?third_sd->status.char_id:0),1,0); } + if (i_data->flag.broadcast) + intif_broadcast_obtain_special_item(mvp_sd, item.nameid, md->mob_id, ITEMOBTAIN_TYPE_MONSTER_ITEM); + //Logs items, MVP prizes [Lupus] log_pick_mob(md, LOG_TYPE_MVP, -1, &item); //If item_drop_mvp_mode is not 2, then only one item should be granted @@ -2902,8 +2930,8 @@ int mob_class_change (struct mob_data *md, int mob_id) for(i=0,c=tick-MOB_MAX_DELAY;iskilldelay[i] = c; - if(md->lootitem == NULL && md->db->status.mode&MD_LOOTER) - md->lootitem=(struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item)); + if (md->lootitems == NULL && md->db->status.mode&MD_LOOTER) + md->lootitems = (struct s_mob_lootitem *)aCalloc(LOOTITEM_SIZE,sizeof(struct s_mob_lootitem)); //Targets should be cleared no morph md->target_id = md->attacked_id = 0; diff --git a/src/map/mob.h b/src/map/mob.h index 246437dd62..4506d241d7 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -102,6 +102,12 @@ struct spawn_info { unsigned short qty; }; +/// Loooitem struct +struct s_mob_lootitem { + struct item item; ///< Item info + unsigned short mob_id; ///< ID of monster that dropped the item +}; + struct mob_db { char sprite[NAME_LENGTH],name[NAME_LENGTH],jname[NAME_LENGTH]; unsigned int base_exp,job_exp; @@ -161,7 +167,7 @@ struct mob_data { } dmglog[DAMAGELOG_SIZE]; struct spawn_data *spawn; //Spawn data. int spawn_timer; //Required for Convex Mirror - struct item *lootitem; + struct s_mob_lootitem *lootitems; short mob_id; unsigned int tdmg; //Stores total damage given to the mob, for exp calculations. [Skotlex] int level; @@ -238,6 +244,8 @@ enum e_mob_skill_condition { // The data structures for storing delayed item drops struct item_drop { struct item item_data; + unsigned short mob_id; + enum bl_type src_type; struct item_drop* next; }; struct item_drop_list { diff --git a/src/map/pc.c b/src/map/pc.c index 227bf0d3e3..e97e185da3 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -4456,7 +4456,7 @@ bool pc_dropitem(struct map_session_data *sd,int n,int amount) return false; } - if (!map_addflooritem(&sd->status.inventory[n], amount, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 2)) + if (!map_addflooritem(&sd->status.inventory[n], amount, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 2, 0)) return false; pc_delitem(sd, n, amount, 1, 0, LOG_TYPE_PICKDROP_PLAYER); @@ -4528,6 +4528,13 @@ bool pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem) //Display pickup animation. pc_stop_attack(sd); clif_takeitem(&sd->bl,&fitem->bl); + + if (fitem->mob_id && + (itemdb_search(fitem->item.nameid))->flag.broadcast && + (!p || !(p->party.item&2)) // Somehow, if party's pickup distribution is 'Even Share', no announcemet + ) + intif_broadcast_obtain_special_item(sd, fitem->item.nameid, fitem->mob_id, ITEMOBTAIN_TYPE_MONSTER_ITEM); + map_clearflooritem(&fitem->bl); return true; } @@ -7367,7 +7374,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) item_tmp.card[1]=0; item_tmp.card[2]=GetWord(sd->status.char_id,0); // CharId item_tmp.card[3]=GetWord(sd->status.char_id,1); - map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } //Remove bonus_script when dead diff --git a/src/map/pet.c b/src/map/pet.c index 19fd304f7c..a0ccf268e7 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -380,7 +380,7 @@ static int pet_return_egg(struct map_session_data *sd, struct pet_data *pd) if((flag = pc_additem(sd,&tmp_item,1,LOG_TYPE_OTHER))) { clif_additem(sd,0,0,flag); - map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } pd->pet.incubate = 1; @@ -731,7 +731,7 @@ bool pet_get_egg(uint32 account_id, short pet_class, int pet_id ) { if((ret = pc_additem(sd,&tmp_item,1,LOG_TYPE_PICKDROP_PLAYER))) { clif_additem(sd,0,0,ret); - map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } return true; @@ -918,7 +918,7 @@ static int pet_unequipitem(struct map_session_data *sd, struct pet_data *pd) if((flag = pc_additem(sd,&tmp_item,1,LOG_TYPE_OTHER))) { clif_additem(sd,0,0,flag); - map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } if( battle_config.pet_equip_required ) { // Skotlex: halt support timers if needed @@ -1277,7 +1277,7 @@ static int pet_delay_item_drop(int tid, unsigned int tick, int id, intptr_t data map_addflooritem(&ditem->item_data,ditem->item_data.amount, list->m,list->x,list->y, - list->first_charid,list->second_charid,list->third_charid,4); + list->first_charid,list->second_charid,list->third_charid,4,0); ditem_prev = ditem; ditem = ditem->next; ers_free(item_drop_ers, ditem_prev); diff --git a/src/map/script.c b/src/map/script.c index a1d65ee578..c7f59730c0 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -6638,7 +6638,7 @@ BUILDIN_FUNC(getitem) { clif_additem(sd, 0, 0, flag); if( pc_candrop(sd,&it) ) - map_addflooritem(&it,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&it,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } } } @@ -6757,7 +6757,7 @@ BUILDIN_FUNC(getitem2) { 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); + map_addflooritem(&item_tmp,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } } } @@ -7046,7 +7046,7 @@ BUILDIN_FUNC(makeitem) { else item_tmp.identify = itemdb_isidentified(nameid); - map_addflooritem(&item_tmp,amount,m,x,y,0,0,0,4); + map_addflooritem(&item_tmp,amount,m,x,y,0,0,0,4,0); } return SCRIPT_CMD_SUCCESS; } @@ -7120,7 +7120,7 @@ BUILDIN_FUNC(makeitem2) { item_tmp.card[2] = script_getnum(st,12); item_tmp.card[3] = script_getnum(st,13); - map_addflooritem(&item_tmp,amount,m,x,y,0,0,0,4); + map_addflooritem(&item_tmp,amount,m,x,y,0,0,0,4,0); } else return SCRIPT_CMD_FAILURE; @@ -12243,7 +12243,7 @@ BUILDIN_FUNC(successremovecards) { if((flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ // get back the cart in inventory clif_additem(sd,0,0,flag); - map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } } } @@ -12266,7 +12266,7 @@ BUILDIN_FUNC(successremovecards) { pc_delitem(sd,i,1,0,3,LOG_TYPE_SCRIPT); if((flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ //chk if can be spawn in inventory otherwise put on floor clif_additem(sd,0,0,flag); - map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } clif_misceffect(&sd->bl,3); @@ -12311,7 +12311,7 @@ BUILDIN_FUNC(failedremovecards) { if((flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ clif_additem(sd,0,0,flag); - map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } } } @@ -12341,7 +12341,7 @@ BUILDIN_FUNC(failedremovecards) { if((flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ clif_additem(sd,0,0,flag); - map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } } clif_misceffect(&sd->bl,2); @@ -19260,7 +19260,7 @@ BUILDIN_FUNC(getrandgroupitem) { if ((flag = pc_additem(sd,&item_tmp,item_tmp.amount,LOG_TYPE_SCRIPT))) { clif_additem(sd,0,0,flag); if (pc_candrop(sd,&item_tmp)) - map_addflooritem(&item_tmp,item_tmp.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&item_tmp,item_tmp.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } } } diff --git a/src/map/skill.c b/src/map/skill.c index 0b00d7cdf2..f973b231af 100755 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -5204,7 +5204,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint item_tmp.nameid = sg->item_id?sg->item_id:ITEMID_TRAP; item_tmp.identify = 1; if( item_tmp.nameid ) - map_addflooritem(&item_tmp,1,bl->m,bl->x,bl->y,0,0,0,4); + map_addflooritem(&item_tmp,1,bl->m,bl->x,bl->y,0,0,0,4,0); } skill_delunit(su); } @@ -7110,7 +7110,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui eflag = pc_additem(sd,&item_tmp,1,LOG_TYPE_PRODUCE); if(eflag) { clif_additem(sd,0,0,eflag); - map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } } break; @@ -7874,7 +7874,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui item_tmp.amount = skill_get_itemqty(su->group->skill_id, i+1); if( item_tmp.nameid && (flag2=pc_additem(sd,&item_tmp,item_tmp.amount,LOG_TYPE_OTHER)) ){ clif_additem(sd,0,0,flag2); - map_addflooritem(&item_tmp,item_tmp.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,4); + map_addflooritem(&item_tmp,item_tmp.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,4,0); } } } @@ -7888,7 +7888,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( item_tmp.nameid && (flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_OTHER)) ) { clif_additem(sd,0,0,flag); - map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,4); + map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,4,0); } } } @@ -17638,7 +17638,7 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) memset(&item_tmp,0,sizeof(item_tmp)); item_tmp.nameid = group->item_id?group->item_id:ITEMID_TRAP; item_tmp.identify = 1; - map_addflooritem(&item_tmp,1,bl->m,bl->x,bl->y,0,0,0,4); + map_addflooritem(&item_tmp,1,bl->m,bl->x,bl->y,0,0,0,4,0); } skill_delunit(unit); } @@ -17721,7 +17721,7 @@ static int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) memset(&item_tmp, 0, sizeof(item_tmp)); item_tmp.nameid = group->item_id; item_tmp.identify = 1; - map_addflooritem(&item_tmp, 1, bl->m, bl->x, bl->y, 0, 0, 0, 4); + map_addflooritem(&item_tmp, 1, bl->m, bl->x, bl->y, 0, 0, 0, 4, 0); } skill_delunit(unit); } @@ -18678,7 +18678,7 @@ bool skill_produce_mix(struct map_session_data *sd, uint16 skill_id, unsigned sh for (l = 0; l < total_qty; l += tmp_item.amount) { if ((flag = pc_additem(sd,&tmp_item,tmp_item.amount,LOG_TYPE_PRODUCE))) { clif_additem(sd,0,0,flag); - map_addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } } k++; @@ -18696,7 +18696,7 @@ bool skill_produce_mix(struct map_session_data *sd, uint16 skill_id, unsigned sh } else if (tmp_item.amount) { //Success if ((flag = pc_additem(sd,&tmp_item,tmp_item.amount,LOG_TYPE_PRODUCE))) { clif_additem(sd,0,0,flag); - map_addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } if (skill_id == GN_MIX_COOKING || skill_id == GN_MAKEBOMB || skill_id == GN_S_PHARMACY) { clif_produceeffect(sd,6,nameid); @@ -18753,7 +18753,7 @@ bool skill_produce_mix(struct map_session_data *sd, uint16 skill_id, unsigned sh tmp_item.identify = 1; if ((flag = pc_additem(sd,&tmp_item,tmp_item.amount,LOG_TYPE_PRODUCE))) { clif_additem(sd,0,0,flag); - map_addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } clif_produceeffect(sd,7,nameid); clif_misceffect(&sd->bl,6); @@ -18823,7 +18823,7 @@ bool skill_arrow_create(struct map_session_data *sd, unsigned short nameid) } if ((flag = pc_additem(sd,&tmp_item,tmp_item.amount,LOG_TYPE_PRODUCE))) { clif_additem(sd,0,0,flag); - map_addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } } return true; @@ -19091,7 +19091,7 @@ int skill_elementalanalysis(struct map_session_data* sd, int n, uint16 skill_lv, unsigned char flag = pc_additem(sd,&tmp_item,tmp_item.amount,LOG_TYPE_CONSUME); if( flag != 0 ) { clif_additem(sd,0,0,flag); - map_addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map_addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); } } diff --git a/src/map/status.c b/src/map/status.c index 272b8bea24..8eb7d41335 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -11403,7 +11403,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const it.nameid = skill_get_itemid(RL_H_MINE,0); it.amount = max(skill_get_itemqty(RL_H_MINE,0),1); it.identify = 1; - map_addflooritem(&it, it.amount, bl->m,bl->x, bl->y, caster->status.char_id, 0, 0, 4); + map_addflooritem(&it, it.amount, bl->m,bl->x, bl->y, caster->status.char_id, 0, 0, 4, 0); } break; case SC_VACUUM_EXTREME: diff --git a/src/map/unit.c b/src/map/unit.c index 15be55d17c..8b9c649fd9 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -3295,9 +3295,9 @@ int unit_free(struct block_list *bl, clr_type clrtype) md->deletetimer = INVALID_TIMER; } - if( md->lootitem ) { - aFree(md->lootitem); - md->lootitem = NULL; + if (md->lootitems) { + aFree(md->lootitems); + md->lootitems = NULL; } if( md->guardian_data ) {