diff options
author | skotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2006-02-02 21:26:53 +0000 |
---|---|---|
committer | skotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2006-02-02 21:26:53 +0000 |
commit | 68503609ec28be3fa2c4eb0d66b0ce0ea8815cee (patch) | |
tree | 9f8c79c6424a9030baf7b6afce60bdbe2dfb1176 | |
parent | cba97f4deb4a9bb62da4ab7748926fd5319090d0 (diff) | |
download | hercules-68503609ec28be3fa2c4eb0d66b0ce0ea8815cee.tar.gz hercules-68503609ec28be3fa2c4eb0d66b0ce0ea8815cee.tar.bz2 hercules-68503609ec28be3fa2c4eb0d66b0ce0ea8815cee.tar.xz hercules-68503609ec28be3fa2c4eb0d66b0ce0ea8815cee.zip |
- Improved the NPC timer system to enable to have 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.
- Now player attached scripts will auto-abort when the atteched player quits the map server.
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@5167 54d463be-8e91-2dee-dedb-b68131a5f0ec
-rw-r--r-- | Changelog-Trunk.txt | 9 | ||||
-rw-r--r-- | src/map/map.c | 2 | ||||
-rw-r--r-- | src/map/map.h | 3 | ||||
-rw-r--r-- | src/map/mob.c | 7 | ||||
-rw-r--r-- | src/map/npc.c | 194 | ||||
-rw-r--r-- | src/map/npc.h | 1 | ||||
-rw-r--r-- | src/map/pc.c | 2 | ||||
-rw-r--r-- | src/map/script.c | 14 |
8 files changed, 188 insertions, 44 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 3b101c853..967e68d0d 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 222ada48a..ab2a13ec7 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 b41f4f1f0..960e99424 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 25806b76b..6303f3d4c 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 2cec45a8d..b56fcd605 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;j++){
@@ -588,14 +631,32 @@ int npc_timerevent_start(struct npc_data *nd, int rid) }
if(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();
+
+ //Attach only the player if attachplayerrid was used.
+ ted->rid = sd?sd->bl.id:0;
- 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]
+// 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,32 +665,81 @@ 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);
+}
+
+/*==========================================
* タイマー値の所得
*------------------------------------------
*/
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 ad482d7d1..de885a99c 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 34933136a..59843f095 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 e7f5996da..76d40d504 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);
|