Tried to make sense out of timer.c ... and failed
git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@11647 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
parent
b95f742af8
commit
59b9654397
@ -17,12 +17,8 @@
|
|||||||
#include <sys/time.h> // struct timeval, gettimeofday()
|
#include <sys/time.h> // struct timeval, gettimeofday()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// タイマー間隔の最小値。モンスターの大量召還時、多数のクライアント接続時に
|
// If the server can't handle processing thousands of monsters
|
||||||
// サーバーが反応しなくなる場合は、TIMER_MIN_INTERVAL を増やしてください。
|
// or many connected clients, please increase TIMER_MIN_INTERVAL.
|
||||||
|
|
||||||
// If the server shows no reaction when processing thousands of monsters
|
|
||||||
// or connected by many clients, please increase TIMER_MIN_INTERVAL.
|
|
||||||
|
|
||||||
#define TIMER_MIN_INTERVAL 50
|
#define TIMER_MIN_INTERVAL 50
|
||||||
|
|
||||||
// timers
|
// timers
|
||||||
@ -41,16 +37,18 @@ static int timer_heap_num = 0;
|
|||||||
static int timer_heap_max = 0;
|
static int timer_heap_max = 0;
|
||||||
static int* timer_heap = NULL;
|
static int* timer_heap = NULL;
|
||||||
|
|
||||||
// for debug
|
// server startup time
|
||||||
|
time_t start_time;
|
||||||
|
|
||||||
|
|
||||||
|
/*----------------------------
|
||||||
|
* Timer debugging
|
||||||
|
*----------------------------*/
|
||||||
struct timer_func_list {
|
struct timer_func_list {
|
||||||
struct timer_func_list* next;
|
struct timer_func_list* next;
|
||||||
TimerFunc func;
|
TimerFunc func;
|
||||||
char* name;
|
char* name;
|
||||||
};
|
} *tfl_root = NULL;
|
||||||
static struct timer_func_list* tfl_root = NULL;
|
|
||||||
|
|
||||||
// server startup time
|
|
||||||
time_t start_time;
|
|
||||||
|
|
||||||
/// Sets the name of a timer function.
|
/// Sets the name of a timer function.
|
||||||
int add_timer_func_list(TimerFunc func, char* name)
|
int add_timer_func_list(TimerFunc func, char* name)
|
||||||
@ -227,10 +225,13 @@ static int acquire_timer(void)
|
|||||||
return tid;
|
return tid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Starts a new timer that is deleted once it expires (single-use).
|
||||||
|
/// Returns the timer's id.
|
||||||
int add_timer(unsigned int tick, TimerFunc func, int id, int data)
|
int add_timer(unsigned int tick, TimerFunc func, int id, int data)
|
||||||
{
|
{
|
||||||
int tid = acquire_timer();
|
int tid;
|
||||||
|
|
||||||
|
tid = acquire_timer();
|
||||||
timer_data[tid].tick = tick;
|
timer_data[tid].tick = tick;
|
||||||
timer_data[tid].func = func;
|
timer_data[tid].func = func;
|
||||||
timer_data[tid].id = id;
|
timer_data[tid].id = id;
|
||||||
@ -242,13 +243,14 @@ int add_timer(unsigned int tick,TimerFunc func, int id, int data)
|
|||||||
return tid;
|
return tid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Starts a new timer that automatically restarts itself (infinite loop until manually removed).
|
||||||
|
/// Returns the timer's id, or -1 if it fails.
|
||||||
int add_timer_interval(unsigned int tick, TimerFunc func, int id, int data, int interval)
|
int add_timer_interval(unsigned int tick, TimerFunc func, int id, int data, int interval)
|
||||||
{
|
{
|
||||||
int tid;
|
int tid;
|
||||||
|
|
||||||
if( interval < 1 ) {
|
if( interval < 1 ) {
|
||||||
ShowError("add_timer_interval : function %08x(%s) has invalid interval %d!\n",
|
ShowError("add_timer_interval : function %08x(%s) has invalid interval %d!\n", (int)func, search_timer_func_list(func), interval);
|
||||||
(int)func, search_timer_func_list(func), interval);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,34 +266,42 @@ int add_timer_interval(unsigned int tick, TimerFunc func, int id, int data, int
|
|||||||
return tid;
|
return tid;
|
||||||
}
|
}
|
||||||
|
|
||||||
int delete_timer(int id, TimerFunc func)
|
/// Retrieves internal timer data
|
||||||
|
//FIXME: for safety, the return value should be 'const'
|
||||||
|
struct TimerData* get_timer(int tid)
|
||||||
{
|
{
|
||||||
if (id <= 0 || id >= timer_data_num) {
|
return &timer_data[tid];
|
||||||
ShowError("delete_timer error : no such timer %d (%08x(%s))\n", id, (int)func, search_timer_func_list(func));
|
}
|
||||||
|
|
||||||
|
/// 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 delete_timer(int tid, TimerFunc func)
|
||||||
|
{
|
||||||
|
if( tid <= 0 || tid >= timer_data_num ) {
|
||||||
|
ShowError("delete_timer error : no such timer %d (%08x(%s))\n", tid, (int)func, search_timer_func_list(func));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (timer_data[id].func != func) {
|
if( timer_data[tid].func != func ) {
|
||||||
ShowError("delete_timer error : function mismatch %08x(%s) != %08x(%s)\n",
|
ShowError("delete_timer error : function mismatch %08x(%s) != %08x(%s)\n", (int)timer_data[tid].func, search_timer_func_list(timer_data[tid].func), (int)func, search_timer_func_list(func));
|
||||||
(int)timer_data[id].func, search_timer_func_list(timer_data[id].func),
|
|
||||||
(int)func, search_timer_func_list(func));
|
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
// そのうち消えるにまかせる
|
|
||||||
timer_data[id].func = NULL;
|
timer_data[tid].func = NULL;
|
||||||
timer_data[id].type = TIMER_ONCE_AUTODEL;
|
timer_data[tid].type = TIMER_ONCE_AUTODEL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adjusts a timer's expiration time.
|
||||||
|
/// Returns the new tick value, or -1 if it fails.
|
||||||
int addtick_timer(int tid, unsigned int tick)
|
int addtick_timer(int tid, unsigned int tick)
|
||||||
{
|
{
|
||||||
// Doesn't adjust the timer position. Might be the root of the FIXME in settick_timer. [FlavioJS]
|
|
||||||
//return timer_data[tid].tick += tick;
|
|
||||||
return settick_timer(tid, timer_data[tid].tick+tick);
|
return settick_timer(tid, timer_data[tid].tick+tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Sets the tick at which the timer triggers directly (meant as a replacement of delete_timer + add_timer) [Skotlex]
|
/// Modifies a timer's expiration time (an alternative to deleting a timer and starting a new one).
|
||||||
//FIXME: DON'T use this function yet, it is not correctly reorganizing the timer stack causing unexpected problems later on!
|
/// Returns the new tick value, or -1 if it fails.
|
||||||
int settick_timer(int tid, unsigned int tick)
|
int settick_timer(int tid, unsigned int tick)
|
||||||
{
|
{
|
||||||
int old_pos,pos;
|
int old_pos,pos;
|
||||||
@ -305,7 +315,7 @@ int settick_timer(int tid, unsigned int tick)
|
|||||||
HEAP_SEARCH(old_tick,0,timer_heap_num-1,old_pos);
|
HEAP_SEARCH(old_tick,0,timer_heap_num-1,old_pos);
|
||||||
while( timer_heap[old_pos] != tid )
|
while( timer_heap[old_pos] != tid )
|
||||||
{// skip timers with the same tick
|
{// skip timers with the same tick
|
||||||
if( DIFF_TICK(old_tick,timer_data[timer_heap[old_pos]].tick) != 0 )
|
if( old_tick != timer_data[timer_heap[old_pos]].tick )
|
||||||
{
|
{
|
||||||
ShowError("settick_timer: no such timer %d (%08x(%s))\n", tid, (int)timer_data[tid].func, search_timer_func_list(timer_data[tid].func));
|
ShowError("settick_timer: no such timer %d (%08x(%s))\n", tid, (int)timer_data[tid].func, search_timer_func_list(timer_data[tid].func));
|
||||||
return -1;
|
return -1;
|
||||||
@ -334,14 +344,11 @@ int settick_timer(int tid, unsigned int tick)
|
|||||||
memmove(&timer_heap[pos+1], &timer_heap[pos], (old_pos-pos)*sizeof(int));
|
memmove(&timer_heap[pos+1], &timer_heap[pos], (old_pos-pos)*sizeof(int));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timer_heap[pos] = tid;
|
timer_heap[pos] = tid;
|
||||||
timer_data[tid].tick = tick;
|
timer_data[tid].tick = tick;
|
||||||
return tick;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TimerData* get_timer(int tid)
|
return tick;
|
||||||
{
|
|
||||||
return &timer_data[tid];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Correcting the heap when the tick overflows is an idea taken from jA to
|
//Correcting the heap when the tick overflows is an idea taken from jA to
|
||||||
@ -367,10 +374,13 @@ static void fix_timer_heap(unsigned int tick)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Executes all expired timers.
|
||||||
|
/// Returns the value of the smallest non-expired timer (or 1 second if there aren't any).
|
||||||
int do_timer(unsigned int tick)
|
int do_timer(unsigned int tick)
|
||||||
{
|
{
|
||||||
|
int nextmin = 1000; // return value
|
||||||
static int fix_heap_flag = 0; //Flag for fixing the stack only once per tick loop. May not be the best way, but it's all I can think of currently :X [Skotlex]
|
static int fix_heap_flag = 0; //Flag for fixing the stack only once per tick loop. May not be the best way, but it's all I can think of currently :X [Skotlex]
|
||||||
int i, nextmin = 1000;
|
int i;
|
||||||
|
|
||||||
if( tick < 0x010000 && fix_heap_flag )
|
if( tick < 0x010000 && fix_heap_flag )
|
||||||
{
|
{
|
||||||
@ -378,26 +388,37 @@ int do_timer(unsigned int tick)
|
|||||||
fix_heap_flag = 0;
|
fix_heap_flag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(timer_heap_num) {
|
// process all timers one by one
|
||||||
i = timer_heap[timer_heap_num - 1]; // next shorter element
|
while( timer_heap_num )
|
||||||
|
{
|
||||||
|
i = timer_heap[timer_heap_num - 1]; // last element in heap (=>smallest)
|
||||||
if( (nextmin = DIFF_TICK(timer_data[i].tick, tick)) > 0 )
|
if( (nextmin = DIFF_TICK(timer_data[i].tick, tick)) > 0 )
|
||||||
break;
|
break; // no more expired timers to process
|
||||||
|
|
||||||
--timer_heap_num; // suppress the actual element from the table
|
--timer_heap_num; // suppress the actual element from the table
|
||||||
|
|
||||||
|
// mark timer as 'to be removed'
|
||||||
timer_data[i].type |= TIMER_REMOVE_HEAP;
|
timer_data[i].type |= TIMER_REMOVE_HEAP;
|
||||||
if (timer_data[i].func) {
|
|
||||||
if (nextmin < -1000) {
|
if( timer_data[i].func )
|
||||||
|
{
|
||||||
|
if( nextmin < -1000 )
|
||||||
// 1秒以上の大幅な遅延が発生しているので、
|
// 1秒以上の大幅な遅延が発生しているので、
|
||||||
// timer処理タイミングを現在値とする事で
|
// timer処理タイミングを現在値とする事で
|
||||||
// 呼び出し時タイミング(引数のtick)相対で処理してる
|
// 呼び出し時タイミング(引数のtick)相対で処理してる
|
||||||
// timer関数の次回処理タイミングを遅らせる
|
// timer関数の次回処理タイミングを遅らせる
|
||||||
timer_data[i].func(i, tick, timer_data[i].id, timer_data[i].data);
|
timer_data[i].func(i, tick, timer_data[i].id, timer_data[i].data);
|
||||||
} else {
|
else
|
||||||
timer_data[i].func(i, timer_data[i].tick, timer_data[i].id, timer_data[i].data);
|
timer_data[i].func(i, timer_data[i].tick, timer_data[i].id, timer_data[i].data);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (timer_data[i].type & TIMER_REMOVE_HEAP) {
|
// in the case the function didn't change anything...
|
||||||
switch(timer_data[i].type & ~TIMER_REMOVE_HEAP) {
|
if( timer_data[i].type & TIMER_REMOVE_HEAP )
|
||||||
|
{
|
||||||
|
timer_data[i].type &= ~TIMER_REMOVE_HEAP;
|
||||||
|
|
||||||
|
switch( timer_data[i].type )
|
||||||
|
{
|
||||||
case TIMER_ONCE_AUTODEL:
|
case TIMER_ONCE_AUTODEL:
|
||||||
timer_data[i].type = 0;
|
timer_data[i].type = 0;
|
||||||
if (free_timer_list_pos >= free_timer_list_max) {
|
if (free_timer_list_pos >= free_timer_list_max) {
|
||||||
@ -425,6 +446,7 @@ int do_timer(unsigned int tick)
|
|||||||
|
|
||||||
if( UINT_MAX - nextmin < tick ) //Tick will loop, rearrange the heap on the next iteration.
|
if( UINT_MAX - nextmin < tick ) //Tick will loop, rearrange the heap on the next iteration.
|
||||||
fix_heap_flag = 1;
|
fix_heap_flag = 1;
|
||||||
|
|
||||||
return nextmin;
|
return nextmin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,28 +8,29 @@
|
|||||||
#include "../common/cbasetypes.h"
|
#include "../common/cbasetypes.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BASE_TICK 5
|
|
||||||
|
|
||||||
#define TIMER_ONCE_AUTODEL 0x01
|
|
||||||
#define TIMER_INTERVAL 0x02
|
|
||||||
#define TIMER_REMOVE_HEAP 0x10
|
|
||||||
|
|
||||||
#define DIFF_TICK(a,b) ((int)((a)-(b)))
|
#define DIFF_TICK(a,b) ((int)((a)-(b)))
|
||||||
|
|
||||||
#define INVALID_TIMER -1
|
#define INVALID_TIMER -1
|
||||||
|
|
||||||
|
// timer flags
|
||||||
|
#define TIMER_ONCE_AUTODEL 0x01
|
||||||
|
#define TIMER_INTERVAL 0x02
|
||||||
|
#define TIMER_REMOVE_HEAP 0x10
|
||||||
|
|
||||||
// Struct declaration
|
// Struct declaration
|
||||||
|
|
||||||
typedef int (*TimerFunc)(int,unsigned int,int,int);
|
typedef int (*TimerFunc)(int tid, unsigned int tick, int id, int data);
|
||||||
|
|
||||||
struct TimerData {
|
struct TimerData {
|
||||||
unsigned int tick;
|
unsigned int tick;
|
||||||
TimerFunc func;
|
TimerFunc func;
|
||||||
int id;
|
|
||||||
int data;
|
|
||||||
int type;
|
int type;
|
||||||
int interval;
|
int interval;
|
||||||
int heap_pos;
|
int heap_pos;
|
||||||
|
|
||||||
|
// general-purpose storage
|
||||||
|
int id;
|
||||||
|
int data;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function prototype declaration
|
// Function prototype declaration
|
||||||
@ -37,21 +38,19 @@ struct TimerData {
|
|||||||
unsigned int gettick(void);
|
unsigned int gettick(void);
|
||||||
unsigned int gettick_nocache(void);
|
unsigned int gettick_nocache(void);
|
||||||
|
|
||||||
int add_timer(unsigned int,TimerFunc f,int,int);
|
int add_timer(unsigned int tick, TimerFunc func, int id, int data);
|
||||||
int add_timer_interval(unsigned int tick, TimerFunc func, int id, int data, int interval);
|
int add_timer_interval(unsigned int tick, TimerFunc func, int id, int data, int interval);
|
||||||
int delete_timer(int,TimerFunc f);
|
struct TimerData* get_timer(int tid);
|
||||||
|
int delete_timer(int tid, TimerFunc func);
|
||||||
|
|
||||||
int addtick_timer(int tid, unsigned int tick);
|
int addtick_timer(int tid, unsigned int tick);
|
||||||
int settick_timer(int tid, unsigned int tick);
|
int settick_timer(int tid, unsigned int tick);
|
||||||
struct TimerData *get_timer(int tid);
|
|
||||||
|
|
||||||
int do_timer(unsigned int tick);
|
|
||||||
|
|
||||||
int add_timer_func_list(TimerFunc func, char* name);
|
int add_timer_func_list(TimerFunc func, char* name);
|
||||||
char* search_timer_func_list(TimerFunc f);
|
|
||||||
|
|
||||||
unsigned long get_uptime(void);
|
unsigned long get_uptime(void);
|
||||||
|
|
||||||
|
int do_timer();
|
||||||
void timer_init(void);
|
void timer_init(void);
|
||||||
void timer_final(void);
|
void timer_final(void);
|
||||||
|
|
||||||
|
@ -1019,7 +1019,7 @@ int chrif_save_scdata(struct map_session_data *sd)
|
|||||||
int i, count=0;
|
int i, count=0;
|
||||||
unsigned int tick;
|
unsigned int tick;
|
||||||
struct status_change_data data;
|
struct status_change_data data;
|
||||||
struct TimerData *timer;
|
const struct TimerData *timer;
|
||||||
|
|
||||||
if (sd->state.finalsave) //Character was already saved?
|
if (sd->state.finalsave) //Character was already saved?
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -54,7 +54,7 @@ int merc_hom_food(struct map_session_data *sd, struct homun_data *hd);
|
|||||||
int merc_hom_hungry_timer_delete(struct homun_data *hd);
|
int merc_hom_hungry_timer_delete(struct homun_data *hd);
|
||||||
int merc_hom_change_name(struct map_session_data *sd,char *name);
|
int merc_hom_change_name(struct map_session_data *sd,char *name);
|
||||||
int merc_hom_change_name_ack(struct map_session_data *sd, char* name, int flag);
|
int merc_hom_change_name_ack(struct map_session_data *sd, char* name, int flag);
|
||||||
#define merc_stop_walking(hd, type) { if((hd)->ud.walktimer != -1) unit_stop_walking(&(hd)->bl, type); }
|
#define merc_stop_walking(hd, type) unit_stop_walking(&(hd)->bl, type)
|
||||||
#define merc_stop_attack(hd) { if((hd)->ud.attacktimer != -1) unit_stop_attack(&(hd)->bl); hd->ud.target = 0; }
|
#define merc_stop_attack(hd) { if((hd)->ud.attacktimer != -1) unit_stop_attack(&(hd)->bl); hd->ud.target = 0; }
|
||||||
int merc_hom_increase_intimacy(struct homun_data * hd, unsigned int value);
|
int merc_hom_increase_intimacy(struct homun_data * hd, unsigned int value);
|
||||||
int merc_hom_decrease_intimacy(struct homun_data * hd, unsigned int value);
|
int merc_hom_decrease_intimacy(struct homun_data * hd, unsigned int value);
|
||||||
|
@ -995,7 +995,7 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick)
|
|||||||
* when trying to pick new targets when the current chosen target is
|
* when trying to pick new targets when the current chosen target is
|
||||||
* unreachable.
|
* unreachable.
|
||||||
*------------------------------------------*/
|
*------------------------------------------*/
|
||||||
int mob_unlocktarget(struct mob_data *md,int tick)
|
int mob_unlocktarget(struct mob_data *md, unsigned int tick)
|
||||||
{
|
{
|
||||||
nullpo_retr(0, md);
|
nullpo_retr(0, md);
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap); //Change Guardia
|
|||||||
int mob_randomwalk(struct mob_data *md,unsigned int tick);
|
int mob_randomwalk(struct mob_data *md,unsigned int tick);
|
||||||
int mob_warpchase(struct mob_data *md, struct block_list *target);
|
int mob_warpchase(struct mob_data *md, struct block_list *target);
|
||||||
int mob_target(struct mob_data *md,struct block_list *bl,int dist);
|
int mob_target(struct mob_data *md,struct block_list *bl,int dist);
|
||||||
int mob_unlocktarget(struct mob_data *md,int tick);
|
int mob_unlocktarget(struct mob_data *md, unsigned int tick);
|
||||||
struct mob_data* mob_spawn_dataset(struct spawn_data *data);
|
struct mob_data* mob_spawn_dataset(struct spawn_data *data);
|
||||||
int mob_spawn(struct mob_data *md);
|
int mob_spawn(struct mob_data *md);
|
||||||
int mob_setdelayspawn(struct mob_data *md);
|
int mob_setdelayspawn(struct mob_data *md);
|
||||||
@ -177,8 +177,8 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type);
|
|||||||
void mob_revive(struct mob_data *md, unsigned int hp);
|
void mob_revive(struct mob_data *md, unsigned int hp);
|
||||||
void mob_heal(struct mob_data *md,unsigned int heal);
|
void mob_heal(struct mob_data *md,unsigned int heal);
|
||||||
|
|
||||||
#define mob_stop_walking(md, type) { if (md->ud.walktimer != -1) unit_stop_walking(&md->bl, type); }
|
#define mob_stop_walking(md, type) unit_stop_walking(&(md)->bl, type)
|
||||||
#define mob_stop_attack(md) { if (md->ud.attacktimer != -1) unit_stop_attack(&md->bl); }
|
#define mob_stop_attack(md) { if((md)->ud.attacktimer != -1) unit_stop_attack(&(md)->bl); }
|
||||||
|
|
||||||
void mob_clear_spawninfo();
|
void mob_clear_spawninfo();
|
||||||
int do_init_mob(void);
|
int do_init_mob(void);
|
||||||
|
@ -110,8 +110,8 @@ enum {
|
|||||||
#define pc_is90overweight(sd) ( (sd)->weight*10 >= (sd)->max_weight*9 )
|
#define pc_is90overweight(sd) ( (sd)->weight*10 >= (sd)->max_weight*9 )
|
||||||
#define pc_maxparameter(sd) ( (sd)->class_&JOBL_BABY ? battle_config.max_baby_parameter : battle_config.max_parameter )
|
#define pc_maxparameter(sd) ( (sd)->class_&JOBL_BABY ? battle_config.max_baby_parameter : battle_config.max_parameter )
|
||||||
|
|
||||||
|
#define pc_stop_walking(sd, type) unit_stop_walking(&(sd)->bl, type)
|
||||||
#define pc_stop_attack(sd) { if((sd)->ud.attacktimer != -1) { unit_stop_attack(&(sd)->bl); (sd)->ud.target = 0; } }
|
#define pc_stop_attack(sd) { if((sd)->ud.attacktimer != -1) { unit_stop_attack(&(sd)->bl); (sd)->ud.target = 0; } }
|
||||||
#define pc_stop_walking(sd, type) { if( (sd)->ud.walktimer != -1 ) unit_stop_walking(&(sd)->bl, type); }
|
|
||||||
|
|
||||||
//Weapon check considering dual wielding.
|
//Weapon check considering dual wielding.
|
||||||
#define pc_check_weapontype(sd, type) ((type)&((sd)->status.weapon < MAX_WEAPON_TYPE? \
|
#define pc_check_weapontype(sd, type) ((type)&((sd)->status.weapon < MAX_WEAPON_TYPE? \
|
||||||
|
@ -58,7 +58,7 @@ int pet_skill_bonus_timer(int tid,unsigned int tick,int id,int data); // [Valari
|
|||||||
int pet_recovery_timer(int tid,unsigned int tick,int id,int data); // [Valaris]
|
int pet_recovery_timer(int tid,unsigned int tick,int id,int data); // [Valaris]
|
||||||
int pet_heal_timer(int tid,unsigned int tick,int id,int data); // [Valaris]
|
int pet_heal_timer(int tid,unsigned int tick,int id,int data); // [Valaris]
|
||||||
|
|
||||||
#define pet_stop_walking(pd, type) { if((pd)->ud.walktimer != -1) unit_stop_walking(&(pd)->bl, type); }
|
#define pet_stop_walking(pd, type) unit_stop_walking(&(pd)->bl, type)
|
||||||
#define pet_stop_attack(pd) { if((pd)->ud.attacktimer != -1) unit_stop_attack(&(pd)->bl); }
|
#define pet_stop_attack(pd) { if((pd)->ud.attacktimer != -1) unit_stop_attack(&(pd)->bl); }
|
||||||
|
|
||||||
int read_petdb(void);
|
int read_petdb(void);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user