diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 3b101c853d..967e68d0d6 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -5,6 +5,15 @@ IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. EV GOES INTO TRUNK AND WILL BE MERGED INTO STABLE BY VALARIS AND WIZPUTER. -- VALARIS 2006/02/02 + * Improved the NPC timer system to enable multiple timers going on at a + time with different players attached to each. Now npc event timers are of + two types: attached or global. The global timers don't have a player + attached and can be started/halted by anyone. The character timers have a + player attached, and they can only be stopped by a script that has the same + player attached. [Skotlex] + - Now player attached scripts will auto-abort when the atteched player + quits the map server. + - Of course, this requires some major testing as it's prone to have bugs... * Applied the Entry Reusage System to the battle delay damage timers. [Skotlex] * Fixed the map server complain when using the default user/password diff --git a/src/map/map.c b/src/map/map.c index 222ada48a2..ab2a13ec75 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1475,6 +1475,8 @@ int map_quit(struct map_session_data *sd) { if(!sd->state.waitingdisconnect) { + if (sd->npc_timer_id != -1) //Cancel the event timer. + npc_timerevent_quit(sd); if (sd->state.event_disconnect) { if (script_config.event_script_type == 0) { struct npc_data *npc; diff --git a/src/map/map.h b/src/map/map.h index b41f4f1f0d..960e99424a 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -491,6 +491,7 @@ struct map_session_data { unsigned char *npc_script,*npc_scriptroot; int npc_scriptstate; char npc_str[256]; + int npc_timer_id; //For player attached npc timers. [Skotlex] unsigned int chatID; time_t idletime; @@ -786,7 +787,7 @@ struct npc_data { unsigned char *script; short xs,ys; int guild_id; - int timer,timerid,timeramount,nexttimer,rid; + int timer,timerid,timeramount,rid; unsigned int timertick; struct npc_timerevent_list *timer_event; int label_list_num; diff --git a/src/map/mob.c b/src/map/mob.c index 25806b76b2..6303f3d4cf 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -620,8 +620,6 @@ int mob_can_reach(struct mob_data *md,struct block_list *bl,int range, int state if( range>0 && !check_distance_bl(&md->bl, bl, range)) return 0; - dx=abs(bl->x - md->bl.x); - dy=abs(bl->y - md->bl.y); // Obstacle judging wpd.path_len=0; wpd.path_pos=0; @@ -629,10 +627,9 @@ int mob_can_reach(struct mob_data *md,struct block_list *bl,int range, int state if(path_search(&wpd,md->bl.m,md->bl.x,md->bl.y,bl->x,bl->y,easy)!=-1) return 1; - if(bl->type!=BL_PC && bl->type!=BL_MOB) - return 0; - // It judges whether it can adjoin or not. + dx=abs(bl->x - md->bl.x); + dy=abs(bl->y - md->bl.y); dx=(dx>0)?1:((dx<0)?-1:0); dy=(dy>0)?1:((dy<0)?-1:0); if(path_search(&wpd,md->bl.m,md->bl.x,md->bl.y,bl->x-dx,bl->y-dy,easy)!=-1) diff --git a/src/map/npc.c b/src/map/npc.c index 2cec45a8db..b56fcd6059 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -13,6 +13,7 @@ #include "../common/malloc.h" #include "../common/grfio.h" #include "../common/showmsg.h" +#include "../common/ers.h" #include "map.h" #include "log.h" #include "npc.h" @@ -59,6 +60,7 @@ struct event_data { }; static struct tm ev_tm_b; // 時計イベント用 +static struct eri *timer_event_ers; //For the npc timer data. [Skotlex] static int npc_walktimer(int,unsigned int,int,int); // [Valaris] static int npc_walktoxy_sub(struct npc_data *nd); // [Valaris] @@ -537,35 +539,74 @@ int npc_timerevent_import(char *lname,void *data,va_list ap) te[j].timer=t; te[j].pos=pos; nd->u.scr.timer_event=te; - nd->u.scr.timeramount=i+1; + nd->u.scr.timeramount++; } return 0; } +struct timer_event_data { + int rid; //Attached player for this timer. + int next; //timer index (starts with 0, then goes up to nd->u.scr.timeramount + int time; //holds total time elapsed for the script since time 0 (whenthe timers started) + unsigned int otick; //Holds tick value at which timer sequence was started (that is, it stores the tick value for which T= 0 +}; + /*========================================== * タイマーイベント実行 *------------------------------------------ */ int npc_timerevent(int tid,unsigned int tick,int id,int data) { - int next,t; + int next,t,old_rid,old_timer; + unsigned int old_tick; struct npc_data* nd=(struct npc_data *)map_id2bl(id); struct npc_timerevent_list *te; - if( nd==NULL || nd->u.scr.nexttimer<0 ){ - ShowError("npc_timerevent: ??\n"); + struct timer_event_data *ted = (struct timer_event_data*)ted; + struct map_session_data *sd=NULL; + + if( nd==NULL ){ + ShowError("npc_timerevent: NPC not found??\n"); return 0; } - nd->u.scr.timertick=tick; - te=nd->u.scr.timer_event+ nd->u.scr.nexttimer; - nd->u.scr.timerid = -1; - - t = nd->u.scr.timer+=data; - nd->u.scr.nexttimer++; - if( nd->u.scr.timeramount>nd->u.scr.nexttimer ){ - next= nd->u.scr.timer_event[ nd->u.scr.nexttimer ].timer - t; - nd->u.scr.timerid = add_timer(tick+next,npc_timerevent,id,next); + if (ted->rid) { + sd = map_id2sd(ted->rid); + if (!sd) { + if(battle_config.error_log) + ShowError("npc_timerevent: Attached player not found.\n"); + ers_free(timer_event_ers, ted); + return 0; + } + } + old_rid = nd->u.scr.rid; //To restore it later. + nd->u.scr.rid = sd?sd->bl.id:0; + + old_tick = nd->u.scr.timertick; + nd->u.scr.timertick=ted->otick; + te=nd->u.scr.timer_event+ ted->next; + + old_timer = nd->u.scr.timer; + t = nd->u.scr.timer=ted->time; + ted->next++; + + if( nd->u.scr.timeramount> ted->next){ + next= nd->u.scr.timer_event[ ted->next ].timer + - nd->u.scr.timer_event[ ted->next-1 ].timer; + ted->time+=next; + if (sd) + sd->npc_timer_id = add_timer(tick+next,npc_timerevent,id,(int)ted); + else + nd->u.scr.timerid = add_timer(tick+next,npc_timerevent,id,(int)ted); + } else { + if (sd) + sd->npc_timer_id = -1; + else + nd->u.scr.timerid = -1; + ers_free(timer_event_ers, ted); } - run_script(nd->u.scr.script,te->pos,nd->u.scr.rid,nd->bl.id); + //Restore previous data. + nd->u.scr.rid = old_rid; + nd->u.scr.timer = old_timer; + nd->u.scr.timertick = old_tick; return 0; } /*========================================== @@ -575,11 +616,13 @@ int npc_timerevent(int tid,unsigned int tick,int id,int data) int npc_timerevent_start(struct npc_data *nd, int rid) { int j,n, next; - + struct map_session_data *sd=NULL; //Player to whom script is attached. + struct timer_event_data *ted; + nullpo_retr(0, nd); n=nd->u.scr.timeramount; - if( nd->u.scr.nexttimer>=0 || n==0 ) + if( n==0 ) return 0; for(j=0;j=n) // check if there is a timer to use !!BEFORE!! you write stuff to the structures [Shinomori] return 0; + if (nd->u.scr.rid > 0) { + //Try to attach timer to this player. + sd = map_id2sd(nd->u.scr.rid); + if (!sd) { + if(battle_config.error_log) + ShowError("npc_timerevent_start: Attached player not found!\n"); + return 1; + } + } + ted = ers_alloc(timer_event_ers, struct timer_event_data); + ted->next = j; + nd->u.scr.timertick=ted->otick=gettick(); - nd->u.scr.nexttimer=j; - nd->u.scr.timertick=gettick(); - if (rid >= 0) nd->u.scr.rid=rid; // changed to: attaching to given rid by default [Shinomori] + //Attach only the player if attachplayerrid was used. + ted->rid = sd?sd->bl.id:0; + +// Do not store it to make way to two types of timers: globals and personals. +// if (rid >= 0) nd->u.scr.rid=rid; // changed to: attaching to given rid by default [Shinomori] // if rid is less than 0 leave it unchanged [celest] next = nd->u.scr.timer_event[j].timer - nd->u.scr.timer; - nd->u.scr.timerid = add_timer(gettick()+next,npc_timerevent,nd->bl.id,next); + ted->time = nd->u.scr.timer_event[j].timer; + if (sd) + sd->npc_timer_id = add_timer(gettick()+next,npc_timerevent,nd->bl.id,(int)ted); + else + nd->u.scr.timerid = add_timer(gettick()+next,npc_timerevent,nd->bl.id,(int)ted); return 0; } /*========================================== @@ -604,18 +665,51 @@ int npc_timerevent_start(struct npc_data *nd, int rid) */ int npc_timerevent_stop(struct npc_data *nd) { + struct map_session_data *sd =NULL; + struct TimerData *td = NULL; + int *tid; nullpo_retr(0, nd); - - if( nd->u.scr.nexttimer>=0 ){ - nd->u.scr.nexttimer = -1; - nd->u.scr.timer += (int)(gettick() - nd->u.scr.timertick); - if(nd->u.scr.timerid!=-1) - delete_timer(nd->u.scr.timerid,npc_timerevent); - nd->u.scr.timerid = -1; - nd->u.scr.rid = 0; + if (nd->u.scr.rid) { + sd = map_id2sd(nd->u.scr.rid); + if (!sd) { + if(battle_config.error_log) + ShowError("npc_timerevent_stop: Attached player not found!\n"); + return 1; + } } + + tid = sd?&sd->npc_timer_id:&nd->u.scr.timerid; + + if (*tid == -1) //Nothing to stop + return 0; + td = get_timer(*tid); + if (td && td->data) + ers_free(timer_event_ers, (struct event_timer_data*)td->data); + delete_timer(*tid,npc_timerevent); + *tid = -1; + //Set the timer tick to the time that has passed since the beginning of the timers and now. + nd->u.scr.timer = DIFF_TICK(gettick(),nd->u.scr.timertick); + nd->u.scr.rid = 0; return 0; } +/*========================================== + * Aborts a running npc timer that is attached to a player. + *------------------------------------------ + */ +void npc_timerevent_quit(struct map_session_data *sd) { + struct TimerData *td; + if (sd->npc_timer_id == -1) + return; + td = get_timer(sd->npc_timer_id); + if (!td) { + sd->npc_timer_id = -1; + return; //?? + } + delete_timer(sd->npc_timer_id,npc_timerevent); + sd->npc_timer_id = -1; + ers_free(timer_event_ers, (struct event_timer_data*)td->data); +} + /*========================================== * タイマー値の所得 *------------------------------------------ @@ -623,13 +717,29 @@ int npc_timerevent_stop(struct npc_data *nd) int npc_gettimerevent_tick(struct npc_data *nd) { int tick; + struct map_session_data *sd =NULL; nullpo_retr(0, nd); tick=nd->u.scr.timer; - if( nd->u.scr.nexttimer>=0 ) - tick += (int)(gettick() - nd->u.scr.timertick); + if (nd->u.scr.rid) { + sd = map_id2sd(nd->u.scr.rid); + if (!sd) { + if(battle_config.error_log) + ShowError("npc_gettimerevent_tick: Attached player not found!\n"); + return tick; + } + } + //If within a timer, set the tick value to the time passed since the beginning of the timer. + if (sd) { + if(sd->npc_timer_id != -1) + tick = DIFF_TICK(gettick(), nd->u.scr.timertick); + } else { + if(nd->u.scr.timerid!=-1) + tick = DIFF_TICK(gettick(), nd->u.scr.timertick); + } + return tick; } /*========================================== @@ -639,14 +749,24 @@ int npc_gettimerevent_tick(struct npc_data *nd) int npc_settimerevent_tick(struct npc_data *nd,int newtimer) { int flag; + struct map_session_data *sd=NULL; nullpo_retr(0, nd); - flag= nd->u.scr.nexttimer; - - npc_timerevent_stop(nd); + if (nd->u.scr.rid) { + sd = map_id2sd(nd->u.scr.rid); + if (!sd) { + if(battle_config.error_log) + ShowError("npc_settimerevent_tick: Attached player not found!\n"); + return 1; + } + flag= sd->npc_timer_id != -1 ; + } else + flag= nd->u.scr.timer != -1 ; + if(flag) + npc_timerevent_stop(nd); nd->u.scr.timer=newtimer; - if(flag>=0) + if(flag) npc_timerevent_start(nd, -1); return 0; } @@ -2050,10 +2170,9 @@ static int npc_parse_script (char *w1,char *w2,char *w3,char *w4,char *first_lin te[j].timer = t; te[j].pos = pos; nd->u.scr.timer_event = te; - nd->u.scr.timeramount = k+1; + nd->u.scr.timeramount++; } } - nd->u.scr.nexttimer = -1; nd->u.scr.timerid = -1; return 0; @@ -2751,7 +2870,7 @@ int do_final_npc(void) //There is no free function for npcname_db because at this point there shouldn't be any npcs left! //So if there is anything remaining, let the memory manager catch it and report it. npcname_db->destroy(npcname_db, NULL); - + ers_destroy(timer_event_ers); npc_clearsrcfile(); return 0; @@ -2778,6 +2897,7 @@ int do_init_npc(void) npcname_db = db_alloc(__FILE__,__LINE__,DB_STRING,DB_OPT_BASE,NAME_LENGTH); memset(&ev_tm_b, -1, sizeof(ev_tm_b)); + timer_event_ers = ers_new((uint32)sizeof(struct timer_event_data)); for (nsl = npc_src_first; nsl; nsl = nsl->next) { npc_parsesrcfile(nsl->name); diff --git a/src/map/npc.h b/src/map/npc.h index ad482d7d1a..de885a99c4 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -59,6 +59,7 @@ int npc_event_doall_id(const unsigned char *name, int id); int npc_timerevent_start(struct npc_data *nd, int rid); int npc_timerevent_stop(struct npc_data *nd); +void npc_timerevent_quit(struct map_session_data *sd); int npc_gettimerevent_tick(struct npc_data *nd); int npc_settimerevent_tick(struct npc_data *nd,int newtimer); int npc_remove_map(struct npc_data *nd); diff --git a/src/map/pc.c b/src/map/pc.c index 34933136a2..59843f095c 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -786,6 +786,8 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t for(i = 0; i < MAX_EVENTTIMER; i++) sd->eventtimer[i] = -1; + sd->npc_timer_id = -1; + // Moved PVP timer initialisation before set_pos sd->pvp_timer = -1; diff --git a/src/map/script.c b/src/map/script.c index e7f5996da8..76d40d5047 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -5639,6 +5639,7 @@ int buildin_stopnpctimer(struct script_state *st) int buildin_getnpctimer(struct script_state *st) { struct npc_data *nd; + struct map_session_data *sd; int type=conv_num(st,& (st->stack->stack_data[st->start+2])); int val=0; if( st->end > st->start+3 ) @@ -5648,7 +5649,18 @@ int buildin_getnpctimer(struct script_state *st) switch(type){ case 0: val=npc_gettimerevent_tick(nd); break; - case 1: val= (nd->u.scr.nexttimer>=0); break; + case 1: + if (nd->u.scr.rid) { + sd = map_id2sd(nd->u.scr.rid); + if (!sd) { + if(battle_config.error_log) + ShowError("buildin_getnpctimer: Attached player not found!\n"); + break; + } + val = (sd->npc_timer_id != -1); + } else + val= (nd->u.scr.timerid !=-1); + break; case 2: val= nd->u.scr.timeramount; break; } push_val(st->stack,C_INT,val);