summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorshennetsind <ind@henn.et>2013-10-19 16:22:04 -0300
committershennetsind <ind@henn.et>2013-10-19 16:22:04 -0300
commit93f61040ac281b84c038af72e322a03f60bc6e03 (patch)
tree8c70712c93f4c297b78c5ecb43a113df81dd5dbd /src
parentcd780e51999c6efa1084e6b41ba0efcaaa347b9e (diff)
downloadhercules-93f61040ac281b84c038af72e322a03f60bc6e03.tar.gz
hercules-93f61040ac281b84c038af72e322a03f60bc6e03.tar.bz2
hercules-93f61040ac281b84c038af72e322a03f60bc6e03.tar.xz
hercules-93f61040ac281b84c038af72e322a03f60bc6e03.zip
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 <ind@henn.et>
Diffstat (limited to 'src')
-rw-r--r--src/common/mmo.h2
-rw-r--r--src/map/instance.c78
-rw-r--r--src/map/instance.h8
-rw-r--r--src/map/npc.c8
-rw-r--r--src/map/pc.c8
-rw-r--r--src/map/script.c71
6 files changed, 166 insertions, 9 deletions
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 <map_name>,<x>,<y>{,<instance_id>} */
+/* 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
**/