diff options
author | shennetsind <ind@henn.et> | 2014-03-14 13:41:30 -0300 |
---|---|---|
committer | shennetsind <ind@henn.et> | 2014-03-14 13:41:30 -0300 |
commit | f4b1ff7426b1c4cd5e8cac37f7e3983cc03c706e (patch) | |
tree | 68b403b855daca7d11b86b02fcf2d95b8de974b4 /src | |
parent | 571d9e25008d8b386e28d7f1fd02f2690edf1f8c (diff) | |
download | hercules-f4b1ff7426b1c4cd5e8cac37f7e3983cc03c706e.tar.gz hercules-f4b1ff7426b1c4cd5e8cac37f7e3983cc03c706e.tar.bz2 hercules-f4b1ff7426b1c4cd5e8cac37f7e3983cc03c706e.tar.xz hercules-f4b1ff7426b1c4cd5e8cac37f7e3983cc03c706e.zip |
Added internal awareness of active script instances
Fixes the following issues:
- donpcevent could cause a crash when used to a event of the same npc
- input/other-dialog-interactions could cause a crash when sending data to a disabled-fakenpc-id'd.
Special Thanks to Haruna, ossi0110.
Signed-off-by: shennetsind <ind@henn.et>
Diffstat (limited to 'src')
-rw-r--r-- | src/map/npc.c | 16 | ||||
-rw-r--r-- | src/map/script.c | 25 | ||||
-rw-r--r-- | src/map/script.h | 3 |
3 files changed, 32 insertions, 12 deletions
diff --git a/src/map/npc.c b/src/map/npc.c index 7933f6d43..f77359b5f 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -1185,21 +1185,21 @@ int npc_click(struct map_session_data* sd, struct npc_data* nd) /*========================================== * *------------------------------------------*/ -int npc_scriptcont(struct map_session_data* sd, int id, bool closing) -{ +int npc_scriptcont(struct map_session_data* sd, int id, bool closing) { + struct block_list *target = map->id2bl(id); nullpo_retr(1, sd); if( id != sd->npc_id ){ TBL_NPC* nd_sd=(TBL_NPC*)map->id2bl(sd->npc_id); - TBL_NPC* nd=(TBL_NPC*)map->id2bl(id); + TBL_NPC* nd = BL_CAST(BL_NPC, target); ShowDebug("npc_scriptcont: %s (sd->npc_id=%d) is not %s (id=%d).\n", nd_sd?(char*)nd_sd->name:"'Unknown NPC'", (int)sd->npc_id, nd?(char*)nd->name:"'Unknown NPC'", (int)id); return 1; } - + if(id != npc->fake_nd->bl.id) { // Not item script - if ((npc->checknear(sd,map->id2bl(id))) == NULL){ + if ((npc->checknear(sd,target)) == NULL){ ShowWarning("npc_scriptcont: failed npc->checknear test.\n"); return 1; } @@ -1219,7 +1219,10 @@ int npc_scriptcont(struct map_session_data* sd, int id, bool closing) **/ if( sd->progressbar.npc_id && DIFF_TICK(sd->progressbar.timeout,timer->gettick()) > 0 ) return 1; - + + if( !sd->st ) + return 1; + if( closing && sd->st->state == CLOSE ) sd->st->state = END; @@ -2226,7 +2229,6 @@ int npc_unload(struct npc_data* nd, bool single) { aFree(nd->u.scr.timer_event); if (nd->src_id == 0) { if(nd->u.scr.script) { - script->stop_instances(nd->u.scr.script); script->free_code(nd->u.scr.script); nd->u.scr.script = NULL; } diff --git a/src/map/script.c b/src/map/script.c index bba771a3c..fca87a81d 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -3208,9 +3208,8 @@ void script_free_vars(struct DBMap* var_storage) { void script_free_code(struct script_code* code) { - script->free_vars(code->local.vars); - if( code->local.arrays ) - code->local.arrays->destroy(code->local.arrays,script->array_free_db); + if( code->instances ) + script->stop_instances(code); aFree( code->script_buf ); aFree( code ); } @@ -3242,6 +3241,13 @@ struct script_state* script_alloc_state(struct script_code* rootscript, int pos, st->oid = oid; st->sleep.timer = INVALID_TIMER; st->npc_item_flag = battle_config.item_enabled_npc; + + if( st->script->instances != USHRT_MAX ) + st->script->instances++; + else { + struct npc_data *nd = map->id2nd(oid); + ShowError("over 65k instances of '%s' script are being run\n",nd ? nd->name : "unknown"); + } if( !st->script->local.vars ) st->script->local.vars = i64db_alloc(DB_OPT_RELEASE_DATA); @@ -3259,9 +3265,20 @@ struct script_state* script_alloc_state(struct script_code* rootscript, int pos, /// @param st Script state void script_free_state(struct script_state* st) { if( idb_exists(script->st_db,st->id) ) { + struct map_session_data *sd = st->rid ? map->id2sd(st->rid) : NULL; + if(st->bk_st) {// backup was not restored ShowDebug("script_free_state: Previous script state lost (rid=%d, oid=%d, state=%d, bk_npcid=%d).\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid); } + + if(sd && sd->st == st) { //Current script is aborted. + if(sd->state.using_fake_npc){ + clif->clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd); + sd->state.using_fake_npc = 0; + } + sd->st = NULL; + sd->npc_id = 0; + } if( st->sleep.timer != INVALID_TIMER ) timer->delete(st->sleep.timer, script->run_timer); @@ -3274,7 +3291,7 @@ void script_free_state(struct script_state* st) { ers_free(script->stack_ers, st->stack); st->stack = NULL; } - if( st->script ) { + if( st->script && st->script->instances != USHRT_MAX && --st->script->instances == 0 ) { if( st->script->local.vars && !db_size(st->script->local.vars) ) { script->free_vars(st->script->local.vars); st->script->local.vars = NULL; diff --git a/src/map/script.h b/src/map/script.h index 73ba7303e..cf7f22aa9 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -371,6 +371,7 @@ struct script_code { int script_size; unsigned char *script_buf; struct reg_db local; ///< Local (npc) vars + unsigned short instances; }; struct script_stack { @@ -407,7 +408,7 @@ struct script_state { int pos; enum e_script_state state; int rid,oid; - struct script_code *script, *scriptroot; + struct script_code *script; struct sleep_data { int tick,timer,charid; } sleep; |