diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/console.c | 1 | ||||
-rw-r--r-- | src/common/sysinfo.c | 15 | ||||
-rw-r--r-- | src/common/sysinfo.h | 1 | ||||
-rw-r--r-- | src/common/timer.c | 64 | ||||
-rw-r--r-- | src/map/skill.c | 79 | ||||
-rw-r--r-- | src/map/status.c | 4 |
6 files changed, 142 insertions, 22 deletions
diff --git a/src/common/console.c b/src/common/console.c index f0702d0da..10e1bee1a 100644 --- a/src/common/console.c +++ b/src/common/console.c @@ -90,6 +90,7 @@ void display_title(void) { ShowInfo("CPU: '"CL_WHITE"%s [%d]"CL_RESET"'\n", sysinfo->cpu(), sysinfo->cpucores()); ShowInfo("Compiled with %s\n", sysinfo->compiler()); ShowInfo("Compile Flags: %s\n", sysinfo->cflags()); + ShowInfo("Timer Function Type: %s\n", sysinfo->time()); } /** diff --git a/src/common/sysinfo.c b/src/common/sysinfo.c index 7cc4cd16a..95f423ff7 100644 --- a/src/common/sysinfo.c +++ b/src/common/sysinfo.c @@ -38,6 +38,7 @@ #ifdef WIN32 # include <windows.h> #else +# include <sys/time.h> // time constants # include <unistd.h> #endif @@ -1052,6 +1053,19 @@ void sysinfo_final(void) { sysinfo->p->vcstype_name = NULL; } +static const char *sysinfo_time(void) +{ +#if defined(WIN32) + return "ticks count"; +#elif defined(ENABLE_RDTSC) + return "rdtsc"; +#elif defined(HAVE_MONOTONIC_CLOCK) + return "monotonic clock"; +#else + return "time of day"; +#endif +} + /** * Interface default values initialization. */ @@ -1072,6 +1086,7 @@ void sysinfo_defaults(void) { sysinfo->is64bit = sysinfo_is64bit; sysinfo->compiler = sysinfo_compiler; sysinfo->cflags = sysinfo_cflags; + sysinfo->time = sysinfo_time; sysinfo->vcstype = sysinfo_vcstype; sysinfo->vcstypeid = sysinfo_vcstypeid; sysinfo->vcsrevision_src = sysinfo_vcsrevision_src; diff --git a/src/common/sysinfo.h b/src/common/sysinfo.h index 904be832f..2a391bfa4 100644 --- a/src/common/sysinfo.h +++ b/src/common/sysinfo.h @@ -52,6 +52,7 @@ struct sysinfo_interface { bool (*is64bit) (void); const char *(*compiler) (void); const char *(*cflags) (void); + const char *(*time) (void); const char *(*vcstype) (void); int (*vcstypeid) (void); const char *(*vcsrevision_src) (void); diff --git a/src/common/timer.c b/src/common/timer.c index 7f71157ae..e7a57481a 100644 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -25,6 +25,7 @@ #include "common/cbasetypes.h" #include "common/db.h" #include "common/memmgr.h" +#include "common/nullpo.h" #include "common/showmsg.h" #include "common/utils.h" @@ -87,6 +88,8 @@ struct timer_func_list { int timer_add_func_list(TimerFunc func, char* name) { struct timer_func_list* tfl; + nullpo_ret(func); + nullpo_ret(name); if (name) { for( tfl=tfl_root; tfl != NULL; tfl=tfl->next ) {// check suspicious cases @@ -303,7 +306,19 @@ static int acquire_timer(void) { int timer_add(int64 tick, TimerFunc func, int id, intptr_t data) { int tid; + nullpo_retr(INVALID_TIMER, func); + tid = acquire_timer(); + if (timer_data[tid].type != 0 && timer_data[tid].type != TIMER_REMOVE_HEAP) + { + ShowError("timer_add error: wrong tid type: %d, [%d]%p(%s) -> %p(%s)\n", timer_data[tid].type, tid, func, search_timer_func_list(func), timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); + Assert_retr(INVALID_TIMER, 0); + } + if (timer_data[tid].func != NULL) + { + ShowError("timer_add error: func non NULL: [%d]%p(%s) -> %p(%s)\n", tid, func, search_timer_func_list(func), timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); + Assert_retr(INVALID_TIMER, 0); + } timer_data[tid].tick = tick; timer_data[tid].func = func; timer_data[tid].id = id; @@ -317,9 +332,11 @@ int timer_add(int64 tick, TimerFunc func, int id, intptr_t data) { /// Starts a new timer that automatically restarts itself (infinite loop until manually removed). /// Returns the timer's id, or INVALID_TIMER if it fails. -int timer_add_interval(int64 tick, TimerFunc func, int id, intptr_t data, int interval) { +int timer_add_interval(int64 tick, TimerFunc func, int id, intptr_t data, int interval) +{ int tid; + nullpo_retr(INVALID_TIMER, func); if (interval < 1) { ShowError("timer_add_interval: invalid interval (tick=%"PRId64" %p[%s] id=%d data=%"PRIdPTR" diff_tick=%"PRId64")\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, timer->gettick())); @@ -327,6 +344,18 @@ int timer_add_interval(int64 tick, TimerFunc func, int id, intptr_t data, int in } tid = acquire_timer(); + if (timer_data[tid].type != 0 && timer_data[tid].type != TIMER_REMOVE_HEAP) + { + ShowError("timer_add_interval: wrong tid type: %d, [%d]%p(%s) -> %p(%s)\n", timer_data[tid].type, tid, func, search_timer_func_list(func), timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); + Assert_retr(INVALID_TIMER, 0); + return INVALID_TIMER; + } + if (timer_data[tid].func != NULL) + { + ShowError("timer_add_interval: func non NULL: [%d]%p(%s) -> %p(%s)\n", tid, func, search_timer_func_list(func), timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); + Assert_retr(INVALID_TIMER, 0); + return INVALID_TIMER; + } timer_data[tid].tick = tick; timer_data[tid].func = func; timer_data[tid].id = id; @@ -346,16 +375,28 @@ const struct TimerData* timer_get(int tid) { /// Marks a timer specified by 'id' for immediate deletion once it expires. /// Param 'func' is used for debug/verification purposes. /// Returns 0 on success, < 0 on failure. -int timer_do_delete(int tid, TimerFunc func) { +int timer_do_delete(int tid, TimerFunc func) +{ + nullpo_ret(func); + if( tid < 0 || tid >= timer_data_num ) { - ShowError("timer_do_delete error : no such timer %d (%p(%s))\n", tid, func, search_timer_func_list(func)); + ShowError("timer_do_delete error : no such timer [%d](%p(%s))\n", tid, func, search_timer_func_list(func)); + Assert_retr(-1, 0); return -1; } if( timer_data[tid].func != func ) { - ShowError("timer_do_delete error : function mismatch %p(%s) != %p(%s)\n", timer_data[tid].func, search_timer_func_list(timer_data[tid].func), func, search_timer_func_list(func)); + ShowError("timer_do_delete error : function mismatch [%d]%p(%s) != %p(%s)\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func), func, search_timer_func_list(func)); + Assert_retr(-2, 0); return -2; } + if (timer_data[tid].type == 0 || timer_data[tid].type == TIMER_REMOVE_HEAP) + { + ShowError("timer_do_delete: timer already deleted: %d, [%d]%p(%s) -> %p(%s)\n", timer_data[tid].type, tid, func, search_timer_func_list(func), func, search_timer_func_list(func)); + Assert_retr(-3, 0); + return -3; + } + timer_data[tid].func = NULL; timer_data[tid].type = TIMER_ONCE_AUTODEL; @@ -383,7 +424,19 @@ int64 timer_settick(int tid, int64 tick) // search timer position ARR_FIND(0, BHEAP_LENGTH(timer_heap), i, BHEAP_DATA(timer_heap)[i] == tid); if (i == BHEAP_LENGTH(timer_heap)) { - ShowError("timer_settick: no such timer %d (%p(%s))\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); + ShowError("timer_settick: no such timer [%d](%p(%s))\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); + Assert_retr(-1, 0); + return -1; + } + + if (timer_data[tid].type == 0 || timer_data[tid].type == TIMER_REMOVE_HEAP) { + ShowError("timer_settick error: set tick for deleted timer %d, [%d](%p(%s))\n", timer_data[tid].type, tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); + Assert_retr(-1, 0); + return -1; + } + if (timer_data[tid].func == NULL) { + ShowError("timer_settick error: set tick for timer with wrong func [%d](%p(%s))\n", tid, timer_data[tid].func, search_timer_func_list(timer_data[tid].func)); + Assert_retr(-1, 0); return -1; } @@ -438,6 +491,7 @@ int do_timer(int64 tick) default: case TIMER_ONCE_AUTODEL: timer_data[tid].type = 0; + timer_data[tid].func = NULL; if (free_timer_list_pos >= free_timer_list_max) { free_timer_list_max += 256; RECREATE(free_timer_list,int,free_timer_list_max); diff --git a/src/map/skill.c b/src/map/skill.c index be899d0dc..c70b94cd5 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -11777,6 +11777,10 @@ int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick sc_start4(ss,bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit); break; case UNT_APPLEIDUN: + // If Aegis, apple of idun doesn't update its effect + if (!battle_config.song_timer_reset && sc && sce) + return 0; + // Let it fall through case UNT_WHISTLE: case UNT_ASSASSINCROSS: case UNT_POEMBRAGI: @@ -11784,19 +11788,34 @@ int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick case UNT_DONTFORGETME: case UNT_FORTUNEKISS: case UNT_SERVICEFORYOU: + // Don't buff themselves without link! if (sg->src_id==bl->id && !(sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) return 0; if (!sc) return 0; if (!sce) sc_start4(ss,bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit); + // From here songs are already active else if (battle_config.song_timer_reset && sce->val4 == 1) { - //Readjust timers since the effect will not last long. + // eA style: + // Readjust timers since the effect will not last long. sce->val4 = 0; timer->delete(sce->timer, status->change_timer); sce->timer = timer->add(tick+sg->limit, status->change_timer, bl->id, type); + } else if (!battle_config.song_timer_reset) { + // Aegis style: + // Songs won't renew unless finished + const struct TimerData *td = timer->get(sce->timer); + if (DIFF_TICK32(td->tick, timer->gettick()) < sg->interval) { + // Update with new values as the current one will vanish soon + timer->delete(sce->timer, status->change_timer); + sce->timer = timer->add(tick+sg->limit, status->change_timer, bl->id, type); + sce->val1 = sg->skill_lv; // Why are we storing skill_lv as val1? + sce->val2 = sg->val1; + sce->val3 = sg->val2; + sce->val4 = 0; + } } - break; case UNT_FOGWALL: @@ -12201,18 +12220,25 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 if (md && md->class_ == MOBID_EMPELIUM) break; #endif - if ((sg->src_id == bl->id && !(tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) - || (!(battle_config.song_timer_reset) && tsc && tsc->data[type] && tsc->data[type]->val4 == 1)) + // Don't buff themselves! + if ((sg->src_id == bl->id && !(tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_BARDDANCER))) break; - heal = skill->calc_heal(ss,bl,sg->skill_id, sg->skill_lv, true); - if( tsc && tsc->data[SC_AKAITSUKI] && heal ) - heal = ~heal + 1; - clif->skill_nodamage(&src->bl, bl, AL_HEAL, heal, 1); - status->heal(bl, heal, 0, 0); - - if (!battle_config.song_timer_reset) + // Aegis style + // Check if the remaining time is enough to survive the next update + if (!battle_config.song_timer_reset + && !(tsc && tsc->data[type] && tsc->data[type]->val4 == 1)) { + // Apple of Idun is not active. Start it now sc_start4(ss, bl, type, 100, sg->skill_lv, sg->val1, sg->val2, 0, sg->limit); + } + + if (tstatus->hp < tstatus->max_hp) { + heal = skill->calc_heal(ss,bl,sg->skill_id, sg->skill_lv, true); + if( tsc && tsc->data[SC_AKAITSUKI] && heal ) + heal = ~heal + 1; + clif->skill_nodamage(&src->bl, bl, AL_HEAL, heal, 1); + status->heal(bl, heal, 0, 0); + } } break; case UNT_POEMBRAGI: @@ -12222,12 +12248,30 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6 case UNT_DONTFORGETME: case UNT_FORTUNEKISS: case UNT_SERVICEFORYOU: - if (battle_config.song_timer_reset - || (!(battle_config.song_timer_reset) && tsc && tsc->data[type] && tsc->data[type]->val4 == 1) - || (sg->src_id == bl->id && !(tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) - ) + // eA style: doesn't need this + if (battle_config.song_timer_reset) + break; + // Don't let buff themselves! + if (sg->src_id == bl->id && !(tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) break; + // Aegis style + // Check if song has enough time to survive the next check + if (!(battle_config.song_timer_reset) && tsc && tsc->data[type] && tsc->data[type]->val4 == 1) { + const struct TimerData *td = timer->get(tsc->data[type]->timer); + if (DIFF_TICK32(td->tick, timer->gettick()) < sg->interval) { + // Update with new values as the current one will vanish + timer->delete(tsc->data[type]->timer, status->change_timer); + tsc->data[type]->timer = timer->add(tick+sg->limit, status->change_timer, bl->id, type); + tsc->data[type]->val1 = sg->skill_lv; + tsc->data[type]->val2 = sg->val1; + tsc->data[type]->val3 = sg->val2; + tsc->data[type]->val4 = 0; + } + break; // Had enough time or not, it now has. Exit + } + + // Song was not active. Start it now sc_start4(ss, bl, type, 100, sg->skill_lv, sg->val1, sg->val2, 0, sg->limit); break; case UNT_TATAMIGAESHI: @@ -12749,8 +12793,9 @@ int skill_unit_onleft(uint16 skill_id, struct block_list *bl, int64 tick) { case DC_DONTFORGETME: case DC_FORTUNEKISS: case DC_SERVICEFORYOU: - if ((battle_config.song_timer_reset && sce) // athena style - || (!battle_config.song_timer_reset && sce && sce->val4 != 1) + + if ((battle_config.song_timer_reset && sce) // eAthena style: update everytime + || (!battle_config.song_timer_reset && sce && sce->val4 != 1) // Aegis style: update only when it was not a reduced effect ) { timer->delete(sce->timer, status->change_timer); //NOTE: It'd be nice if we could get the skill_lv for a more accurate extra time, but alas... diff --git a/src/map/status.c b/src/map/status.c index 879f10efb..26db1750b 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -3523,10 +3523,14 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str if (regen->sregen) regen->sregen->rate.hp += 3; } + if (sc->data[SC_MAGNIFICAT]) { +#ifndef RENEWAL // HP Regen applies only in Pre-renewal regen->rate.hp += 1; +#endif regen->rate.sp += 1; } + if (sc->data[SC_GDSKILL_REGENERATION]) { const struct status_change_entry *sce = sc->data[SC_GDSKILL_REGENERATION]; if (!sce->val4) { |