From 19e25a2d18164ede743c79aba0c92b20ac17bdca Mon Sep 17 00:00:00 2001 From: shennetsind Date: Sun, 30 Jun 2013 15:34:50 -0300 Subject: Fixed Skill Cooldowns Special Thanks to Vylow for bringing this to our attention. Also added support for the client-side cooldown left/total feature (packetver 20120604 and newer) Made Possible Thanks to Yommy =3 Signed-off-by: shennetsind --- src/common/mmo.h | 3 +++ src/map/battleground.c | 6 ++--- src/map/clif.c | 36 ++++++++++++++++++++++++++++ src/map/clif.h | 2 ++ src/map/map.c | 1 + src/map/pc.h | 6 ++--- src/map/skill.c | 65 ++++++++++++++++++++++++++++++++++---------------- src/map/skill.h | 19 +++++++++++++++ 8 files changed, 111 insertions(+), 27 deletions(-) diff --git a/src/common/mmo.h b/src/common/mmo.h index 6e5dae099..17caf917a 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -92,6 +92,9 @@ #define MAX_CART 100 #define MAX_SKILL 1478 #define MAX_SKILL_ID 10015 // [Ind/Hercules] max used skill ID +//Update this max as necessary. 55 is the value needed for Super Baby currently +//Raised to 84 since Expanded Super Novice needs it. +#define MAX_SKILL_TREE 84 #define GLOBAL_REG_NUM 256 // Max permanent character variables per char #define ACCOUNT_REG_NUM 64 // Max permanent local account variables per account #define ACCOUNT_REG2_NUM 16 // Max permanent global account variables per account diff --git a/src/map/battleground.c b/src/map/battleground.c index d54178347..3f0b9ee41 100644 --- a/src/map/battleground.c +++ b/src/map/battleground.c @@ -255,7 +255,7 @@ void bg_config_read(void) { config_setting_t *settings = config_setting_get_elem(data, 0); config_setting_t *arenas; const char *delay_var; - int i, arena_count = 0, total = 0, offline = 0; + int i, arena_count = 0, offline = 0; if( !config_setting_lookup_string(settings, "global_delay_var", &delay_var) ) delay_var = "BG_Delay_Tick"; @@ -391,13 +391,11 @@ void bg_config_read(void) { bg->arena[i]->fillup_timer = INVALID_TIMER; bg->arena[i]->pregame_duration = pregame_duration; bg->arena[i]->fillup_duration = fillup_duration; - - total++; + } bg->arenas = arena_count; } - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' arenas in '"CL_WHITE"%s"CL_RESET"'.\n", total, config_filename); config_destroy(&bg_conf); } } diff --git a/src/map/clif.c b/src/map/clif.c index 373d510ba..0ad6fbd44 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -17478,6 +17478,41 @@ void clif_package_item_announce(struct map_session_data *sd, unsigned short name clif->send(&p,sizeof(p), &sd->bl, ALL_CLIENT); } +/* [Ind/Hercules] special thanks to Yommy~! */ +void clif_skill_cooldown_list(int fd, struct skill_cd* cd) { +#if PACKETVER >= 20120604 + const int offset = 10; +#else + const int offset = 6; +#endif + int i, count = 0; + + WFIFOHEAD(fd,4+(offset*cd->cursor)); + +#if PACKETVER >= 20120604 + WFIFOW(fd,0) = 0x985; +#else + WFIFOW(fd,0) = 0x43e; +#endif + + for( i = 0; i < cd->cursor; i++ ) { + if( cd->duration[i] < 1 ) continue; +#if PACKETVER >= 20120604 + WFIFOW(fd, 4 + (i*10)) = cd->nameid[i]; + WFIFOL(fd, 6 + (i*10)) = cd->total[i]; + WFIFOL(fd, 10 + (i*10)) = cd->duration[i]; +#else + WFIFOW(fd, 4 + (i*6)) = cd->nameid[i]; + WFIFOL(fd, 6 + (i*6)) = cd->duration[i]; +#endif + count++; + } + + WFIFOW(fd,2) = 4+(offset*count); + + WFIFOSET(fd,4+(offset*count)); +} + /* */ unsigned short clif_decrypt_cmd( int cmd, struct map_session_data *sd ) { if( sd ) { @@ -17944,6 +17979,7 @@ void clif_defaults(void) { clif->sc_load = clif_status_change2; clif->sc_end = clif_status_change_end; clif->initialstatus = clif_initialstatus; + clif->cooldown_list = clif_skill_cooldown_list; /* player-unit-specific-related */ clif->updatestatus = clif_updatestatus; clif->changestatus = clif_changestatus; diff --git a/src/map/clif.h b/src/map/clif.h index 81376db15..c23db873e 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -38,6 +38,7 @@ struct quest; struct party_booking_ad_info; struct view_data; struct eri; +struct skill_cd; /** * Defines @@ -632,6 +633,7 @@ struct clif_interface { void (*sc_load) (struct block_list *bl, int tid, enum send_target target, int type, int val1, int val2, int val3); void (*sc_end) (struct block_list *bl, int tid, enum send_target target, int type); void (*initialstatus) (struct map_session_data *sd); + void (*cooldown_list) (int fd, struct skill_cd* cd); /* player-unit-specific-related */ void (*updatestatus) (struct map_session_data *sd,int type); void (*changestatus) (struct map_session_data* sd,int type,int val); diff --git a/src/map/map.c b/src/map/map.c index 99f585a8d..389c031bd 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1647,6 +1647,7 @@ int map_quit(struct map_session_data *sd) { if( sd->bg_id ) bg_team_leave(sd,1); + skill->cooldown_save(sd); pc->itemcd_do(sd,false); for( i = 0; i < sd->queues_count; i++ ) { diff --git a/src/map/pc.h b/src/map/pc.h index 442b55965..8be2b7344 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -3,6 +3,7 @@ // Portions Copyright (c) Athena Dev Teams #ifndef _PC_H_ #define _PC_H_ + #include "../common/mmo.h" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus #include "../common/ers.h" #include "../common/timer.h" // INVALID_TIMER @@ -20,9 +21,11 @@ #include "mob.h" #include "log.h" #include "pc_groups.h" + #define MAX_PC_BONUS 10 #define MAX_PC_SKILL_REQUIRE 5 #define MAX_PC_FEELHATE 3 + //Equip indexes constants. (eg: sd->equip_index[EQI_AMMO] returns the index //where the arrows are equipped) enum equip_index { @@ -507,9 +510,6 @@ struct map_session_data { struct eri *pc_sc_display_ers; -//Update this max as necessary. 55 is the value needed for Super Baby currently -//Raised to 84 since Expanded Super Novice needs it. -#define MAX_SKILL_TREE 84 //Total number of classes (for data storage) #define CLASS_COUNT (JOB_MAX - JOB_NOVICE_HIGH + JOB_MAX_BASIC) diff --git a/src/map/skill.c b/src/map/skill.c index 8cb82e3a6..4bd27f578 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -63,20 +63,6 @@ static struct eri *skill_timer_ers = NULL; //For handling skill_timerskills [Sko DBMap* skillunit_db = NULL; // int id -> struct skill_unit* -/** - * Skill Cool Down Delay Saving - * Struct skill_cd is not a member of struct map_session_data - * to keep cooldowns in memory between player log-ins. - * All cooldowns are reset when server is restarted. - **/ -DBMap* skillcd_db = NULL; // char_id -> struct skill_cd -struct skill_cd { - int duration[MAX_SKILL_TREE];//milliseconds - short skidx[MAX_SKILL_TREE];//the skill index entries belong to - short nameid[MAX_SKILL_TREE];//skill id - unsigned char cursor; -}; - /** * Skill Unit Persistency during endack routes (mostly for songs see bugreport:4574) **/ @@ -8050,9 +8036,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui else if(bl->type == BL_PC) rate += 20 + 10 * skill_lv; // On Players, (20 + 10 * Skill Level) % else rate += 40 + 10 * skill_lv; // On Monsters, (40 + 10 * Skill Level) % - if( sd ) - skill->blockpc_start(sd,skill_id,4000, false); - if( !(tsc && tsc->data[type]) ){ i = sc_start2(bl,type,rate,skill_lv,src->id,(src == bl)?5000:(bl->type == BL_PC)?skill->get_time(skill_id,skill_lv):skill->get_time2(skill_id, skill_lv)); clif->skill_nodamage(src,bl,skill_id,skill_lv,i); @@ -16888,16 +16871,24 @@ int skill_blockpc_end(int tid, unsigned int tick, int id, intptr_t data) { int i,cursor; ARR_FIND( 0, cd->cursor+1, cursor, cd->skidx[cursor] == data ); cd->duration[cursor] = 0; +#if PACKETVER >= 20120604 + cd->total[cursor] = 0; +#endif cd->skidx[cursor] = 0; cd->nameid[cursor] = 0; + cd->started[cursor] = 0; // compact the cool down list for( i = 0, cursor = 0; i < cd->cursor; i++ ) { if( cd->duration[i] == 0 ) continue; if( cursor != i ) { cd->duration[cursor] = cd->duration[i]; +#if PACKETVER >= 20120604 + cd->total[cursor] = cd->total[i]; +#endif cd->skidx[cursor] = cd->skidx[i]; cd->nameid[cursor] = cd->nameid[i]; + cd->started[cursor] = cd->started[i]; } cursor++; } @@ -16933,7 +16924,7 @@ int skill_blockpc_start_(struct map_session_data *sd, uint16 skill_id, int tick, return -1; } - if( battle_config.display_status_timers ) + if( !load && battle_config.display_status_timers ) clif->skill_cooldown(sd, skill_id, tick); if( !load ) {// not being loaded initially so ensure the skill delay is recorded @@ -16944,8 +16935,12 @@ int skill_blockpc_start_(struct map_session_data *sd, uint16 skill_id, int tick, // record the skill duration in the database map cd->duration[cd->cursor] = tick; +#if PACKETVER >= 20120604 + cd->total[cd->cursor] = tick; +#endif cd->skidx[cd->cursor] = idx; cd->nameid[cd->cursor] = skill_id; + cd->started[cd->cursor] = iTimer->gettick(); cd->cursor++; } @@ -17437,14 +17432,38 @@ int skill_get_elemental_type( uint16 skill_id , uint16 skill_lv ) { return type; } +/** + * update stored skill cooldowns for player logout + * @param sd the affected player structure + */ +void skill_cooldown_save(struct map_session_data * sd) { + int i; + struct skill_cd* cd = NULL; + unsigned int now = 0; + + // always check to make sure the session properly exists + nullpo_retv(sd); + + if( !(cd = idb_get(skillcd_db, sd->status.char_id)) ) {// no skill cooldown is associated with this character + return; + } + + now = iTimer->gettick(); + + // process each individual cooldown associated with the character + for( i = 0; i < cd->cursor; i++ ) { + cd->duration[i] = DIFF_TICK(cd->started[i]+cd->duration[i],now); + } +} + /** * reload stored skill cooldowns when a player logs in. * @param sd the affected player structure */ -void skill_cooldown_load(struct map_session_data * sd) -{ +void skill_cooldown_load(struct map_session_data * sd) { int i; struct skill_cd* cd = NULL; + unsigned int now = 0; // always check to make sure the session properly exists nullpo_retv(sd); @@ -17453,8 +17472,13 @@ void skill_cooldown_load(struct map_session_data * sd) return; } + clif->cooldown_list(sd->fd,cd); + + now = iTimer->gettick(); + // process each individual cooldown associated with the character for( i = 0; i < cd->cursor; i++ ) { + cd->started[i] = now; // block the skill from usage but ensure it is not recorded (load = true) skill->blockpc_start( sd, cd->nameid[i], cd->duration[i], true ); } @@ -18145,5 +18169,6 @@ void skill_defaults(void) { skill->elementalanalysis = skill_elementalanalysis; skill->changematerial = skill_changematerial; skill->get_elemental_type = skill_get_elemental_type; + skill->cooldown_save = skill_cooldown_save; } diff --git a/src/map/skill.h b/src/map/skill.h index 921a682a2..338537975 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -1713,12 +1713,30 @@ struct s_skill_magicmushroom_db { }; extern struct s_skill_magicmushroom_db skill_magicmushroom_db[MAX_SKILL_MAGICMUSHROOM_DB]; +/** + * Skill Cool Down Delay Saving + * Struct skill_cd is not a member of struct map_session_data + * to keep cooldowns in memory between player log-ins. + * All cooldowns are reset when server is restarted. + **/ +struct skill_cd { + int duration[MAX_SKILL_TREE];//milliseconds +#if PACKETVER >= 20120604 + int total[MAX_SKILL_TREE]; +#endif + short skidx[MAX_SKILL_TREE];//the skill index entries belong to + short nameid[MAX_SKILL_TREE];//skill id + unsigned int started[MAX_SKILL_TREE]; + unsigned char cursor; +}; + /** * Vars **/ extern int enchant_eff[5]; extern int deluge_eff[5]; DBMap* skilldb_name2id; +DBMap* skillcd_db; // char_id -> struct skill_cd /** * Skill.c Interface @@ -1917,6 +1935,7 @@ struct skill_interface { int (*elementalanalysis) (struct map_session_data *sd, int n, uint16 skill_lv, unsigned short *item_list); int (*changematerial) (struct map_session_data *sd, int n, unsigned short *item_list); int (*get_elemental_type) (uint16 skill_id, uint16 skill_lv); + void (*cooldown_save) (struct map_session_data * sd); } skill_s; struct skill_interface *skill; -- cgit v1.2.3-70-g09d2