summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/console.c1
-rw-r--r--src/common/sysinfo.c15
-rw-r--r--src/common/sysinfo.h1
-rw-r--r--src/common/timer.c64
-rw-r--r--src/map/skill.c79
-rw-r--r--src/map/status.c4
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) {