diff --git a/db/const.txt b/db/const.txt index e595a13037..fdd5e56bfd 100644 --- a/db/const.txt +++ b/db/const.txt @@ -1796,7 +1796,22 @@ SC_MTF_MSP 604 SC_MTF_PUMPKIN 605 SC_MTF_HITFLEE 606 SC_CRIFOOD 607 -SC_EXTREMITYFIST2 608 +SC_HASTEATTACK_CASH 608 +SC_REUSE_LIMIT_A 609 +SC_REUSE_LIMIT_B 610 +SC_REUSE_LIMIT_C 611 +SC_REUSE_LIMIT_D 612 +SC_REUSE_LIMIT_E 613 +SC_REUSE_LIMIT_F 614 +SC_REUSE_LIMIT_G 615 +SC_REUSE_LIMIT_H 616 +SC_REUSE_LIMIT_MTF 617 +SC_REUSE_LIMIT_ASPD_POTION 618 +SC_REUSE_MILLENNIUMSHIELD 619 +SC_REUSE_CRUSHSTRIKE 620 +SC_REUSE_STORMBLAST 621 +SC_ALL_RIDING_REUSE_LIMIT 622 +SC_EXTREMITYFIST2 623 //Status Icon SI_BLANK -1 diff --git a/db/pre-re/item_delay.txt b/db/pre-re/item_delay.txt index 31bc494455..d34bd34156 100644 --- a/db/pre-re/item_delay.txt +++ b/db/pre-re/item_delay.txt @@ -1,31 +1,56 @@ // Item Delay Database // // Structure of Database: -// Item ID,Delay in Milliseconds +// ,{,} // -// NOTE: -// There is a max concurrent number of entries set in src/map/itemdb.h as MAX_ITEMDELAYS. +// +// ID of item that will has reuse delay. +// +// Re-use delay in milliseconds. +// +// SC (status change) group for the item. +// Example for SC_REUSE_LIMIT_MTF +// 12658,10000,620 // Transformation Scroll(Deviruchi) +// 12659,10000,620 // Transformation Scroll(Raydric) +// -> 12658 has reuse delay for 10 seconds, and also, +// 12659 cannot be used when this delay is active. +// Since this is optional, default is -1 will ignores the +// delay group and the delay will be stored in character's +// data that has limit set in src/map/itemdb.h as MAX_ITEMDELAYS. +// SC_REUSE_LIMIT_A 609 +14538,300000,608 //Glass_Of_Illusion + +// SC_REUSE_LIMIT_B 610 +14586,180000,609 //Spark_Candy + +// SC_REUSE_LIMIT_C 611 +12208,60000,610 //Battle_Manual + +// SC_REUSE_LIMIT_D 612 +12210,60000,611 //Bubble_Gum + +// SC_REUSE_LIMIT_E 613 +11522,1000,612 //Red_Raffle_Sap +11523,2000,612 //Yellow_Raffle_Sap +11524,3000,612 //White_Raffle_Sap + +// SC_REUSE_LIMIT_F 614 +607,5000,613 //Yggdrasil_Berry + +// SC_REUSE_LIMIT_G 615 +608,3000,614 //Yggdrasil_Seed + +// SC_REUSE_LIMIT_H 616 +11525,5000,615 //Mora_Hip_Tea + +// Misc //12202,60000 //Str_Dish10_ //12203,60000 //Agi_Dish10_ //12204,60000 //Int_Dish10_ //12205,60000 //Dex_Dish10_ //12206,60000 //Luk_Dish10_ //12207,60000 //Vit_Dish10_ -12208,60000 //Battle_Manual -12210,60000 //Bubble_Gum -14538,300000 //Glass_Of_Illusion -14586,180000 //Spark_Candy -607,5000 //Yggdrasil_Berry -608,3000 //Yggdrasil_Seed - -// Bifrost Items -11522,1000 //Red_Raffle_Sap -11523,2000 //Yellow_Raffle_Sap -11524,3000 //White_Raffle_Sap -11525,5000 //Mora_Hip_Tea - -// FIX ME! Delays need confirmation. -12968,300000 //Emergency_Scroll1 -12969,300000 //Emergency_Scroll2 -12970,300000 //Emergency_Scroll3 +12968,300000 //Emergency_Scroll1 //! CHECKME: Need confirmation! +12969,300000 //Emergency_Scroll2 //! CHECKME: Need confirmation! +12970,300000 //Emergency_Scroll3 //! CHECKME: Need confirmation! diff --git a/db/re/item_db.txt b/db/re/item_db.txt index ba45f9c330..e5645d8e08 100644 --- a/db/re/item_db.txt +++ b/db/re/item_db.txt @@ -6556,7 +6556,7 @@ 12681,Nestea_Lemon,Nestea Lemon,2,0,,50,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{} 12682,Nestea_Blacktea,Nestea Black Tea,2,0,,30,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{} 12683,Sg_Vi_Potion_Box200,Siege Violet Potion Box (200),2,20,,200,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 11547,200; },{},{} -12684,ASPD_Potion,ASPD Potion,2,0,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{} +12684,ASPD_Potion,ASPD Potion,2,0,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ sc_start SC_HASTEATTACK_CASH,900000,3; },{},{} 12685,Gryphon_Egg_Scroll,Gryphon Egg Scroll,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{} 12686,Str_Dish20,Str Dish20,2,0,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{} 12687,Int_Dish20,Int Dish20,2,0,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{} @@ -9883,7 +9883,7 @@ 22064,Thorny_Shoes,Thorny Shoes,4,0,,1000,,25,,1,0xFFFFFFFF,63,2,64,,,1,,{ bonus bShortWeaponDamageReturn,getrefine()/2; },{},{} 22067,Shoe_of_Witch,Shoe of Witch,4,10,,400,,10,,0,0xFFFFFFFE,63,2,64,,1,1,,{ skill "ALL_CATCRY",1,1; },{},{} // -22508,Para_Team_Mark_,Eden Group Mark,11,0,,0,,,,,,,,,,,,,{},{},{} +22508,Para_Team_Mark_,Eden Group Mark,11,0,,0,,,,0,0xFFFFFFFF,63,2,,,,,,{ /*itemskill "AL_TELEPORT",3;*/ unitskilluseid getcharid(3),"AL_TELEPORT",3; },{},{} 22507,Worn-Out-Scroll,Worn-Out-Scroll,3,10,,10,,,,0,,,,,,,,,{},{},{} 22510,King_Wolf_Scroll,King Wolf Scroll,2,10,,10,,,,0,0xFFFFFFFF,63,2,,,,,,{ /*TODO, confirm the rates*/ getitem callfunc("F_Rand",6635,19598,5658,6238,6239),1; },{},{} 22513,King_of_Gift_Box,King of Gift Box,2,10,,100,,,,0,0xFFFFFFFF,63,2,,,,,,{ /*TODO, confirm the rates*/ getitem callfunc("F_Rand",12817,4403,14512),1; },{},{} diff --git a/db/re/item_delay.txt b/db/re/item_delay.txt index d8b58097b0..1f7b3969c5 100644 --- a/db/re/item_delay.txt +++ b/db/re/item_delay.txt @@ -1,41 +1,91 @@ // Item Delay Database // // Structure of Database: -// Item ID,Delay in Milliseconds +// ,{,} // -// NOTE: -// There is a max concurrent number of entries set in src/map/itemdb.h as MAX_ITEMDELAYS. +// +// ID of item that will has reuse delay. +// +// Re-use delay in milliseconds. +// +// SC (status change) group for the item. +// Example for SC_REUSE_LIMIT_MTF +// 12658,10000,620 // Transformation Scroll(Deviruchi) +// 12659,10000,620 // Transformation Scroll(Raydric) +// -> 12658 has reuse delay for 10 seconds, and also, +// 12659 cannot be used when this delay is active. +// Since this is optional, default is -1 will ignores the +// delay group and the delay will be stored in character's +// data that has limit set in src/map/itemdb.h as MAX_ITEMDELAYS. +// SC_REUSE_REFRESH 317 +12725,120000,317 //Runstone_Nosiege + +// SC_REUSE_LIMIT_A 609 +14538,300000,608 //Glass_Of_Illusion + +// SC_REUSE_LIMIT_B 610 +12596,180000,609 //Magic_Candy +14586,180000,609 //Spark_Candy + +// SC_REUSE_LIMIT_C 611 +12208,60000,610 //Battle_Manual + +// SC_REUSE_LIMIT_D 612 +12210,60000,611 //Bubble_Gum + +// SC_REUSE_LIMIT_E 613 +11522,1000,612 //Red_Raffle_Sap +11523,2000,612 //Yellow_Raffle_Sap +11524,3000,612 //White_Raffle_Sap + +// SC_REUSE_LIMIT_F 614 +607,5000,613 //Yggdrasil_Berry + +// SC_REUSE_LIMIT_G 615 +608,3000,614 //Yggdrasil_Seed +22559,3000,614 //Mock_Strawberry + +// SC_REUSE_LIMIT_H 616 +11525,5000,615 //Mora_Hip_Tea + +// SC_REUSE_LIMIT_ASPD_POTION 617 +//12684,0,616 //ASPD_Potion //! CHECKME: Need confirmation! + +// SC_REUSE_LIMIT_MTF 618 +12658,10000,620 //Transformation Scroll(Deviruchi) +12659,10000,620 //Transformation Scroll(Raydric) +12660,10000,620 //Transformation Scroll(Mavka) +12661,10000,620 //Transformation Scroll(Marduk) +12662,10000,620 //Transformation Scroll(Banshee) +12663,10000,620 //Transformation Scroll(Poring) +12664,10000,620 //Transformation Scroll(Golem) + +// SC_ALL_RIDING_REUSE_LIMIT 619 +12622,3000,621 //Boarding_Halter + +// SC_SEARCH_STORE_INFO 620 +12580,0,624 //Vending_Search_Scroll +12581,0,624 //Vending_Search_Scroll2 +12591,0,624 //Uni_Catalog_Bz + +// SC_REUSE_MILLENNIUMSHIELD 621 +12727,60000,625 //Runstone_Verkana + +// SC_REUSE_CRUSHSTRIKE 622 +12726,30000,626 //Runstone_Rhydo + +// SC_REUSE_STORMBLAST 623 +12732,1000,627 //Runstone_Pertz + +// Misc //12202,60000 //Str_Dish10_ //12203,60000 //Agi_Dish10_ //12204,60000 //Int_Dish10_ //12205,60000 //Dex_Dish10_ //12206,60000 //Luk_Dish10_ //12207,60000 //Vit_Dish10_ -12208,60000 //Battle_Manual -12210,60000 //Bubble_Gum -14538,300000 //Glass_Of_Illusion -607,5000 //Yggdrasil_Berry -608,3000 //Yggdrasil_Seed - -// Bifrost Items -11522,1000 //Red_Raffle_Sap -11523,2000 //Yellow_Raffle_Sap -11524,3000 //White_Raffle_Sap -11525,5000 //Mora_Hip_Tea - -12658,10000 //Transformation Scroll(Deviruchi) -12659,10000 //Transformation Scroll(Raydric) -12660,10000 //Transformation Scroll(Mavka) -12661,10000 //Transformation Scroll(Marduk) -12662,10000 //Transformation Scroll(Banshee) -12663,10000 //Transformation Scroll(Poring) -12664,10000 //Transformation Scroll(Golem) - -// FIX ME! Delays need confirmation. -12968,300000 //Emergency_Scroll1 -12969,300000 //Emergency_Scroll2 -12970,300000 //Emergency_Scroll3 - -12596,300000 //Magic_Candy -14586,300000 //Spark_Candy +12968,300000 //Emergency_Scroll1 //! CHECKME: Need confirmation! +12969,300000 //Emergency_Scroll2 //! CHECKME: Need confirmation! +12970,300000 //Emergency_Scroll3 //! CHECKME: Need confirmation! +22508,7200000 //Para_Team_Mark_ diff --git a/sql-files/item_db_re.sql b/sql-files/item_db_re.sql index 9d7f34519a..8059bdccdd 100644 --- a/sql-files/item_db_re.sql +++ b/sql-files/item_db_re.sql @@ -6587,7 +6587,7 @@ REPLACE INTO `item_db_re` VALUES (12680,'Sg_Blue_Potion_Box','Siege Blue Potion REPLACE INTO `item_db_re` VALUES (12681,'Nestea_Lemon','Nestea Lemon',2,0,NULL,50,NULL,NULL,NULL,NULL,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); REPLACE INTO `item_db_re` VALUES (12682,'Nestea_Blacktea','Nestea Black Tea',2,0,NULL,30,NULL,NULL,NULL,NULL,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); REPLACE INTO `item_db_re` VALUES (12683,'Sg_Vi_Potion_Box200','Siege Violet Potion Box (200)',2,20,NULL,200,NULL,NULL,NULL,NULL,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'getitem 11547,200;',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (12684,'ASPD_Potion','ASPD Potion',2,0,NULL,10,NULL,NULL,NULL,NULL,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); +REPLACE INTO `item_db_re` VALUES (12684,'ASPD_Potion','ASPD Potion',2,0,NULL,10,NULL,NULL,NULL,NULL,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'sc_start SC_HASTEATTACK_CASH,900000,3;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (12685,'Gryphon_Egg_Scroll','Gryphon Egg Scroll',2,20,NULL,10,NULL,NULL,NULL,NULL,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); REPLACE INTO `item_db_re` VALUES (12686,'Str_Dish20','Str Dish20',2,0,NULL,10,NULL,NULL,NULL,NULL,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); REPLACE INTO `item_db_re` VALUES (12687,'Int_Dish20','Int Dish20',2,0,NULL,10,NULL,NULL,NULL,NULL,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); @@ -9914,7 +9914,7 @@ REPLACE INTO `item_db_re` VALUES (22059,'Aegir_Shoes','Aegir Shoes',4,10,NULL,30 REPLACE INTO `item_db_re` VALUES (22064,'Thorny_Shoes','Thorny Shoes',4,0,NULL,1000,NULL,25,NULL,1,0xFFFFFFFF,63,2,64,NULL,NULL,1,NULL,'bonus bShortWeaponDamageReturn,getrefine()/2;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (22067,'Shoe_of_Witch','Shoe of Witch',4,10,NULL,400,NULL,10,NULL,0,0xFFFFFFFE,63,2,64,NULL,'1',1,NULL,'skill "ALL_CATCRY",1,1;',NULL,NULL); # -REPLACE INTO `item_db_re` VALUES (22508,'Para_Team_Mark_','Eden Group Mark',11,0,NULL,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); +REPLACE INTO `item_db_re` VALUES (22508,'Para_Team_Mark_','Eden Group Mark',11,0,NULL,0,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'/*itemskill "AL_TELEPORT",3;*/ unitskilluseid getcharid(3),"AL_TELEPORT",3;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (22507,'Worn-Out-Scroll','Worn-Out-Scroll',3,10,NULL,10,NULL,NULL,NULL,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); REPLACE INTO `item_db_re` VALUES (22510,'King_Wolf_Scroll','King Wolf Scroll',2,10,NULL,10,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'/*TODO, confirm the rates*/ getitem callfunc("F_Rand",6635,19598,5658,6238,6239),1;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (22513,'King_of_Gift_Box','King of Gift Box',2,10,NULL,100,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'/*TODO, confirm the rates*/ getitem callfunc("F_Rand",12817,4403,14512),1;',NULL,NULL); diff --git a/src/map/clif.h b/src/map/clif.h index aaf0c03e42..9fe96aa3b0 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -428,6 +428,7 @@ enum clif_messages { ITEM_PRODUCE_SUCCESS = 0x627, ITEM_PRODUCE_FAIL = 0x628, ITEM_UNIDENTIFIED = 0x62d, + ITEM_REUSE_LIMIT = 0x746, USAGE_FAIL = 0x783, NEED_REINS_OF_MOUNT = 0x78c, }; diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 344547665f..8be066f49c 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -786,6 +786,11 @@ static bool itemdb_read_itemdelay(char* str[], int columns, int current) { id->delay = delay; + if (columns == 2) + id->delay_sc = SC_NONE; + else + id->delay_sc = (sc_type)atoi(str[2]); + return true; } @@ -1602,7 +1607,7 @@ static void itemdb_read(void) { itemdb_read_combos(dbsubpath2,i); //TODO change this to sv_read ? id#script ? sv_readdb(dbsubpath2, "item_noequip.txt", ',', 2, 2, -1, &itemdb_read_noequip, i); sv_readdb(dbsubpath2, "item_trade.txt", ',', 3, 3, -1, &itemdb_read_itemtrade, i); - sv_readdb(dbsubpath2, "item_delay.txt", ',', 2, 2, -1, &itemdb_read_itemdelay, i); + sv_readdb(dbsubpath2, "item_delay.txt", ',', 2, 3, -1, &itemdb_read_itemdelay, i); sv_readdb(dbsubpath2, "item_buyingstore.txt", ',', 1, 1, -1, &itemdb_read_buyingstore, i); sv_readdb(dbsubpath2, "item_flag.txt", ',', 2, 2, -1, &itemdb_read_flag, i); aFree(dbsubpath1); diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 34e8e56137..79d3b81805 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -450,6 +450,7 @@ struct item_data /* bugreport:309 */ struct item_combo **combos; unsigned char combos_count; + enum sc_type delay_sc; ///< Use delay group if any instead using player's item_delay data [Cydh] }; struct item_data* itemdb_searchname(const char *name); diff --git a/src/map/pc.c b/src/map/pc.c index 41bb709a8e..5dc5a8c765 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -4768,41 +4768,8 @@ int pc_useitem(struct map_session_data *sd,int n) if( id->flag.delay_consume && ( sd->ud.skilltimer != INVALID_TIMER /*|| !status_check_skilluse(&sd->bl, &sd->bl, ALL_RESURRECTION, 0)*/ ) ) return 0; - if( id->delay > 0 && !pc_has_permission(sd,PC_PERM_ITEM_UNCONDITIONAL) ) { - int i; - ARR_FIND(0, MAX_ITEMDELAYS, i, sd->item_delay[i].nameid == nameid ); - if( i == MAX_ITEMDELAYS ) /* item not found. try first empty now */ - ARR_FIND(0, MAX_ITEMDELAYS, i, !sd->item_delay[i].nameid ); - if( i < MAX_ITEMDELAYS ) { - if( sd->item_delay[i].nameid ) {// found - if( DIFF_TICK(sd->item_delay[i].tick, tick) > 0 ) { - int e_tick = DIFF_TICK(sd->item_delay[i].tick, tick)/1000; - char e_msg[CHAT_SIZE_MAX]; - if( e_tick > 99 ) - sprintf(e_msg,msg_txt(sd,379), // Item Failed. [%s] is cooling down. Wait %.1f minutes. - itemdb_jname(sd->item_delay[i].nameid), (double)e_tick / 60); - else - sprintf(e_msg,msg_txt(sd,380), // Item Failed. [%s] is cooling down. Wait %d seconds. - itemdb_jname(sd->item_delay[i].nameid), e_tick+1); - clif_colormes(sd->fd,color_table[COLOR_YELLOW],e_msg); - return 0; // Delay has not expired yet - } - } else {// not yet used item (all slots are initially empty) - sd->item_delay[i].nameid = nameid; - } - if( !(nameid == ITEMID_REINS_OF_MOUNT && sd->sc.option&(OPTION_WUGRIDER|OPTION_RIDING|OPTION_DRAGON|OPTION_MADOGEAR)) ) - sd->item_delay[i].tick = tick + sd->inventory_data[n]->delay; - } else {// should not happen - ShowError("pc_useitem: Exceeded item delay array capacity! (nameid=%hu, char_id=%d)\n", nameid, sd->status.char_id); - } - //clean up used delays so we can give room for more - for(i = 0; i < MAX_ITEMDELAYS; i++) { - if( DIFF_TICK(sd->item_delay[i].tick, tick) <= 0 ) { - sd->item_delay[i].tick = 0; - sd->item_delay[i].nameid = 0; - } - } - } + if( id->delay > 0 && !pc_has_permission(sd,PC_PERM_ITEM_UNCONDITIONAL) && pc_itemcd_check(sd, id, tick, n)) + return 0; /* on restricted maps the item is consumed but the effect is not used */ if (!pc_has_permission(sd,PC_PERM_ITEM_UNCONDITIONAL) && itemdb_isNoEquip(id,sd->bl.m)) { @@ -10967,13 +10934,14 @@ int pc_read_motd(void) return 0; } + void pc_itemcd_do(struct map_session_data *sd, bool load) { int i,cursor = 0; struct item_cd* cd = NULL; if( load ) { if( !(cd = idb_get(itemcd_db, sd->status.char_id)) ) { - // no skill cooldown is associated with this character + // no item cooldown is associated with this character return; } for(i = 0; i < MAX_ITEMDELAYS; i++) { @@ -11001,6 +10969,82 @@ void pc_itemcd_do(struct map_session_data *sd, bool load) { return; } +/** + * Add item delay to player's item delay data + * @param sd Player + * @param id Item data + * @param tick Current tick + * @param n Item index in inventory + * @return 0: No delay, can consume item. + * 1: Has delay, cancel consumption. + **/ +uint8 pc_itemcd_add(struct map_session_data *sd, struct item_data *id, unsigned int tick, unsigned short n) { + int i; + ARR_FIND(0, MAX_ITEMDELAYS, i, sd->item_delay[i].nameid == id->nameid ); + if( i == MAX_ITEMDELAYS ) /* item not found. try first empty now */ + ARR_FIND(0, MAX_ITEMDELAYS, i, !sd->item_delay[i].nameid ); + if( i < MAX_ITEMDELAYS ) { + if( sd->item_delay[i].nameid ) {// found + if( DIFF_TICK(sd->item_delay[i].tick, tick) > 0 ) { + int e_tick = DIFF_TICK(sd->item_delay[i].tick, tick)/1000; + char e_msg[CHAT_SIZE_MAX]; + if( e_tick > 99 ) + sprintf(e_msg,msg_txt(sd,379), // Item Failed. [%s] is cooling down. Wait %.1f minutes. + itemdb_jname(sd->item_delay[i].nameid), (double)e_tick / 60); + else + sprintf(e_msg,msg_txt(sd,380), // Item Failed. [%s] is cooling down. Wait %d seconds. + itemdb_jname(sd->item_delay[i].nameid), e_tick+1); + clif_colormes(sd->fd,color_table[COLOR_YELLOW],e_msg); + return 1; // Delay has not expired yet + } + } else {// not yet used item (all slots are initially empty) + sd->item_delay[i].nameid = id->nameid; + } + if( !(id->nameid == ITEMID_REINS_OF_MOUNT && sd->sc.option&(OPTION_WUGRIDER|OPTION_RIDING|OPTION_DRAGON|OPTION_MADOGEAR)) ) + sd->item_delay[i].tick = tick + sd->inventory_data[n]->delay; + } else {// should not happen + ShowError("pc_itemcd_add: Exceeded item delay array capacity! (nameid=%hu, char_id=%d)\n", id->nameid, sd->status.char_id); + } + //clean up used delays so we can give room for more + for(i = 0; i < MAX_ITEMDELAYS; i++) { + if( DIFF_TICK(sd->item_delay[i].tick, tick) <= 0 ) { + sd->item_delay[i].tick = 0; + sd->item_delay[i].nameid = 0; + } + } + return 0; +} + +/** + * Check if player has delay to reuse item + * @param sd Player + * @param id Item data + * @param tick Current tick + * @param n Item index in inventory + * @return 0: No delay, can consume item. + * 1: Has delay, cancel consumption. + **/ +uint8 pc_itemcd_check(struct map_session_data *sd, struct item_data *id, unsigned int tick, unsigned short n) { + struct status_change *sc = NULL; + + nullpo_retr(0, sd); + nullpo_retr(0, id); + + // Do normal delay assignment + if (id->delay_sc <= SC_NONE || id->delay_sc >= SC_MAX || !(sc = &sd->sc)) + return pc_itemcd_add(sd, id, tick, n); + + // Send reply of delay remains + if (sc->data[id->delay_sc]) { + const struct TimerData *timer = get_timer(sc->data[id->delay_sc]->timer); + clif_msg_value(sd, ITEM_REUSE_LIMIT, timer ? DIFF_TICK(timer->tick, tick) / 1000 : 99); + return 1; + } + + sc_start(&sd->bl, &sd->bl, id->delay_sc, 100, id->nameid, id->delay); + return 0; +} + /** * Clear the dmglog data from player * @param sd diff --git a/src/map/pc.h b/src/map/pc.h index 50f615be91..52fbed4494 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -1153,6 +1153,8 @@ void pc_overheat(struct map_session_data *sd, int val); int pc_banding(struct map_session_data *sd, uint16 skill_lv); void pc_itemcd_do(struct map_session_data *sd, bool load); +uint8 pc_itemcd_add(struct map_session_data *sd, struct item_data *id, unsigned int tick, unsigned short n); +uint8 pc_itemcd_check(struct map_session_data *sd, struct item_data *id, unsigned int tick, unsigned short n); int pc_load_combo(struct map_session_data *sd); diff --git a/src/map/script.c b/src/map/script.c index 45e5b3a794..7e6e696684 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -10575,6 +10575,12 @@ BUILDIN_FUNC(sc_end) case SC_MTF_MSP: case SC_MTF_PUMPKIN: case SC_MTF_HITFLEE: + case SC_ATTHASTE_CASH: + case SC_REUSE_LIMIT_A: case SC_REUSE_LIMIT_B: case SC_REUSE_LIMIT_C: + case SC_REUSE_LIMIT_D: case SC_REUSE_LIMIT_E: case SC_REUSE_LIMIT_F: + case SC_REUSE_LIMIT_G: case SC_REUSE_LIMIT_H: case SC_REUSE_LIMIT_MTF: + case SC_REUSE_LIMIT_ASPD_POTION: case SC_REUSE_MILLENNIUMSHIELD: case SC_REUSE_CRUSHSTRIKE: + case SC_REUSE_STORMBLAST: case SC_ALL_RIDING_REUSE_LIMIT: case SC_REUSE_REFRESH: return 0; default: break; diff --git a/src/map/skill.c b/src/map/skill.c index ea4def6e10..9a16bc842b 100755 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -1700,6 +1700,12 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1 case SC_MTF_ASPD2: case SC_MTF_RANGEATK2: case SC_MTF_MATK2: case SC_2011RWC_SCROLL: case SC_JP_EVENT04: case SC_MTF_MHP: case SC_MTF_MSP: case SC_MTF_PUMPKIN: case SC_MTF_HITFLEE: + case SC_ATTHASTE_CASH: case SC_REUSE_REFRESH: + case SC_REUSE_LIMIT_A: case SC_REUSE_LIMIT_B: case SC_REUSE_LIMIT_C: + case SC_REUSE_LIMIT_D: case SC_REUSE_LIMIT_E: case SC_REUSE_LIMIT_F: + case SC_REUSE_LIMIT_G: case SC_REUSE_LIMIT_H: case SC_REUSE_LIMIT_MTF: + case SC_REUSE_LIMIT_ASPD_POTION: case SC_REUSE_MILLENNIUMSHIELD: case SC_REUSE_CRUSHSTRIKE: + case SC_REUSE_STORMBLAST: case SC_ALL_RIDING_REUSE_LIMIT: continue; case SC_WHISTLE: case SC_ASSNCROS: case SC_POEMBRAGI: case SC_APPLEIDUN: case SC_HUMMING: case SC_DONTFORGETME: @@ -7440,6 +7446,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SC_MTF_ASPD2: case SC_MTF_RANGEATK2: case SC_MTF_MATK2: case SC_2011RWC_SCROLL: case SC_JP_EVENT04: case SC_MTF_MHP: case SC_MTF_MSP: case SC_MTF_PUMPKIN: case SC_MTF_HITFLEE: + case SC_ATTHASTE_CASH: case SC_REUSE_REFRESH: + case SC_REUSE_LIMIT_A: case SC_REUSE_LIMIT_B: case SC_REUSE_LIMIT_C: + case SC_REUSE_LIMIT_D: case SC_REUSE_LIMIT_E: case SC_REUSE_LIMIT_F: + case SC_REUSE_LIMIT_G: case SC_REUSE_LIMIT_H: case SC_REUSE_LIMIT_MTF: + case SC_REUSE_LIMIT_ASPD_POTION: case SC_REUSE_MILLENNIUMSHIELD: case SC_REUSE_CRUSHSTRIKE: + case SC_REUSE_STORMBLAST: case SC_ALL_RIDING_REUSE_LIMIT: continue; //bugreport:4888 these songs may only be dispelled if you're not in their song area anymore case SC_WHISTLE: @@ -8922,6 +8934,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SC_MTF_ASPD2: case SC_MTF_RANGEATK2: case SC_MTF_MATK2: case SC_2011RWC_SCROLL: case SC_JP_EVENT04: case SC_MTF_MHP: case SC_MTF_MSP: case SC_MTF_PUMPKIN: case SC_MTF_HITFLEE: + case SC_ATTHASTE_CASH: case SC_REUSE_REFRESH: + case SC_REUSE_LIMIT_A: case SC_REUSE_LIMIT_B: case SC_REUSE_LIMIT_C: + case SC_REUSE_LIMIT_D: case SC_REUSE_LIMIT_E: case SC_REUSE_LIMIT_F: + case SC_REUSE_LIMIT_G: case SC_REUSE_LIMIT_H: case SC_REUSE_LIMIT_MTF: + case SC_REUSE_LIMIT_ASPD_POTION: case SC_REUSE_MILLENNIUMSHIELD: case SC_REUSE_CRUSHSTRIKE: + case SC_REUSE_STORMBLAST: case SC_ALL_RIDING_REUSE_LIMIT: continue; case SC_ASSUMPTIO: if( bl->type == BL_MOB ) diff --git a/src/map/status.c b/src/map/status.c index fe68caffe2..272b8bea24 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -886,6 +886,7 @@ void initChangeTables(void) StatusIconChangeTable[SC_L_LIFEPOTION] = SI_L_LIFEPOTION; StatusIconChangeTable[SC_SPCOST_RATE] = SI_ATKER_BLOOD; StatusIconChangeTable[SC_COMMONSC_RESIST] = SI_TARGET_BLOOD; + StatusIconChangeTable[SC_ATTHASTE_CASH] = SI_ATTHASTE_CASH; /* Mercenary Bonus Effects */ StatusIconChangeTable[SC_MERC_FLEEUP] = SI_MERC_FLEEUP; @@ -1007,6 +1008,23 @@ void initChangeTables(void) StatusIconChangeTable[SC_MTF_MSP] = SI_MTF_MSP; StatusIconChangeTable[SC_MTF_PUMPKIN] = SI_MTF_PUMPKIN; + // Item Reuse Limits + StatusIconChangeTable[SC_REUSE_REFRESH] = SI_REUSE_REFRESH; + StatusIconChangeTable[SC_REUSE_LIMIT_A] = SI_REUSE_LIMIT_A; + StatusIconChangeTable[SC_REUSE_LIMIT_B] = SI_REUSE_LIMIT_B; + StatusIconChangeTable[SC_REUSE_LIMIT_C] = SI_REUSE_LIMIT_C; + StatusIconChangeTable[SC_REUSE_LIMIT_D] = SI_REUSE_LIMIT_D; + StatusIconChangeTable[SC_REUSE_LIMIT_E] = SI_REUSE_LIMIT_E; + StatusIconChangeTable[SC_REUSE_LIMIT_F] = SI_REUSE_LIMIT_F; + StatusIconChangeTable[SC_REUSE_LIMIT_G] = SI_REUSE_LIMIT_G; + StatusIconChangeTable[SC_REUSE_LIMIT_H] = SI_REUSE_LIMIT_H; + StatusIconChangeTable[SC_REUSE_LIMIT_MTF] = SI_REUSE_LIMIT_MTF; + StatusIconChangeTable[SC_REUSE_LIMIT_ASPD_POTION] = SI_REUSE_LIMIT_ASPD_POTION; + StatusIconChangeTable[SC_REUSE_MILLENNIUMSHIELD] = SI_REUSE_MILLENNIUMSHIELD; + StatusIconChangeTable[SC_REUSE_CRUSHSTRIKE] = SI_REUSE_CRUSHSTRIKE; + StatusIconChangeTable[SC_REUSE_STORMBLAST] = SI_REUSE_STORMBLAST; + StatusIconChangeTable[SC_ALL_RIDING_REUSE_LIMIT] = SI_ALL_RIDING_REUSE_LIMIT; + /* Other SC which are not necessarily associated to skills */ StatusChangeFlagTable[SC_ASPDPOTION0] |= SCB_ASPD; StatusChangeFlagTable[SC_ASPDPOTION1] |= SCB_ASPD; @@ -1064,6 +1082,7 @@ void initChangeTables(void) StatusChangeFlagTable[SC_FOOD_DEX_CASH] |= SCB_DEX; StatusChangeFlagTable[SC_FOOD_INT_CASH] |= SCB_INT; StatusChangeFlagTable[SC_FOOD_LUK_CASH] |= SCB_LUK; + StatusChangeFlagTable[SC_ATTHASTE_CASH] |= SCB_ASPD; /* Mercenary Bonus Effects */ StatusChangeFlagTable[SC_MERC_FLEEUP] |= SCB_FLEE; @@ -6255,6 +6274,9 @@ static short status_calc_aspd(struct block_list *bl, struct status_change *sc, s sc->data[i=SC_ASPDPOTION0]) pots += sc->data[i]->val1; + if (sc->data[SC_ATTHASTE_CASH]) + pots += sc->data[SC_ATTHASTE_CASH]->val1; + if( !sc->data[SC_QUAGMIRE] ) { if(sc->data[SC_TWOHANDQUICKEN] && skills1 < 7) skills1 = 7; @@ -6478,6 +6500,9 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * sc->data[i=SC_ASPDPOTION0] ) aspd_rate -= sc->data[i]->val2; + if (sc->data[SC_ATTHASTE_CASH]) + aspd_rate -= sc->data[SC_ATTHASTE_CASH]->val2; + if(sc->data[SC_DONTFORGETME]) aspd_rate += sc->data[SC_DONTFORGETME]->val2; if(sc->data[SC_LONGING]) @@ -8539,6 +8564,21 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC__WEAKNESS: case SC__UNLUCKY: //case SC__CHAOS: + case SC_REUSE_REFRESH: + case SC_REUSE_LIMIT_A: + case SC_REUSE_LIMIT_B: + case SC_REUSE_LIMIT_C: + case SC_REUSE_LIMIT_D: + case SC_REUSE_LIMIT_E: + case SC_REUSE_LIMIT_F: + case SC_REUSE_LIMIT_G: + case SC_REUSE_LIMIT_H: + case SC_REUSE_LIMIT_MTF: + case SC_REUSE_LIMIT_ASPD_POTION: + case SC_REUSE_MILLENNIUMSHIELD: + case SC_REUSE_CRUSHSTRIKE: + case SC_REUSE_STORMBLAST: + case SC_ALL_RIDING_REUSE_LIMIT: return 0; case SC_COMBO: case SC_DANCING: @@ -8552,6 +8592,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty case SC_ENCHANTARMS: case SC_ARMOR_ELEMENT: case SC_ARMOR_RESIST: + case SC_ATTHASTE_CASH: break; case SC_GOSPEL: // Must not override a casting gospel char. @@ -8841,6 +8882,10 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty val2 = 50*(2+type-SC_ASPDPOTION0); break; + case SC_ATTHASTE_CASH: + val2 = 50*val1; // Just custom for pre-re + break; + case SC_NOCHAT: // A hardcoded interval of 60 seconds is expected, as the time that SC_NOCHAT uses is defined by // mmocharstatus.manner, each negative point results in 1 minute with this status activated. @@ -10771,6 +10816,22 @@ int status_change_clear(struct block_list* bl, int type) case SC_QUEST_BUFF3: case SC_2011RWC_SCROLL: case SC_JP_EVENT04: + case SC_ATTHASTE_CASH: + case SC_REUSE_REFRESH: + case SC_REUSE_LIMIT_A: + case SC_REUSE_LIMIT_B: + case SC_REUSE_LIMIT_C: + case SC_REUSE_LIMIT_D: + case SC_REUSE_LIMIT_E: + case SC_REUSE_LIMIT_F: + case SC_REUSE_LIMIT_G: + case SC_REUSE_LIMIT_H: + case SC_REUSE_LIMIT_MTF: + case SC_REUSE_LIMIT_ASPD_POTION: + case SC_REUSE_MILLENNIUMSHIELD: + case SC_REUSE_CRUSHSTRIKE: + case SC_REUSE_STORMBLAST: + case SC_ALL_RIDING_REUSE_LIMIT: continue; } } @@ -12652,6 +12713,22 @@ void status_change_clear_buffs (struct block_list* bl, int type) case SC_MTF_MSP: case SC_MTF_PUMPKIN: case SC_MTF_HITFLEE: + case SC_ATTHASTE_CASH: + case SC_REUSE_REFRESH: + case SC_REUSE_LIMIT_A: + case SC_REUSE_LIMIT_B: + case SC_REUSE_LIMIT_C: + case SC_REUSE_LIMIT_D: + case SC_REUSE_LIMIT_E: + case SC_REUSE_LIMIT_F: + case SC_REUSE_LIMIT_G: + case SC_REUSE_LIMIT_H: + case SC_REUSE_LIMIT_MTF: + case SC_REUSE_LIMIT_ASPD_POTION: + case SC_REUSE_MILLENNIUMSHIELD: + case SC_REUSE_CRUSHSTRIKE: + case SC_REUSE_STORMBLAST: + case SC_ALL_RIDING_REUSE_LIMIT: continue; // Debuffs that can be removed. diff --git a/src/map/status.h b/src/map/status.h index a8f2bd2d66..eb96f48572 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -716,6 +716,23 @@ typedef enum sc_type { SC_MTF_HITFLEE, SC_CRIFOOD, + SC_ATTHASTE_CASH, + + // Item Reuse Limits + SC_REUSE_LIMIT_A, + SC_REUSE_LIMIT_B, + SC_REUSE_LIMIT_C, + SC_REUSE_LIMIT_D, + SC_REUSE_LIMIT_E, + SC_REUSE_LIMIT_F, + SC_REUSE_LIMIT_G, + SC_REUSE_LIMIT_H, + SC_REUSE_LIMIT_MTF, + SC_REUSE_LIMIT_ASPD_POTION, + SC_REUSE_MILLENNIUMSHIELD, + SC_REUSE_CRUSHSTRIKE, + SC_REUSE_STORMBLAST, + SC_ALL_RIDING_REUSE_LIMIT, #ifdef RENEWAL SC_EXTREMITYFIST2, //! NOTE: This SC should be right before SC_MAX, so it doesn't disturb if RENEWAL is disabled @@ -1029,14 +1046,14 @@ enum si_type { SI_ATKER_BLOOD = 300, SI_TARGET_BLOOD = 301, SI_ARMOR_PROPERTY = 302, -// SI_REUSE_LIMIT_A = 303, + SI_REUSE_LIMIT_A = 303, SI_HELLPOWER = 304, SI_STEAMPACK = 305, -// SI_REUSE_LIMIT_B = 306, -// SI_REUSE_LIMIT_C = 307, -// SI_REUSE_LIMIT_D = 308, -// SI_REUSE_LIMIT_E = 309, -// SI_REUSE_LIMIT_F = 310, + SI_REUSE_LIMIT_B = 306, + SI_REUSE_LIMIT_C = 307, + SI_REUSE_LIMIT_D = 308, + SI_REUSE_LIMIT_E = 309, + SI_REUSE_LIMIT_F = 310, SI_INVINCIBLE = 311, SI_CASH_PLUSONLYJOBEXP = 312, SI_PARTYFLEE = 313,