From 93f61040ac281b84c038af72e322a03f60bc6e03 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Sat, 19 Oct 2013 16:22:04 -0300 Subject: Instance Dungeons Update As requested by the community in http://hercules.ws/board/topic/1702-implement-rathena-npc/ we're merging in the latest of rAthena's dungeons, this includes the rewriting of all instance dungeons and the addition of 4 dungeons that were not present previously (BakonawaLake, BangungotHospital, BuwayaCave and OldGlastHeim). Update also includes the ability for instances to reset (or be destroyed if instance files were disabled/removed) upon @reloadscript, instance scripts are able to control to what stage the instances are to be reset via the instance_set_respawn (reload spawn) script command, OnInstanceInit labels are now triggered when the instance starts via instance_init (and upon reload), they may be used alongside instance variables (which are persistent to @reloadscript) to save players' progress. - NPC Changelog: -- npc/instances/EndlessTower.txt --- 2.2 Instance system rewrite. [Euphy] --- 2.3 Added some missing announcements. [Euphy] --- 2.4 Added GM management function. [Euphy] -- npc/instances/NydhoggsNest.txt --- 1.5 Instance system rewrite. [Euphy] --- 1.6 Added GM management NPCs. [Euphy] -- npc/instances/OrcsMemory.txt --- 1.7 Instance system rewrite. [Euphy] -- npc/instances/SealedShrine.txt --- 2.3 Instance system rewrite. [Euphy] -- npc/other/gm_npcs.txt --- 1.0 First version. [Euphy] -- npc/re/instances/BakonawaLake.txt --- 1.0 First version. [Euphy] --- 1.1 Added GM management NPC. [Euphy] -- npc/re/instances/BangungotHospital.txt --- 1.0 First version. [Euphy] --- 1.1 Added GM management function. [Euphy] -- npc/re/instances/BuwayaCave.txt --- 1.0 First version. [Euphy] -- npc/re/instances/HazyForest.txt --- 1.1 Instance system rewrite. [Euphy] -- npc/re/instances/MalangdoCulvert.txt --- 1.0b Fixed incorrect use of 'close'. [Joseph] --- 1.1 Instance system rewrite. [Euphy] -- npc/re/instances/OctopusCave.txt --- 1.1 Instance system rewrite. [Euphy] -- npc/re/instances/OldGlastHeim.txt --- 1.0 First version. [Euphy] Special Thanks to Haru, Uziel for their contributions to this update, and ossi0110 for helping us debug it. Signed-off-by: shennetsind --- src/common/mmo.h | 2 +- src/map/instance.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++--- src/map/instance.h | 8 ++++++ src/map/npc.c | 8 +++--- src/map/pc.c | 8 ++++++ src/map/script.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 166 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/common/mmo.h b/src/common/mmo.h index ccba0fa7f..7977042d8 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -119,7 +119,7 @@ #define MAX_GUILDSKILL 15 // Increased max guild skills because of new skills [Sara-chan] #define MAX_GUILDLEVEL 50 #define MAX_GUARDIANS 8 // Local max per castle. [Skotlex] -#define MAX_QUEST_DB 2662 // Max quests that the server will load +#define MAX_QUEST_DB 2670 // Max quests that the server will load #define MAX_QUEST_OBJECTIVES 3 // Max quest objectives for a quest #define MAX_START_ITEMS 32 // Max number of items allowed to be given to a char whenever it's created. [mkbu95] diff --git a/src/map/instance.c b/src/map/instance.c index 6ae1d6141..045be5431 100644 --- a/src/map/instance.c +++ b/src/map/instance.c @@ -110,7 +110,10 @@ int instance_create(int owner_id, const char *name, enum instance_owner_type typ instance->list[i].owner_id = owner_id; instance->list[i].owner_type = type; instance->list[i].vars = idb_alloc(DB_OPT_RELEASE_DATA); - + instance->list[i].respawn.map = 0; + instance->list[i].respawn.y = 0; + instance->list[i].respawn.x = 0; + safestrncpy( instance->list[i].name, name, sizeof(instance->list[i].name) ); if( type != IOT_NONE ) { @@ -242,6 +245,7 @@ int instance_add_map(const char *name, int instance_id, bool usebasename, const map->list[im].m = im; map->list[im].instance_id = instance_id; map->list[im].instance_src_map = m; + map->list[im].flag.src4instance = 0; //clear map->list[m].flag.src4instance = 1; // Flag this map as a src map for instances RECREATE(instance->list[instance_id].map, unsigned short, ++instance->list[instance_id].num_map); @@ -271,6 +275,21 @@ int instance_map2imap(int16 m, int instance_id) { return -1; } +int instance_mapname2imap(const char *map_name, int instance_id) { + int i; + + if( !instance->valid(instance_id) ) { + return -1; + } + + for( i = 0; i < instance->list[instance_id].num_map; i++ ) { + if( instance->list[instance_id].map[i] && !strcmpi(map->list[map->list[instance->list[instance_id].map[i]].instance_src_map].name,map_name) ) + return instance->list[instance_id].map[i]; + } + return -1; +} + + /*-------------------------------------- * m : source map * instance_id : where to search @@ -291,7 +310,6 @@ int instance_mapid2imapid(int16 m, int instance_id) { } /*-------------------------------------- - * map_instance_map_npcsub * Used on Init instance. Duplicates each script on source map *--------------------------------------*/ int instance_map_npcsub(struct block_list* bl, va_list args) { @@ -304,6 +322,19 @@ int instance_map_npcsub(struct block_list* bl, va_list args) { return 1; } +int instance_init_npc(struct block_list* bl, va_list args) { + struct npc_data *nd = (struct npc_data*)bl; + struct event_data *ev; + char evname[EVENT_NAME_LENGTH]; + + snprintf(evname, EVENT_NAME_LENGTH, "%s::OnInstanceInit", nd->exname); + + if( ( ev = strdb_get(npc->ev_db, evname) ) ) + script->run(ev->nd->u.scr.script, ev->pos, 0, ev->nd->bl.id); + + return 1; +} + /*-------------------------------------- * Init all map on the instance. Npcs are created here *--------------------------------------*/ @@ -314,8 +345,11 @@ void instance_init(int instance_id) { return; // nothing to do for( i = 0; i < instance->list[instance_id].num_map; i++ ) - map->foreachinmap(instance_map_npcsub, map->list[instance->list[instance_id].map[i]].instance_src_map, BL_NPC, instance->list[instance_id].map[i]); + map->foreachinmap(instance->map_npcsub, map->list[instance->list[instance_id].map[i]].instance_src_map, BL_NPC, instance->list[instance_id].map[i]); + /* cant be together with the previous because it will rely on all of them being up */ + map->foreachininstance(instance->init_npc, instance_id, BL_NPC); + instance->list[instance_id].state = INSTANCE_BUSY; } @@ -566,9 +600,11 @@ void instance_set_timeout(int instance_id, unsigned int progress_timeout, unsign if( progress_timeout ) { instance->list[instance_id].progress_timeout = now + progress_timeout; instance->list[instance_id].progress_timer = timer->add( timer->gettick() + progress_timeout * 1000, instance->destroy_timer, instance_id, 0); + instance->list[instance_id].original_progress_timeout = progress_timeout; } else { instance->list[instance_id].progress_timeout = 0; instance->list[instance_id].progress_timer = INVALID_TIMER; + instance->list[instance_id].original_progress_timeout = 0; } if( idle_timeout ) { @@ -600,6 +636,37 @@ void instance_check_kick(struct map_session_data *sd) { } } +void do_reload_instance(void) { + struct s_mapiterator *iter; + struct map_session_data *sd; + int i, k; + + for(i = 0; i < instance->instances; i++) { + for(k = 0; k < instance->list[i].num_map; k++) { + if( !map->list[map->list[instance->list[i].map[k]].instance_src_map].flag.src4instance ) + break; + } + + if( k != instance->list[i].num_map ) /* any (or all) of them were disabled, we destroy */ + instance->destroy(i); + else { + /* populate the instance again */ + instance->start(i); + /* restart timers */ + instance->set_timeout(i,instance->list[i].original_progress_timeout,instance->list[i].idle_timeoutval); + } + } + + iter = mapit_getallusers(); + for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) { + if(sd && map->list[sd->bl.m].instance_id >= 0) { + pc->setpos(sd,instance->list[map->list[sd->bl.m].instance_id].respawn.map,instance->list[map->list[sd->bl.m].instance_id].respawn.x,instance->list[map->list[sd->bl.m].instance_id].respawn.y,CLR_TELEPORT); + } + } + mapit->free(iter); +} + + void do_final_instance(void) { int i; @@ -623,7 +690,7 @@ void instance_defaults(void) { instance->init = do_init_instance; instance->final = do_final_instance; - + instance->reload = do_reload_instance; /* start point */ instance->start_id = 0; /* count */ @@ -636,6 +703,9 @@ void instance_defaults(void) { instance->del_map = instance_del_map; instance->map2imap = instance_map2imap; instance->mapid2imapid = instance_mapid2imapid; + instance->mapname2imap = instance_mapname2imap; + instance->map_npcsub = instance_map_npcsub; + instance->init_npc = instance_init_npc; instance->destroy = instance_destroy; instance->start = instance_init; instance->check_idle = instance_check_idle; diff --git a/src/map/instance.h b/src/map/instance.h index ba6d26d59..449ca42c6 100644 --- a/src/map/instance.h +++ b/src/map/instance.h @@ -40,11 +40,16 @@ struct instance_data { int idle_timer; unsigned int idle_timeout, idle_timeoutval; + + unsigned int original_progress_timeout; + + struct point respawn;/* reload spawn */ }; struct instance_interface { void (*init) (void); void (*final) (void); + void (*reload) (void); /* start point */ unsigned short start_id; unsigned short instances;/* count */ @@ -56,6 +61,9 @@ struct instance_interface { void (*del_map) (int16 m); int (*map2imap) (int16 m, int instance_id); int (*mapid2imapid) (int16 m, int instance_id); + int (*mapname2imap) (const char *map_name, int instance_id); + int (*map_npcsub) (struct block_list* bl, va_list args); + int (*init_npc) (struct block_list* bl, va_list args); void (*destroy) (int instance_id); void (*start) (int instance_id); void (*check_idle) (int instance_id); diff --git a/src/map/npc.c b/src/map/npc.c index c52dce325..c536dc856 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -3439,6 +3439,8 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char map->list[m].short_damage_rate = (state) ? atoi(w4) : 100; } else if ( !strcmpi(w3,"long_damage_rate") ) { map->list[m].long_damage_rate = (state) ? atoi(w4) : 100; + } else if ( !strcmpi(w3,"src4instance") ) { + map->list[m].flag.src4instance = (state) ? 1 : 0; } else ShowError("npc_parse_mapflag: unrecognized mapflag '%s' (file '%s', line '%d').\n", w3, filepath, strline(buffer,start-buffer)); @@ -3784,10 +3786,8 @@ int npc_reload(void) { npc_id - npc_new_min, npc_warp, npc_shop, npc_script, npc_mob, npc_cache_mob, npc_delay_mob); itemdb->name_constants(); - - for(i = 0; i < instance->instances; i++) { - instance->destroy(i); - } + + instance->reload(); map->zone_init(); diff --git a/src/map/pc.c b/src/map/pc.c index 157d9e28a..b39ae1c59 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -4791,6 +4791,14 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y stop = true; } } + /* we hit a instance, if empty we populate the spawn data */ + if( map->list[m].instance_id >= 0 && instance->list[map->list[m].instance_id].respawn.map == 0 && + instance->list[map->list[m].instance_id].respawn.x == 0 && + instance->list[map->list[m].instance_id].respawn.y == 0) { + instance->list[map->list[m].instance_id].respawn.map = mapindex; + instance->list[map->list[m].instance_id].respawn.x = x; + instance->list[map->list[m].instance_id].respawn.y = y; + } } sd->state.changemap = (sd->mapindex != mapindex); diff --git a/src/map/script.c b/src/map/script.c index c74eff07b..e6d23541a 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -17455,6 +17455,74 @@ BUILDIN(bg_match_over) { return true; } + +BUILDIN(instance_mapname) { + const char *map_name; + int m; + short instance_id = -1; + + map_name = script_getstr(st,2); + + if( script_hasdata(st,3) ) + instance_id = script_getnum(st,3); + else + instance_id = st->instance_id; + + // Check that instance mapname is a valid map + if( instance_id == -1 || (m = instance->mapname2imap(map_name,instance_id)) == -1 ) + script_pushconststr(st, ""); + else + script_pushconststr(st, map->list[m].name); + + return true; +} +/* modify an instances' reload-spawn point */ +/* instance_set_respawn ,,{,} */ +/* returns 1 when successful, 0 otherwise. */ +BUILDIN(instance_set_respawn) { + const char *map_name; + short instance_id = -1; + short mid; + short x,y; + + map_name = script_getstr(st,2); + x = script_getnum(st, 3); + y = script_getnum(st, 4); + + if( script_hasdata(st, 5) ) + instance_id = script_getnum(st, 5); + else + instance_id = st->instance_id; + + if( instance_id == -1 || !instance->valid(instance_id) ) + script_pushint(st, 0); + else if( (mid = map->mapname2mapid(map_name)) == -1 ) { + ShowError("buildin_instance_set_respawn: unknown map '%s'\n",map_name); + script_pushint(st, 0); + } else { + int i; + + for(i = 0; i < instance->list[instance_id].num_map; i++) { + if( map->list[instance->list[instance_id].map[i]].m == mid ) { + instance->list[instance_id].respawn.map = map_id2index(mid); + instance->list[instance_id].respawn.x = x; + instance->list[instance_id].respawn.y = y; + break; + } + } + + if( i != instance->list[instance_id].num_map ) + script_pushint(st, 1); + else { + ShowError("buildin_instance_set_respawn: map '%s' not part of instance '%s'\n",map_name,instance->list[instance_id].name); + script_pushint(st, 0); + } + } + + + return true; +} + // declarations that were supposed to be exported from npc_chat.c #ifdef PCRE_SUPPORT BUILDIN(defpattern); @@ -17920,6 +17988,9 @@ void script_parse_builtin(void) { BUILDIN_DEF(has_instance,"s?"), BUILDIN_DEF(instance_warpall,"sii?"), BUILDIN_DEF(instance_check_party,"i???"), + BUILDIN_DEF(instance_mapname,"s?"), + BUILDIN_DEF(instance_set_respawn,"sii?"), + /** * 3rd-related **/ -- cgit v1.2.3-70-g09d2