Pārlūkot izejas kodu

Added returning to instances (#7622)

Fixes #5226

Thanks to @Forte22, @attackjom and @OptimusM

Co-authored-by: Aleos <aleos89@users.noreply.github.com>
Lemongrass3110 2 gadi atpakaļ
vecāks
revīzija
49ba072f3a

+ 7 - 0
conf/battle/feature.conf

@@ -168,3 +168,10 @@ feature.mesitemlink_dbname: no
 // Stylist UI (Note 1)
 // Requires: 2015-11-04 or later
 feature.stylist: on
+
+// Are players allowed to reconnect into instances? (Note 1)
+// This is enabled by default in Renewal mode and
+// disabled by default in Pre-Renewal mode.
+// If this is allowed the "nosave" mapflag is still being respected
+// and may prevent players from warping back into the instance.
+//feature.instance_allow_reconnect: yes

+ 1 - 29
npc/mapflag/nosave.txt

@@ -7,6 +7,7 @@
 //= 1.7 Updated. [Lupus]
 //= 1.8 Updated. [L0ne_W0lf]
 //= 1.9 Renewal split. [Euphy]
+//= 2.0 Moved instances to pre-renewal. [Lemongrass]
 //============================================================
 
 //============================================================
@@ -268,23 +269,6 @@ que_qaru03	mapflag	nosave	SavePoint
 que_qaru04	mapflag	nosave	SavePoint
 que_qaru05	mapflag	nosave	SavePoint
 
-//============================================================
-// Sealed Shrine
-//============================================================
-1@cata	mapflag	nosave	SavePoint
-2@cata	mapflag	nosave	SavePoint
-
-//============================================================
-// Endless Tower
-//============================================================
-e_tower	mapflag	nosave	SavePoint
-1@tower	mapflag	nosave	SavePoint
-2@tower	mapflag	nosave	SavePoint
-3@tower	mapflag	nosave	SavePoint
-4@tower	mapflag	nosave	SavePoint
-5@tower	mapflag	nosave	SavePoint
-6@tower	mapflag	nosave	SavePoint
-
 //============================================================
 // Battlegrounds
 //============================================================
@@ -307,18 +291,6 @@ schg_dun01	mapflag	nosave	SavePoint
 arug_que01	mapflag	nosave	SavePoint
 arug_dun01	mapflag	nosave	SavePoint
 
-//============================================================
-// Orc's Memory
-//============================================================
-1@orcs	mapflag	nosave	SavePoint
-2@orcs	mapflag	nosave	SavePoint
-
-//============================================================
-// Nidhoggr's Instance
-//============================================================
-1@nyd	mapflag	nosave	SavePoint
-2@nyd	mapflag	nosave	SavePoint
-
 //============================================================
 // RWC
 //============================================================

+ 37 - 0
npc/pre-re/mapflag/nosave.txt

@@ -0,0 +1,37 @@
+//===== rAthena Script =======================================
+//= Mapflag: Disable auto-save.
+//===== Description: ========================================= 
+//= Characters logging out on the specified map will be warped
+//= to the map specified in the last field, or "SavePoint".
+//===== Additional Comments: ================================= 
+//= 1.0 Renewal Split. [Lemongrass]
+//============================================================
+
+//============================================================
+// Endless Tower
+//============================================================
+e_tower	mapflag	nosave	SavePoint
+1@tower	mapflag	nosave	SavePoint
+2@tower	mapflag	nosave	SavePoint
+3@tower	mapflag	nosave	SavePoint
+4@tower	mapflag	nosave	SavePoint
+5@tower	mapflag	nosave	SavePoint
+6@tower	mapflag	nosave	SavePoint
+
+//============================================================
+// Sealed Shrine
+//============================================================
+1@cata	mapflag	nosave	SavePoint
+2@cata	mapflag	nosave	SavePoint
+
+//============================================================
+// Orc's Memory
+//============================================================
+1@orcs	mapflag	nosave	SavePoint
+2@orcs	mapflag	nosave	SavePoint
+
+//============================================================
+// Nidhoggr's Instance
+//============================================================
+1@nyd	mapflag	nosave	SavePoint
+2@nyd	mapflag	nosave	SavePoint

+ 1 - 241
npc/re/mapflag/nosave.txt

@@ -6,6 +6,7 @@
 //===== Changelogs: ==========================================
 //= 1.0 Renewal split. [Euphy]
 //= 1.1 Added GVG TE Guild Dungeons. [Capuche]
+//= 1.2 Removed instances. [Lemongrass]
 //============================================================
 
 //============================================================
@@ -60,27 +61,10 @@ te_aldecas3	mapflag	nosave	SavePoint
 te_aldecas4	mapflag	nosave	SavePoint
 te_aldecas5	mapflag	nosave	SavePoint
 
-//============================================================
-// Misty Forest Labyrinth
-//============================================================
-1@mist	mapflag	nosave	SavePoint
-
-//============================================================
-// Octopus Cave
-//============================================================
-1@cash	mapflag	nosave	SavePoint
-
-//============================================================
-// Drain
-//============================================================
-1@pump	mapflag	nosave	SavePoint
-2@pump	mapflag	nosave	SavePoint
-
 //============================================================
 // Somatology Laboratory
 //============================================================
 que_lhz	mapflag	nosave	SavePoint
-1@lhz	mapflag	nosave	SavePoint
 
 //============================================================
 // Port Malaya
@@ -95,246 +79,22 @@ ma_zif07	mapflag	nosave	SavePoint
 ma_zif08	mapflag	nosave	SavePoint
 ma_zif09	mapflag	nosave	SavePoint
 
-//============================================================
-// Bangungot Hospital F2
-//============================================================
-1@ma_h	mapflag	nosave	SavePoint
-
-//============================================================
-// Buwaya Cave
-//============================================================
-1@ma_c	mapflag	nosave	SavePoint
-
-//============================================================
-// Bakonawa Hideout
-//============================================================
-1@ma_b	mapflag	nosave	SavePoint
-
 //============================================================
 // Inside Eclage
 //============================================================
 que_avan01	mapflag	nosave	SavePoint
-1@ecl	mapflag	nosave	SavePoint
-
-//============================================================
-// Glastheim Memorial Dungeon
-//============================================================
-1@gl_k	mapflag	nosave	SavePoint
-2@gl_k	mapflag	nosave	SavePoint
-
-//============================================================
-// Wave Mode Memorial Dungeon
-//============================================================
-1@def01	mapflag	nosave	SavePoint
-1@def02	mapflag	nosave	SavePoint
-1@def03	mapflag	nosave	SavePoint
-
-//============================================================
-// Heroes' Trail - Part 1
-//============================================================
-1@face	mapflag	nosave	SavePoint
-1@sara	mapflag	nosave	SavePoint
-
-//============================================================
-// Heroes' Trail - Part 2
-//============================================================
-1@ge_st	mapflag	nosave	SavePoint
-1@gef	mapflag	nosave	SavePoint
-1@gef_in	mapflag	nosave	SavePoint
-1@spa	mapflag	nosave	SavePoint
-1@tnm1	mapflag	nosave	SavePoint
-1@tnm2	mapflag	nosave	SavePoint
-1@tnm3	mapflag	nosave	SavePoint
-
-//============================================================
-// Horror Toy Factory Memorial Dungeon
-//============================================================
-1@xm_d	mapflag	nosave	SavePoint
-
-//============================================================
-// Heroes' Trail - Part 3
-//============================================================
-1@glast	mapflag	nosave	SavePoint
-1@air1	mapflag	nosave	SavePoint
-1@air2	mapflag	nosave	SavePoint
-
-//============================================================
-// Decisive Battle - Part 1
-//============================================================
-1@dth1	mapflag	nosave	SavePoint
-1@dth2	mapflag	nosave	SavePoint
-1@dth3	mapflag	nosave	SavePoint
-1@rev	mapflag	nosave	SavePoint
-
-//============================================================
-// Decisive Battle - Part 2
-//============================================================
-1@eom	mapflag	nosave	SavePoint
-1@jtb	mapflag	nosave	SavePoint
 
 //============================================================
 // Episode 15 - Phantasmagorica
 //============================================================
-1@lab	mapflag	nosave	SavePoint
-1@uns	mapflag	nosave	SavePoint
 un_myst	mapflag	nosave	SavePoint
-1@mcd	mapflag	nosave	SavePoint
-
-//============================================================
-// Infinite Space
-//============================================================
-1@infi	mapflag	nosave
 
 //============================================================
 // Episode 16.1 - Banquet of Heroes
 //============================================================
 que_swat	mapflag	nosave	SavePoint
-1@mir	mapflag	nosave	SavePoint
-2@mir	mapflag	nosave	SavePoint
-1@sthb	mapflag	nosave	SavePoint
-1@sthc	mapflag	nosave	SavePoint
-1@sthd	mapflag	nosave	SavePoint
-1@slw	mapflag	nosave	SavePoint
-1@swat	mapflag	nosave	SavePoint
 
 //============================================================
 // Rockridge
 //============================================================
 rockmi2	mapflag	nosave	SavePoint
-
-//============================================================
-// Memorial day
-//============================================================
-1@md_gef	mapflag	nosave	SavePoint
-1@md_pay	mapflag	nosave	SavePoint
-
-//============================================================
-// Chicken Mode - Nightmare Glastheim
-//============================================================
-1@gl_k2	mapflag	nosave	SavePoint
-2@gl_k2	mapflag	nosave	SavePoint
-
-//============================================================
-// Chicken Mode - Horror Toy Factory
-//============================================================
-1@xm_d2	mapflag	nosave	SavePoint
-
-//============================================================
-// Suspicious Shipwreck
-//============================================================
-1@tre	mapflag	nosave	SavePoint
-
-//============================================================
-// Poring Village
-//============================================================
-1@begi	mapflag	nosave	SavePoint
-
-//============================================================
-// Volcanic Island Korodo
-//============================================================
-1@crd	mapflag	nosave	SavePoint
-
-//============================================================
-// Noodles Festival July
-//============================================================
-1@drdo	mapflag	nosave	SavePoint
-
-//============================================================
-// Soul Reaper Job Change
-//============================================================
-1@soul	mapflag	nosave	SavePoint
-
-//============================================================
-// Episode 17.1
-//============================================================
-1@cor	mapflag	nosave	SavePoint
-1@os_a	mapflag	nosave	SavePoint
-1@os_b	mapflag	nosave	SavePoint
-1@rgsr	mapflag	nosave	SavePoint
-
-//============================================================
-// Episode 17.2
-//============================================================
-1@bamn	mapflag	nosave	SavePoint
-1@bamq	mapflag	nosave	SavePoint
-1@ghg	mapflag	nosave	SavePoint
-1@herbs	mapflag	nosave	SavePoint
-1@lost	mapflag	nosave	SavePoint
-1@odin	mapflag	nosave	SavePoint
-
-//============================================================
-// 4th Jobs Change
-//============================================================
-1@4win	mapflag	nosave	SavePoint
-1@4mag	mapflag	nosave	SavePoint
-1@4mst	mapflag	nosave	SavePoint
-1@4sac	mapflag	nosave	SavePoint
-1@4tro	mapflag	nosave	SavePoint
-1@4inq	mapflag	nosave	SavePoint
-1@4cdn	mapflag	nosave	SavePoint
-1@4igd	mapflag	nosave	SavePoint
-1@4drk	mapflag	nosave	SavePoint
-
-//============================================================
-// Geffen Night Arena
-//============================================================
-1@ge_sn	mapflag	nosave	SavePoint
-
-//============================================================
-// Traces of Heroes
-//============================================================
-1@mjo1	mapflag	nosave	SavePoint
-1@mjo2	mapflag	nosave	SavePoint
-1@spa2	mapflag	nosave	SavePoint
-
-//============================================================
-// Thanatos Tower Memorial Dungeon
-//============================================================
-1@thts	mapflag	nosave	SavePoint
-2@thts	mapflag	nosave	SavePoint
-3@thts	mapflag	nosave	SavePoint
-4@thts	mapflag	nosave	SavePoint
-5@thts	mapflag	nosave	SavePoint
-6@thts	mapflag	nosave	SavePoint
-7@thts	mapflag	nosave	SavePoint
-8@thts	mapflag	nosave	SavePoint
-
-//============================================================
-// Glastheim Challenge Mode
-//============================================================
-1@gl_he	mapflag	nosave	SavePoint
-1@gl_he2	mapflag	nosave	SavePoint
-
-//============================================================
-// EDDA
-//============================================================
-1@gl_prq	mapflag	nosave	SavePoint
-1@gol1	mapflag	nosave	SavePoint
-1@gol2	mapflag	nosave	SavePoint
-
-//============================================================
-// 2018 Halloween
-//============================================================
-1@halo	mapflag	nosave	SavePoint
-
-//============================================================
-// Constellation Tower
-//============================================================
-1@ch_t	mapflag	nosave	SavePoint
-2@ch_t	mapflag	nosave	SavePoint
-3@ch_t	mapflag	nosave	SavePoint
-
-//============================================================
-// Episode 18 - Direction of Prayer
-//============================================================
-1@adv	mapflag	nosave	SavePoint
-1@advs	mapflag	nosave	SavePoint
-1@nyr	mapflag	nosave	SavePoint
-1@oz	mapflag	nosave	SavePoint
-1@tcamp	mapflag	nosave	SavePoint
-2@nyr	mapflag	nosave	SavePoint
-
-//============================================================
-// Sunken Tower
-//============================================================
-1@ch_u	mapflag	nosave	SavePoint

+ 1 - 0
sql-files/main.sql

@@ -259,6 +259,7 @@ CREATE TABLE IF NOT EXISTS `char` (
   `last_map` varchar(11) NOT NULL default '',
   `last_x` smallint(4) unsigned NOT NULL default '53',
   `last_y` smallint(4) unsigned NOT NULL default '111',
+  `last_instanceid` int(11) unsigned NOT NULL default '0',
   `save_map` varchar(11) NOT NULL default '',
   `save_x` smallint(4) unsigned NOT NULL default '53',
   `save_y` smallint(4) unsigned NOT NULL default '111',

+ 3 - 0
sql-files/upgrades/upgrade_20230224.sql

@@ -0,0 +1,3 @@
+ALTER TABLE `char`
+	ADD COLUMN `last_instanceid` int(11) unsigned NOT NULL default '0' AFTER `last_y`
+;

+ 10 - 8
src/char/char.cpp

@@ -279,7 +279,7 @@ int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){
 		(p->job_level != cp->job_level) || (p->job_exp != cp->job_exp) ||
 		(p->zeny != cp->zeny) ||
 		( strncmp( p->last_point.map, cp->last_point.map, sizeof( p->last_point.map ) ) != 0 ) ||
-		(p->last_point.x != cp->last_point.x) || (p->last_point.y != cp->last_point.y) ||
+		(p->last_point.x != cp->last_point.x) || (p->last_point.y != cp->last_point.y) || (p->last_point_instanceid != cp->last_point_instanceid) || 
 		( strncmp( p->save_point.map, cp->save_point.map, sizeof( p->save_point.map ) ) != 0 ) ||
 		( p->save_point.x != cp->save_point.x ) || ( p->save_point.y != cp->save_point.y ) ||
 		(p->max_hp != cp->max_hp) || (p->hp != cp->hp) ||
@@ -307,7 +307,8 @@ int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){
 			"`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d',"
 			"`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d',`elemental_id`='%d',"
 			"`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d',"
-			"`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d',"
+			"`last_map`='%s',`last_x`='%d',`last_y`='%d',`last_instanceid`='%d',"
+			"`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d',"
 			"`delete_date`='%lu',`robe`='%d',`moves`='%d',`font`='%u',`uniqueitem_counter`='%u',"
 			"`hotkey_rowshift`='%d', `clan_id`='%d', `title_id`='%lu', `show_equip`='%d', `hotkey_rowshift2`='%d',"
 			"`max_ap`='%u',`ap`='%u',`trait_point`='%d',"
@@ -319,7 +320,7 @@ int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){
 			p->str, p->agi, p->vit, p->int_, p->dex, p->luk,
 			p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, p->ele_id,
 			p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom,
-			p->last_point.map, p->last_point.x, p->last_point.y,
+			p->last_point.map, p->last_point.x, p->last_point.y, p->last_point_instanceid,
 			p->save_point.map, p->save_point.x, p->save_point.y, p->rename,
 			(unsigned long)p->delete_date, // FIXME: platform-dependent size
 			p->robe, p->character_moves, p->font, p->uniqueitem_counter,
@@ -1060,7 +1061,7 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
 		"`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`, `moves`,"
 		"`unban_time`,`font`,`uniqueitem_counter`,`sex`,`hotkey_rowshift`,`clan_id`,`title_id`,`show_equip`,`hotkey_rowshift2`,"
 		"`max_ap`,`ap`,`trait_point`,`pow`,`sta`,`wis`,`spl`,`con`,`crt`,"
-		"`inventory_slots`,`body_direction`,`disable_call`"
+		"`inventory_slots`,`body_direction`,`disable_call`,`last_instanceid`"
 		" FROM `%s` WHERE `char_id`=? LIMIT 1", schema_config.char_db)
 	||	SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
 	||	SQL_ERROR == SqlStmt_Execute(stmt)
@@ -1138,7 +1139,8 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 71, SQLDT_SHORT,  &p->crt, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 72, SQLDT_UINT16, &p->inventory_slots, 0, NULL, NULL)
 	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 73, SQLDT_UINT8,  &p->body_direction, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 74, SQLDT_UINT16, &p->disable_call, 0, NULL, NULL)
+	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 74, SQLDT_UINT8,	&p->disable_call, 0, NULL, NULL)
+	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 75, SQLDT_INT,    &p->last_point_instanceid, 0, NULL, NULL)
 	)
 	{
 		SqlStmt_ShowDebug(stmt);
@@ -1516,8 +1518,8 @@ int char_make_new_char( struct char_session_data* sd, char* name_, int str, int
 
 	//Insert the new char entry to the database
 	if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `class`, `zeny`, `status_point`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`,"
-		"`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`, `sex`) VALUES ("
-		"'%d', '%d', '%s', '%d', '%d',  '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%u', '%u', '%u', '%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d', '%c')",
+		"`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`, `sex`, `last_instanceid`) VALUES ("
+		"'%d', '%d', '%s', '%d', '%d',  '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%u', '%u', '%u', '%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d', '%c', '0')",
 		schema_config.char_db, sd->account_id , slot, esc_name, start_job, charserv_config.start_zeny, status_points, str, agi, vit, int_, dex, luk,
 		(40 * (100 + vit)/100) , (40 * (100 + vit)/100 ),  (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
 		tmp_start_point[start_point_idx].map, tmp_start_point[start_point_idx].x, tmp_start_point[start_point_idx].y, tmp_start_point[start_point_idx].map, tmp_start_point[start_point_idx].x, tmp_start_point[start_point_idx].y, sex ) )
@@ -2330,7 +2332,7 @@ bool char_checkdb(void){
 		"`moves`,`unban_time`,`font`,`sex`,`hotkey_rowshift`,`clan_id`,`last_login`,`title_id`,`show_equip`,"
 		"`hotkey_rowshift2`,"
 		"`max_ap`,`ap`,`trait_point`,`pow`,`sta`,`wis`,`spl`,`con`,`crt`,"
-		"`inventory_slots`,`body_direction`,`disable_call`"
+		"`inventory_slots`,`body_direction`,`disable_call`,`last_instanceid`"
 		" FROM `%s` LIMIT 1;", schema_config.char_db) ){
 		Sql_ShowDebug(sql_handle);
 		return false;

+ 1 - 0
src/common/mmo.hpp

@@ -595,6 +595,7 @@ struct mmo_charstatus {
 	uint16 mapport;
 
 	struct s_point_str last_point;
+	int32 last_point_instanceid;
 	struct s_point_str save_point;
 	struct s_point_str memo_point[MAX_MEMOPOINTS];
 	struct s_skill skill[MAX_SKILL];

+ 5 - 0
src/map/battle.cpp

@@ -10458,6 +10458,11 @@ static const struct _battle_data {
 
 	{ "feature.stylist",                    &battle_config.feature_stylist,                 1,      0,      1,              },
 	{ "feature.banking_state_enforce",      &battle_config.feature_banking_state_enforce,   0,      0,      1,              },
+#ifdef RENEWAL
+	{ "feature.instance_allow_reconnect",   &battle_config.instance_allow_reconnect,        1,      0,      1,              },
+#else
+	{ "feature.instance_allow_reconnect",   &battle_config.instance_allow_reconnect,        0,      0,      1,              },
+#endif
 
 #include <custom/battle_config_init.inc>
 };

+ 1 - 0
src/map/battle.hpp

@@ -730,6 +730,7 @@ struct Battle_Config
 
 	int feature_stylist;
 	int feature_banking_state_enforce;
+	int instance_allow_reconnect;
 
 #include <custom/battle_config_struct.inc>
 };

+ 127 - 5
src/map/pc.cpp

@@ -1307,6 +1307,10 @@ void pc_makesavestatus(map_session_data *sd) {
 #else
 	sd->status.option = sd->sc.option&(OPTION_INVISIBLE|OPTION_CART|OPTION_FALCON|OPTION_RIDING|OPTION_DRAGON|OPTION_WUG|OPTION_WUGRIDER|OPTION_MADOGEAR);
 #endif
+
+	// Mark last point as not instance related by default
+	sd->status.last_point_instanceid = 0;
+
 	if (sd->sc.getSCE(SC_JAILED)) { //When Jailed, do not move last point.
 		if(pc_isdead(sd)){
 			pc_setrestartvalue(sd, 0);
@@ -1348,12 +1352,22 @@ void pc_makesavestatus(map_session_data *sd) {
 				sd->status.last_point.x = sd->status.save_point.x;
 				sd->status.last_point.y = sd->status.save_point.y;
 			}
-		// If the user is on a instance map, we return him to his save point
+		// If the user is on a instance map, special handling is needed
 		}else if( mapdata->instance_id ){
-			// Return the user to his save point
-			safestrncpy( sd->status.last_point.map, sd->status.save_point.map, sizeof( sd->status.last_point.map ) );
-			sd->status.last_point.x = sd->status.save_point.x;
-			sd->status.last_point.y = sd->status.save_point.y;
+			if( battle_config.instance_allow_reconnect ){
+				// Store the original mapname
+				struct map_data* mapdata_source = map_getmapdata( mapdata->instance_src_map );
+
+				mapindex_getmapname( mapindex_id2name( mapdata_source->index ), sd->status.last_point.map );
+				sd->status.last_point.x = sd->bl.x;
+				sd->status.last_point.y = sd->bl.y;
+				sd->status.last_point_instanceid = mapdata->instance_id;
+			}else{
+				// Return the user to his save point
+				safestrncpy( sd->status.last_point.map, sd->status.save_point.map, sizeof( sd->status.last_point.map ) );
+				sd->status.last_point.x = sd->status.save_point.x;
+				sd->status.last_point.y = sd->status.save_point.y;
+			}
 		}else{
 			// Save normally
 			mapindex_getmapname( mapindex_id2name( sd->mapindex ), sd->status.last_point.map );
@@ -1890,6 +1904,106 @@ uint8 pc_isequip(map_session_data *sd,int n)
 	return ITEM_EQUIP_ACK_OK;
 }
 
+/**
+ * Performs some special modifications to a player's last point location,
+ * if the map has a nosave mapflag or if the map was an instance.
+ * @param sd: Player data
+ * @return True if the player should be returned to his savepoint or false if not
+ */
+bool pc_lastpoint_special( map_session_data& sd ){
+	int16 mapid = map_mapname2mapid( sd.status.last_point.map );
+
+	// Should not happen because otherwise the char-server would have sent the player to another map-server
+	if( mapid < 0 ){
+		// Return the player to his savepoint
+		return true;
+	}
+
+	struct map_data* mapdata = map_getmapdata( mapid );
+
+	if( mapdata == nullptr ){
+		// Return the player to his savepoint
+		return true;
+	}
+
+	// Maybe since the player's logout the nosave mapflag was added to the map
+	if( mapdata->flag[MF_NOSAVE] ){
+		// The map has a specific return point
+		if( mapdata->save.map ){
+			safestrncpy( sd.status.last_point.map, mapindex_id2name( mapdata->save.map ), sizeof( sd.status.last_point.map ) );
+			sd.status.last_point.x = mapdata->save.x;
+			sd.status.last_point.y = mapdata->save.y;
+			return false;
+		}else{
+			// Return the user to his save point
+			return true;
+		}
+	}
+
+	// Check if the last point was an instance
+	if( sd.status.last_point_instanceid == 0 ){
+		// Nothing to do
+		return false;
+	}
+
+	// Check if returning to the instance is allowed in general
+	if( !battle_config.instance_allow_reconnect ){
+		// Return the player to his savepoint
+		return true;
+	}
+
+	std::shared_ptr<s_instance_data> instance_data = util::umap_find( instances, sd.status.last_point_instanceid );
+
+	if( instance_data == nullptr ){
+		// Instance does not exist anymore, return the player to his savepoint
+		return true;
+	}
+
+	switch( instance_data->mode ){
+		case IM_NONE:
+			// Cannot validate
+			break;
+		case IM_CHAR:
+			if( sd.status.char_id != instance_data->owner_id ){
+				// It is a character bound instance and the player is not the owner, return the player to his savepoint
+				return true;
+			}
+			break;
+		case IM_PARTY:
+			if( sd.status.party_id != instance_data->owner_id ){
+				// It is a party bound instance and the player is not in the party, return the player to his savepoint
+				return true;
+			}
+			break;
+		case IM_GUILD:
+			if( sd.status.guild_id != instance_data->owner_id ){
+				// It is a guild bound instance and the player is not in the guild, return the player to his savepoint
+				return true;
+			}
+			break;
+		case IM_CLAN:
+			if( sd.status.clan_id != instance_data->owner_id ){
+				// It is a clan bound instance and the player is not in the clan, return the player to his savepoint
+				return true;
+			}
+			break;
+	}
+
+	int16 imapid = instance_mapid( mapid, sd.status.last_point_instanceid );
+
+	if( imapid < 0 ){
+		// Instance does not contain this map anymore, return the player to his savepoint
+		return true;
+	}
+
+	// Overwrite the stored "source mapname" with the real mapname
+	instance_generate_mapname( mapid, sd.status.last_point_instanceid, sd.status.last_point.map );
+	// X/Y coordinates are already correct and do not need to be modified
+
+	// Dont warp the player back to his savepoint
+	return false;
+}
+
 /*==========================================
  * No problem with the session id
  * set the status that has been sent from char server
@@ -2030,6 +2144,14 @@ bool pc_authok(map_session_data *sd, uint32 login_id2, time_t expiration_time, i
 	sd->vars_ok = false;
 	sd->vars_received = 0x0;
 
+	// Check if the player's last point requires special handling and if conditions apply to return the player to his savepoint
+	if( pc_lastpoint_special( *sd ) ){
+		// The player should be warped back to his savepoint
+		safestrncpy( sd->status.last_point.map, sd->status.save_point.map, sizeof( sd->status.last_point.map ) );
+		sd->status.last_point.x = sd->status.save_point.x;
+		sd->status.last_point.y = sd->status.save_point.y;
+	}
+
 	//warp player
 	enum e_setpos setpos_result = pc_setpos( sd, mapindex_name2id( sd->status.last_point.map ), sd->status.last_point.x, sd->status.last_point.y, CLR_OUTSIGHT );
 	if( setpos_result != SETPOS_OK ){