浏览代码

Expanded the instance system to support new modes
* New modes include: No player attached, single player, and guild.
* Expanded script command instance_create to take in an owner ID and an optional mode.
* Added a new script command instance_check_guild (works the same as instance_check_party).
* Refactored all instance_id to unsigned short.

aleos89 9 年之前
父节点
当前提交
c97be60bbf
共有 15 个文件被更改,包括 666 次插入245 次删除
  1. 55 20
      doc/script_commands.txt
  2. 1 0
      src/common/mmo.h
  3. 48 29
      src/map/clif.c
  4. 4 4
      src/map/clif.h
  5. 24 0
      src/map/guild.c
  6. 316 118
      src/map/instance.c
  7. 28 12
      src/map/instance.h
  8. 4 4
      src/map/map.c
  9. 3 3
      src/map/map.h
  10. 1 1
      src/map/party.c
  11. 1 1
      src/map/party.h
  12. 14 3
      src/map/pc.c
  13. 2 0
      src/map/pc.h
  14. 159 50
      src/map/script.c
  15. 6 0
      src/map/script_constants.h

+ 55 - 20
doc/script_commands.txt

@@ -472,8 +472,8 @@ nothing  - A permanent variable attached to the character, the default variable
            ends it. When a scope ends, its variables are converted to values 
            ('return .@var;' returns a value, not a reference).
 "'"      - An instance variable.
-           These are used with the instancing system, and are unique to each 
-           party's instance.
+           These are used with the instancing system and are unique to each 
+           instance type.
 "#"      - A permanent local account variable.
            They are stored by char-server in the `acc_reg_num` table and
            `acc_reg_str`.
@@ -503,6 +503,8 @@ $@name$ - temporary global string variable
  .name$ - NPC string variable
 .@name  - scope integer variable
 .@name$ - scope string variable
+ 'name  - instance integer variable
+ 'name$ - instance string variable
  #name  - permanent local account integer variable
  #name$ - permanent local account string variable
 ##name  - permanent global account integer variable
@@ -8111,13 +8113,19 @@ This command will open a book item at the specified page.
 ========================
 ---------------------------------------
 
-*instance_create("<instance name>");
+*instance_create("<instance name>",<owner_id>{,<mode>});
 
-Creates an instance for the party of the attached player. The instance name,
-along with all other instance data, is read from 'db/(pre-)re/instance_db.txt'.
-Upon success, the command generates a unique instance ID, duplicates all listed
-maps and NPCs, sets the alive time, and triggers the "OnInstanceInit" label in
-all NPCs inside the instance.
+Creates an instance for the <owner_id> of <mode>. The instance name, along with
+all other instance data, is read from 'db/(pre-)re/instance_db.txt'. Upon success,
+the command generates a unique instance ID, duplicates all listed maps and NPCs,
+sets the alive time, and triggers the "OnInstanceInit" label in all NPCs inside
+the instance.
+
+Instance Mode options:
+ IM_NONE: Attached to no one.
+ IM_CHAR: Attached to a single character.
+ IM_PARTY: Attached to a party (default instance mode).
+ IM_GUILD: Attached to a guild.
 
 The command returns the instance ID upon success, and these values upon failure:
  -1: Invalid type.
@@ -8131,8 +8139,9 @@ The command returns the instance ID upon success, and these values upon failure:
 
 Destroys instance with the ID <instance id>. If no ID is specified, the instance
 the script is attached to is used. If the script is not attached to an instance,
-the instance of the currently attached player's party is used. If that fails,
-the script will come to a halt.
+the instance of the currently attached player is used (if it is a party or guild
+mode). If it is not owned by anyone, no player needs to be attached. If that
+fails, the script will come to a halt.
 
 ---------------------------------------
 
@@ -8142,9 +8151,9 @@ Warps player to the specified instance after the script terminates. The map and
 coordinates are located in 'db/(pre-)re/instance_db.txt'.
 
 The command returns 0 upon success, and these values upon failure:
- 1: Party not found.
- 2: Party does not have an instance.
- 3: Other errors (invalid instance name, instance doesn't match with party).
+ 1: Party/Guild not found (for party/guild modes).
+ 2: Character/Party/Guild does not have an instance.
+ 3: Other errors (invalid instance name, instance doesn't match with character/party/guild).
 
 Put -1 for x and y if want to warp player with default entrance coordinates.
 
@@ -8163,16 +8172,18 @@ that fails, the script will come to a halt.
 
 Returns the unique name of the instanced map. If no instance ID is specified,
 the instance the script is attached to is used. If the script is not attached to
-an instance, the instance of the currently attached player's party is used. If
-that fails, the command returns an empty string instead.
+an instance, the instance of the currently attached player is used (if it is a
+party or guild mode). If it is not owned by anyone, no player needs to be
+attached. If that fails, the command returns an empty string instead.
 
 ---------------------------------------
 
 *instance_id()
 
 Returns the unique instance id of the attached script. If the script is not
-attached to an instance, the instance of the currently attached player's party is
-used. If that fails, the function will return 0.
+attached to an instance, the instance of the currently attached player is
+used (if it is a party or guild mode). If it is not owned by anyone, no
+player needs to be attached. If that fails, the function will return 0.
 
 ---------------------------------------
 
@@ -8181,8 +8192,9 @@ used. If that fails, the function will return 0.
 Warps all players in the instance <instance id> to <map name> at given
 coordinates. If no ID is specified, the instance the script is attached to
 is used. If the script is not attached to an instance, the instance of the
-currently attached player's party is used. If that fails, the script will
-come to a halt.
+currently attached player is used (if it is a party or guild mode). If it
+is not owned by anyone, no player needs to be attached. If that
+fails, the script will come to a halt.
 
 ---------------------------------------
 
@@ -8191,7 +8203,8 @@ come to a halt.
 Broadcasts a message to all players in the instance <instance id> currently
 residing on an instance map. If -1 is specified for <instance id>, the instance
 the script is attached to is used. If the script is not attached to an instance,
-the instance of the currently attached player's party is used.
+the instance of the currently attached player is used (if it is a party or guild
+mode). If it is not owned by anyone, no player needs to be attached.
 
 For details on the other parameters, see 'announce'.
 
@@ -8219,6 +8232,28 @@ if (instance_check_party(getcharid(1),2,2,149)) {
 
 ---------------------------------------
 
+*instance_check_guild(<guild id>{,<amount>{,<min>{,<max>}}})
+
+This function checks if a guild meets certain requirements, returning 1 if all
+conditions are met and 0 otherwise. It will only check online characters.
+
+amount - number of online guild members (default is 1).
+min    - minimum level of all characters in the guild (default is 1).
+max    - maximum level of all characters in the guild (default is max level in conf).
+
+Example:
+
+if (instance_check_guild(getcharid(2),2,2,149)) {
+	mes "Your guild meets the Memorial Dungeon requirements.",
+	mes "All online members are between levels 1-150 and at least two are online.";
+	close;
+} else {
+	mes "Sorry, your guild does not meet requirements.";
+	close;
+}
+
+---------------------------------------
+
 =========================
 |8.- Quest Log commands.|
 =========================

+ 1 - 0
src/common/mmo.h

@@ -563,6 +563,7 @@ struct guild {
 	struct guild_expulsion expulsion[MAX_GUILDEXPULSION];
 	struct guild_skill skill[MAX_GUILDSKILL];
 	struct Channel *channel;
+	unsigned short instance_id;
 
 	/* Used by char-server to save events for guilds */
 	unsigned short save_flag;

+ 48 - 29
src/map/clif.c

@@ -16572,80 +16572,99 @@ void clif_font(struct map_session_data *sd)
 }
 
 
-/*==========================================
- * Notifies party members of instance change
- *------------------------------------------*/
-void clif_instance_create(struct map_session_data *sd, const char *name, int num, int flag)
+/// Required to start the instancing information window on Client
+/// This window re-appears each "refresh" of client automatically until the keep_limit reaches 0.
+/// S 0x2cb <Instance name>.61B <Standby Position>.W
+void clif_instance_create(unsigned short instance_id, int num)
 {
 #if PACKETVER >= 20071128
+	struct map_session_data *sd = NULL;
+	enum send_target target = PARTY;
 	unsigned char buf[65];
 
-	if(!sd) return;
+	instance_getsd(instance_id, &sd, &target);
+
+	if (!sd)
+		return;
 
 	WBUFW(buf,0) = 0x2cb;
-	memcpy( WBUFP(buf,2), name, 62 );
+	memcpy(WBUFP(buf,2), instance_data[instance_id].name, 62);
 	WBUFW(buf,63) = num;
-	if(flag) // A timer has changed or been added
-		clif_send(buf,packet_len(0x2cb),&sd->bl,PARTY);
-	else	// No notification
-		clif_send(buf,packet_len(0x2cb),&sd->bl,SELF);
+	clif_send(buf,packet_len(0x2cb),&sd->bl,target);
 #endif
 
 	return;
 }
 
-void clif_instance_changewait(struct map_session_data *sd, int num, int flag)
+/// To announce Instancing queue creation if no maps available
+/// S 0x2cc <Standby Position>.W
+void clif_instance_changewait(unsigned short instance_id, int num)
 {
 #if PACKETVER >= 20071128
+	struct map_session_data *sd = NULL;
+	enum send_target target = PARTY;
 	unsigned char buf[4];
 
-	if(!sd) return;
+	instance_getsd(instance_id, &sd, &target);
+
+	if (!sd)
+		return;
 
 	WBUFW(buf,0) = 0x2cc;
 	WBUFW(buf,2) = num;
-	if(flag) // A timer has changed or been added
-		clif_send(buf,packet_len(0x2cc),&sd->bl,PARTY);
-	else	// No notification
-		clif_send(buf,packet_len(0x2cc),&sd->bl,SELF);
+	clif_send(buf,packet_len(0x2cc),&sd->bl,target);
 #endif
 
 	return;
 }
 
-void clif_instance_status(struct map_session_data *sd, const char *name, unsigned int limit1, unsigned int limit2, int flag)
+/// Notify the current status to members
+/// S 0x2cd <Instance Name>.61B <Instance Remaining Time>.L <Instance Noplayers close time>.L
+void clif_instance_status(unsigned short instance_id, unsigned int limit1, unsigned int limit2)
 {
 #if PACKETVER >= 20071128
+	struct map_session_data *sd = NULL;
+	enum send_target target = PARTY;
 	unsigned char buf[71];
 
-	if(!sd) return; //party_getavailablesd can return NULL
+	instance_getsd(instance_id, &sd, &target);
+
+	if (!sd)
+		return;
 
 	WBUFW(buf,0) = 0x2cd;
-	memcpy( WBUFP(buf,2), name, 62 );
+	memcpy(WBUFP(buf,2), instance_data[instance_id].name, 62);
 	WBUFL(buf,63) = limit1;
 	WBUFL(buf,67) = limit2;
-	if(flag) // A timer has changed or been added
-		clif_send(buf,packet_len(0x2cd),&sd->bl,PARTY);
-	else	// No notification
-		clif_send(buf,packet_len(0x2cd),&sd->bl,SELF);
+	clif_send(buf,packet_len(0x2cd),&sd->bl,target);
 #endif
 
 	return;
 }
 
-void clif_instance_changestatus(struct map_session_data *sd, int type, unsigned int limit, int flag)
+/// Notify a status change to members
+/// S 0x2ce <Message ID>.L
+/// 0 = Notification (EnterLimitDate update?)
+/// 1 = The Memorial Dungeon expired; it has been destroyed
+/// 2 = The Memorial Dungeon's entry time limit expired; it has been destroyed
+/// 3 = The Memorial Dungeon has been removed.
+/// 4 = Create failure (removes the instance window)
+void clif_instance_changestatus(unsigned int instance_id, int type, unsigned int limit)
 {
 #if PACKETVER >= 20071128
+	struct map_session_data *sd = NULL;
+	enum send_target target = PARTY;
 	unsigned char buf[10];
 
-	if(!sd) return;
+	instance_getsd(instance_id, &sd, &target);
+
+	if (!sd)
+		return;
 
 	WBUFW(buf,0) = 0x2ce;
 	WBUFL(buf,2) = type;
 	WBUFL(buf,6) = limit;
-	if(flag) // A timer has changed or been added
-		clif_send(buf,packet_len(0x2ce),&sd->bl,PARTY);
-	else	// No notification
-		clif_send(buf,packet_len(0x2ce),&sd->bl,SELF);
+	clif_send(buf,packet_len(0x2ce),&sd->bl,target);
 #endif
 
 	return;

+ 4 - 4
src/map/clif.h

@@ -745,10 +745,10 @@ void clif_sendbgemblem_area(struct map_session_data *sd);
 void clif_sendbgemblem_single(int fd, struct map_session_data *sd);
 
 // Instancing
-void clif_instance_create(struct map_session_data *sd, const char *name, int num, int flag);
-void clif_instance_changewait(struct map_session_data *sd, int num, int flag);
-void clif_instance_status(struct map_session_data *sd, const char *name, unsigned int limit1, unsigned int limit2, int flag);
-void clif_instance_changestatus(struct map_session_data *sd, int type, unsigned int limit, int flag);
+void clif_instance_create(unsigned short instance_id, int num);
+void clif_instance_changewait(unsigned short instance_id, int num);
+void clif_instance_status(unsigned short instance_id, unsigned int limit1, unsigned int limit2);
+void clif_instance_changestatus(unsigned int instance_id, int type, unsigned int limit);
 
 // Custom Fonts
 void clif_font(struct map_session_data *sd);

+ 24 - 0
src/map/guild.c

@@ -17,6 +17,7 @@
 #include "battle.h"
 #include "npc.h"
 #include "pc.h"
+#include "instance.h"
 #include "intif.h"
 #include "channel.h"
 #include "log.h"
@@ -551,6 +552,8 @@ int guild_recv_info(struct guild *sg) {
 			clif_guild_notice(sd, g);
 			sd->guild_emblem_id = g->emblem_id;
 		}
+		if (g->instance_id != 0)
+			instance_reqinfo(sd, g->instance_id);
 	}
 
 	//Occurrence of an event
@@ -694,6 +697,8 @@ void guild_member_joined(struct map_session_data *sd) {
 		g->member[i].sd = sd;
 		sd->guild = g;
 
+		if (g->instance_id != 0)
+			instance_reqinfo(sd, g->instance_id);
 		if( channel_config.ally_enable && channel_config.ally_autojoin ) {
 			channel_gjoin(sd,3);
 		}
@@ -744,6 +749,9 @@ int guild_member_added(int guild_id,uint32 account_id,uint32 char_id,int flag) {
 	//Next line commented because it do nothing, look at guild_recv_info [LuzZza]
 	//clif_charnameupdate(sd); //Update display name [Skotlex]
 
+	if (g->instance_id != 0)
+		instance_reqinfo(sd, g->instance_id);
+
 	return 0;
 }
 
@@ -860,6 +868,17 @@ int guild_member_withdraw(int guild_id, uint32 account_id, uint32 char_id, int f
 		sd->guild = NULL;
 		sd->guild_emblem_id = 0;
 
+		if (g->instance_id) {
+			int16 m = sd->bl.m;
+
+			if (map[m].instance_id) { // User was on the instance map
+				if (map[m].save.map)
+					pc_setpos(sd, map[m].save.map, map[m].save.x, map[m].save.y, CLR_TELEPORT);
+				else
+					pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
+			}
+		}
+
 		clif_charnameupdate(sd); //Update display name [Skotlex]
 		status_change_end(&sd->bl,SC_LEADERSHIP,INVALID_TIMER);
 		status_change_end(&sd->bl,SC_GLORYWOUNDS,INVALID_TIMER);
@@ -1833,6 +1852,11 @@ int guild_break(struct map_session_data *sd,char *name) {
 		return 0;
 	}
 
+	if (g->instance_id) {
+		instance_data[g->instance_id].owner_id = 0;
+		instance_destroy(g->instance_id);
+	}
+
 	/* Regardless of char server allowing it, we clear the guild master's auras */
 	if ((ud = unit_bl2ud(&sd->bl))) {
 		int count = 0;

+ 316 - 118
src/map/instance.c

@@ -11,6 +11,7 @@
 #include "../common/malloc.h"
 
 #include "clif.h"
+#include "guild.h"
 #include "instance.h"
 #include "map.h"
 #include "npc.h"
@@ -30,7 +31,8 @@ struct instance_data instance_data[MAX_INSTANCE_DATA];
 struct instance_db {
 	unsigned short id; ///< Instance ID
 	StringBuf *name; ///< Instance name
-	unsigned int limit; ///< Duration limit
+	unsigned int limit, ///< Duration limit
+				 timeout; ///< Timeout limit
 	struct {
 		StringBuf *mapname; ///< Mapname, the limit should be MAP_NAME_LENGTH_EXT
 		unsigned short x, y; ///< Map coordinates
@@ -59,6 +61,34 @@ static uint16 instance_name2id(const char *instance_name) {
 	return (uint16)strdb_uiget(InstanceNameDB,instance_name);
 }
 
+/**
+ * Search for a sd of an Instance
+ * @param instance_id: Instance ID
+ * @param sd: Player data to attach
+ * @param target: Target display type
+ */
+void instance_getsd(unsigned short instance_id, struct map_session_data **sd, enum send_target *target) {
+	switch(instance_data[instance_id].mode) {
+		case IM_NONE:
+			(*sd) = NULL;
+			(*target) = SELF;
+			break;
+		case IM_GUILD:
+			(*sd) = guild_getavailablesd(guild_search(instance_data[instance_id].owner_id));
+			(*target) = GUILD;
+			break;
+		case IM_PARTY:
+			(*sd) = party_getavailablesd(party_search(instance_data[instance_id].owner_id));
+			(*target) = PARTY;
+			break;
+		case IM_CHAR:
+			(*sd) = map_id2sd(instance_data[instance_id].owner_id);
+			(*target) = SELF;
+			break;
+	}
+	return;
+}
+
 /*==========================================
  * Searches for an instance name in the database
  *------------------------------------------*/
@@ -80,23 +110,42 @@ static int instance_delete_timer(int tid, unsigned int tick, int id, intptr_t da
 }
 
 /*==========================================
- * Create subscription timer for party
+ * Create subscription timer
  *------------------------------------------*/
 static int instance_subscription_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	int i, ret;
-	int instance_id = instance_wait.id[0];
-	struct party_data *p;
+	unsigned short instance_id = instance_wait.id[0];
+	struct map_session_data *sd = NULL;
+	struct party_data *p = NULL;
+	struct guild *g = NULL;
+	enum instance_mode mode;
 
-	if(instance_wait.count == 0 || instance_id <= 0)
+	if(instance_wait.count == 0 || instance_id == 0)
 		return 0;
 
 	// Check that maps have been added
 	ret = instance_addmap(instance_id);
-
-	// If no maps are created, tell party to wait
-	if(ret == 0 && ( p = party_search( instance_data[instance_id].party_id ) ) != NULL)
-		clif_instance_changewait( party_getavailablesd( p ), 0xffff, 1 );
+	mode = instance_data[instance_id].mode;
+
+	switch(mode) {
+		case IM_NONE:
+			break;
+		case IM_CHAR:
+			if (ret == 0 && (sd = map_id2sd(instance_data[instance_id].owner_id)) != NULL) // If no maps are created, tell player to wait
+				clif_instance_changewait(instance_id, 0xffff);
+			break;
+		case IM_PARTY:
+			if (ret == 0 && (p = party_search(instance_data[instance_id].owner_id)) != NULL) // If no maps are created, tell party to wait
+				clif_instance_changewait(instance_id, 0xffff);
+			break;
+		case IM_GUILD:
+			if (ret == 0 && (g = guild_search(instance_data[instance_id].owner_id)) != NULL) // If no maps are created, tell guild to wait
+				clif_instance_changewait(instance_id, 0xffff);
+			break;
+		default:
+			return 0;
+	}
 
 	instance_wait.count--;
 	memmove(&instance_wait.id[0],&instance_wait.id[1],sizeof(instance_wait.id[0])*instance_wait.count);
@@ -104,9 +153,9 @@ static int instance_subscription_timer(int tid, unsigned int tick, int id, intpt
 
 	for(i = 0; i < instance_wait.count; i++) {
 		if(	instance_data[instance_wait.id[i]].state == INSTANCE_IDLE &&
-			( p = party_search( instance_data[instance_wait.id[i]].party_id ) ) != NULL
+			((mode == IM_CHAR && sd != NULL) || (mode == IM_GUILD && g != NULL) || (mode == IM_PARTY && p != NULL))
 		){
-			clif_instance_changewait( party_getavailablesd( p ), i + 1, 1 );
+			clif_instance_changewait(instance_id, i + 1);
 		}
 	}
 
@@ -119,12 +168,11 @@ static int instance_subscription_timer(int tid, unsigned int tick, int id, intpt
 }
 
 /*==========================================
- * Adds timer back to party entering instance
+ * Adds timer back to members entering instance
  *------------------------------------------*/
-static int instance_startkeeptimer(struct instance_data *im, short instance_id)
+static int instance_startkeeptimer(struct instance_data *im, unsigned short instance_id)
 {
 	struct instance_db *db;
-	struct party_data *p;
 
 	nullpo_retr(0, im);
 
@@ -139,9 +187,24 @@ static int instance_startkeeptimer(struct instance_data *im, short instance_id)
 	im->keep_limit = (unsigned int)time(NULL) + db->limit;
 	im->keep_timer = add_timer(gettick()+db->limit*1000, instance_delete_timer, instance_id, 0);
 
-	// Notify party of the added instance timer
-	if( ( p = party_search( im->party_id ) ) != NULL )
-		clif_instance_status( party_getavailablesd( p ), StringBuf_Value(db->name), im->keep_limit, im->idle_limit, 1 );
+	switch(im->mode) {
+		case IM_NONE:
+			break;
+		case IM_CHAR:
+			if (map_id2sd(im->owner_id) != NULL) // Notify player of the added instance timer
+				clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+			break;
+		case IM_PARTY:
+			if (party_search(im->owner_id) != NULL) // Notify party of the added instance timer
+				clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+			break;
+		case IM_GUILD:
+			if (guild_search(im->owner_id) != NULL) // Notify guild of the added instance timer
+				clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+			break;
+		default:
+			return 1;
+	}
 
 	return 0;
 }
@@ -150,10 +213,9 @@ static int instance_startkeeptimer(struct instance_data *im, short instance_id)
  * Creates idle timer
  * Default before instance destroy is 5 minutes
  *------------------------------------------*/
-static int instance_startidletimer(struct instance_data *im, short instance_id)
+static int instance_startidletimer(struct instance_data *im, unsigned short instance_id)
 {
 	struct instance_db *db;
-	struct party_data *p;
 
 	nullpo_retr(1, im);
 
@@ -161,16 +223,30 @@ static int instance_startidletimer(struct instance_data *im, short instance_id)
 	if(im->idle_timer != INVALID_TIMER)
 		return 1;
 
+	if ((db = instance_searchtype_db(im->type)) == NULL)
+		return 1;
+
 	// Add the timer
 	im->idle_limit = (unsigned int)time(NULL) + INSTANCE_LIMIT/1000;
 	im->idle_timer = add_timer(gettick()+INSTANCE_LIMIT, instance_delete_timer, instance_id, 0);
 
-	// Notify party of added instance timer
-	if( ( p = party_search( im->party_id ) ) != NULL &&
-		( db = instance_searchtype_db( im->type ) ) != NULL
-		)
-	{
-		clif_instance_status( party_getavailablesd( p ), StringBuf_Value(db->name), im->keep_limit, im->idle_limit, 1 );
+	switch(im->mode) {
+		case IM_NONE:
+			break;
+		case IM_CHAR:
+			if (map_id2sd(im->owner_id) != NULL && instance_searchtype_db(im->type) != NULL) // Notify player of added instance timer
+				clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+			break;
+		case IM_PARTY:
+			if (party_search(im->owner_id) != NULL && instance_searchtype_db(im->type) != NULL) // Notify party of added instance timer
+				clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+			break;
+		case IM_GUILD:
+			if (guild_search(im->owner_id) != NULL && instance_searchtype_db(im->type) != NULL) // Notify guild of added instance timer
+				clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+			break;
+		default:
+			return 1;
 	}
 
 	return 0;
@@ -179,10 +255,8 @@ static int instance_startidletimer(struct instance_data *im, short instance_id)
 /*==========================================
  * Delete the idle timer
  *------------------------------------------*/
-static int instance_stopidletimer(struct instance_data *im)
+static int instance_stopidletimer(struct instance_data *im, unsigned short instance_id)
 {
-	struct party_data *p;
-
 	nullpo_retr(0, im);
 	
 	// No timer
@@ -194,9 +268,24 @@ static int instance_stopidletimer(struct instance_data *im)
 	delete_timer(im->idle_timer, instance_delete_timer);
 	im->idle_timer = INVALID_TIMER;
 
-	// Notify the party
-	if( ( p = party_search( im->party_id ) ) != NULL )
-		clif_instance_changestatus( party_getavailablesd( p ), 0, im->idle_limit, 1 );
+	switch(im->mode) {
+		case IM_NONE:
+			break;
+		case IM_CHAR:
+			if (map_id2sd(im->owner_id) != NULL) // Notify the player
+				clif_instance_changestatus(instance_id, 0, im->idle_limit);
+			break;
+		case IM_PARTY:
+			if (party_search(im->owner_id) != NULL) // Notify the party
+				clif_instance_changestatus(instance_id, 0, im->idle_limit);
+			break;
+		case IM_GUILD:
+			if (guild_search(im->owner_id) != NULL) // Notify the guild
+				clif_instance_changestatus(instance_id, 0, im->idle_limit);
+			break;
+		default:
+			return 1;
+	}
 
 	return 0;
 }
@@ -247,46 +336,84 @@ void instance_addnpc(struct instance_data *im)
 /*--------------------------------------
  * name : instance name
  * Return value could be
- * -4 = no free instances | -3 = already exists | -2 = party not found | -1 = invalid type
+ * -4 = no free instances | -3 = already exists | -2 = character/party/guild not found | -1 = invalid type
  * On success return instance_id
  *--------------------------------------*/
-int instance_create(int party_id, const char *name)
-{
-	short i;
+int instance_create(int owner_id, const char *name, enum instance_mode mode) {
 	struct instance_db *db = instance_searchname_db(name);
-	struct party_data *p = party_search(party_id);
-
-	if(db == NULL)
-		return -1;
-
-	if( p == NULL )
-		return -2;
-
-	if( p->instance_id )
-		return -3; // Party already instancing
+	struct map_session_data *sd = NULL;
+	struct party_data *p = NULL;
+	struct guild *g = NULL;
+	unsigned short i;
+
+	nullpo_retr(-1, db);
+
+	switch(mode) {
+		case IM_NONE:
+			break;
+		case IM_CHAR:
+			if ((sd = map_id2sd(owner_id)) == NULL) {
+				ShowError("instance_create: character %d not found for instance '%s'.\n", owner_id, name);
+				return -2;
+			}
+			if (sd->instance_id)
+				return -3; // Player already instancing
+			break;
+		case IM_PARTY:
+			if ((p = party_search(owner_id)) == NULL) {
+				ShowError("instance_create: party %d not found for instance '%s'.\n", owner_id, name);
+				return -2;
+			}
+			if (p->instance_id)
+				return -3; // Party already instancing
+			break;
+		case IM_GUILD:
+			if ((g = guild_search(owner_id)) == NULL) {
+				ShowError("instance_create: guild %d not found for instance '%s'.\n", owner_id, name);
+				return -2;
+			}
+			if (g->instance_id)
+				return -3; // Guild already instancing
+			break;
+		default:
+			ShowError("instance_create: unknown mode %u for owner_id %d and name %s.\n", mode, owner_id, name);
+			return -2;
+	}
 
 	// Searching a Free Instance
-	// 0 is ignored as this mean "no instance" on maps
+	// 0 is ignored as this means "no instance" on maps
 	ARR_FIND(1, MAX_INSTANCE_DATA, i, instance_data[i].state == INSTANCE_FREE);
 	if( i >= MAX_INSTANCE_DATA )
 		return -4;
 
 	instance_data[i].type = db->id;
 	instance_data[i].state = INSTANCE_IDLE;
-	instance_data[i].party_id = p->party.party_id;
+	instance_data[i].owner_id = owner_id;
+	instance_data[i].mode = mode;
 	instance_data[i].keep_limit = 0;
 	instance_data[i].keep_timer = INVALID_TIMER;
 	instance_data[i].idle_limit = 0;
 	instance_data[i].idle_timer = INVALID_TIMER;
 	instance_data[i].regs.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
 	instance_data[i].regs.arrays = NULL;
+	safestrncpy(instance_data[i].name, name, sizeof(instance_data[i].name));
 	memset(instance_data[i].map, 0, sizeof(instance_data[i].map));
 
-	p->instance_id = i;
+	switch(mode) {
+		case IM_CHAR:
+			sd->instance_id = i;
+			break;
+		case IM_PARTY:
+			p->instance_id = i;
+			break;
+		case IM_GUILD:
+			g->instance_id = i;
+			break;
+	}
 
-	instance_wait.id[instance_wait.count++] = p->instance_id;
+	instance_wait.id[instance_wait.count++] = i;
 
-	clif_instance_create( party_getavailablesd( p ), name, instance_wait.count, 1);
+	clif_instance_create(i, instance_wait.count);
 
 	instance_subscription_timer(0,0,0,0);
 
@@ -298,24 +425,23 @@ int instance_create(int party_id, const char *name)
 /*--------------------------------------
  * Adds maps to the instance
  *--------------------------------------*/
-int instance_addmap(short instance_id)
+int instance_addmap(unsigned short instance_id)
 {
 	int i, m;
 	int cnt_map = 0;
 	struct instance_data *im;
 	struct instance_db *db;
-	struct party_data *p;
 
-	if(instance_id <= 0)
+	if (instance_id == 0)
 		return 0;
 
 	im = &instance_data[instance_id];
 
 	// If the instance isn't idle, we can't do anything
-	if(im->state != INSTANCE_IDLE)
+	if (im->state != INSTANCE_IDLE)
 		return 0;
 
-	if((db = instance_searchtype_db(im->type)) == NULL)
+	if ((db = instance_searchtype_db(im->type)) == NULL)
 		return 0;
 
 	// Set to busy, update timers
@@ -343,9 +469,24 @@ int instance_addmap(short instance_id)
 	// Create NPCs on all maps
 	instance_addnpc(im);
 
-	// Inform party members of the created instance
-	if( (p = party_search( im->party_id ) ) != NULL )
-		clif_instance_status( party_getavailablesd( p ), StringBuf_Value(db->name), im->keep_limit, im->idle_limit, 1);
+	switch(im->mode) {
+		case IM_NONE:
+			break;
+		case IM_CHAR:
+			if (map_id2sd(im->owner_id) != NULL) // Inform player of the created instance
+				clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+			break;
+		case IM_PARTY:
+			if (party_search(im->owner_id) != NULL) // Inform party members of the created instance
+				clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+			break;
+		case IM_GUILD:
+			if (guild_search(im->owner_id) != NULL) // Inform guild members of the created instance
+				clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
+			break;
+		default:
+			return 0;
+	}
 
 	return cnt_map;
 }
@@ -357,7 +498,7 @@ int instance_addmap(short instance_id)
  * instance_id : where to search
  * result : mapid of map "name" in this instance
  *------------------------------------------*/
-int instance_mapname2mapid(const char *name, short instance_id)
+int instance_mapname2mapid(const char *name, unsigned short instance_id)
 {
 	struct instance_data *im;
 	int m = map_mapname2mapid(name);
@@ -371,7 +512,7 @@ int instance_mapname2mapid(const char *name, short instance_id)
 
 	strcpy(iname,name);
 
-	if(instance_id <= 0 || instance_id > MAX_INSTANCE_DATA)
+	if(instance_id == 0 || instance_id > MAX_INSTANCE_DATA)
 		return m;
 
 	im = &instance_data[instance_id];
@@ -395,14 +536,17 @@ int instance_mapname2mapid(const char *name, short instance_id)
 /*==========================================
  * Removes a instance, all its maps and npcs.
  *------------------------------------------*/
-int instance_destroy(short instance_id)
+int instance_destroy(unsigned short instance_id)
 {
 	struct instance_data *im;
-	struct party_data *p;
+	struct map_session_data *sd = NULL;
+	struct party_data *p = NULL;
+	struct guild *g = NULL;
 	int i, type = 0;
 	unsigned int now = (unsigned int)time(NULL);
+	enum instance_mode mode;
 
-	if(instance_id <= 0 || instance_id > MAX_INSTANCE_DATA)
+	if(instance_id == 0 || instance_id > MAX_INSTANCE_DATA)
 		return 1;
 
 	im = &instance_data[instance_id];
@@ -410,6 +554,33 @@ int instance_destroy(short instance_id)
 	if(im->state == INSTANCE_FREE)
 		return 1;
 
+	mode = im->mode;
+	switch(mode) {
+		case IM_NONE:
+			break;
+		case IM_CHAR:
+			if ((sd = map_id2sd(im->owner_id)) == NULL) {
+				ShowError("instance_destroy: character %d not found for instance '%s'.\n", im->owner_id, im->name);
+				return 1;
+			}
+			break;
+		case IM_PARTY:
+			if ((p = party_search(im->owner_id)) == NULL) {
+				ShowError("instance_destroy: party %d not found for instance '%s'.\n", im->owner_id, im->name);
+				return 1;
+			}
+			break;
+		case IM_GUILD:
+			if ((g = guild_search(im->owner_id)) == NULL) {
+				ShowError("instance_destroy: guild %d not found for instance '%s'.\n", im->owner_id, im->name);
+				return 1;
+			}
+			break;
+		default:
+			ShowError("instance_destroy: unknown owner type %u for owner_id %d and name %s.\n", mode, im->owner_id, im->name);
+			return 1;
+	}
+
 	if(im->state == INSTANCE_IDLE) {
 		for(i = 0; i < instance_wait.count; i++) {
 			if(instance_wait.id[i] == instance_id) {
@@ -419,8 +590,8 @@ int instance_destroy(short instance_id)
 
 				for(i = 0; i < instance_wait.count; i++)
 					if(instance_data[instance_wait.id[i]].state == INSTANCE_IDLE)
-						if((p = party_search(instance_data[instance_wait.id[i]].party_id)) != NULL)
-							clif_instance_changewait( party_getavailablesd( p ), i+1, 1);
+						if ((mode == IM_CHAR && sd != NULL) || (mode == IM_PARTY && p != NULL) || (mode == IM_GUILD && g != NULL))
+							clif_instance_changewait(instance_id, i + 1);
 
 				if(instance_wait.count)
 					instance_wait.timer = add_timer(gettick()+INSTANCE_INTERVAL, instance_subscription_timer, 0, 0);
@@ -451,13 +622,18 @@ int instance_destroy(short instance_id)
 		im->idle_timer = INVALID_TIMER;
 	}
 
-	if((p = party_search(im->party_id))) {
+	if (mode == IM_CHAR)
+		sd->instance_id = 0;
+	else if (mode == IM_PARTY)
 		p->instance_id = 0;
+	else if (mode == IM_GUILD)
+		g->instance_id = 0;
 
+	if (mode != IM_NONE) {
 		if(type)
-			clif_instance_changestatus( party_getavailablesd( p ), type, 0, 1 );
+			clif_instance_changestatus(instance_id, type, 0);
 		else
-			clif_instance_changewait( party_getavailablesd( p ), 0xffff, 1 );
+			clif_instance_changewait(instance_id, 0xffff);
 	}
 
 	if( im->regs.vars ) {
@@ -478,61 +654,78 @@ int instance_destroy(short instance_id)
 /*==========================================
  * Allows a user to enter an instance
  *------------------------------------------*/
-int instance_enter(struct map_session_data *sd, const char *name)
+int instance_enter(struct map_session_data *sd, unsigned short instance_id, const char *name)
 {
 	struct instance_db *db = instance_searchname_db(name);
 
-	if(db == NULL)
-		return 3;
+	nullpo_retr(-1, sd);
+	nullpo_retr(3, db);
 
-	return instance_enter_position(sd, name, db->enter.x, db->enter.y);
+	return instance_enter_position(sd, instance_id, name, db->enter.x, db->enter.y);
 }
 
 /*==========================================
  * Warp a user into instance
  *------------------------------------------*/
-int instance_enter_position(struct map_session_data *sd, const char *name, short x, short y)
+int instance_enter_position(struct map_session_data *sd, unsigned short instance_id, const char *name, short x, short y)
 {
-	struct instance_data *im;
+	struct instance_data *im = &instance_data[instance_id];
 	struct instance_db *db = instance_searchname_db(name);
-	struct party_data *p;
-	int m;
+	struct party_data *p = NULL;
+	struct guild *g = NULL;
+	int16 m;
 
 	nullpo_retr(-1, sd);
+	nullpo_retr(3, db);
+
+	switch(instance_data[instance_id].mode) {
+		case IM_NONE:
+			break;
+		case IM_CHAR:
+			if (sd->instance_id == 0) // Player must have an instance
+				return 2;
+			if (im->owner_id != sd->status.account_id)
+				return 3;
+			break;
+		case IM_PARTY:
+			if (sd->status.party_id == 0) // Character must be in instance party
+				return 1;
+			if ((p = party_search(sd->status.party_id)) == NULL)
+				return 1;
+			if (p->instance_id == 0) // Party must have an instance
+				return 2;
+			if (im->owner_id != p->party.party_id)
+				return 3;
+			break;
+		case IM_GUILD:
+			if (sd->status.guild_id == 0) // Character must be in instance guild
+				return 1;
+			if ((g = guild_search(sd->status.guild_id)) == NULL)
+				return 1;
+			if (g->instance_id == 0) // Guild must have an instance
+				return 2;
+			if (im->owner_id != g->guild_id)
+				return 3;
+			break;
+	}
 
-	// Character must be in instance party
-	if(sd->status.party_id == 0)
-		return 1;
-	if((p = party_search(sd->status.party_id)) == NULL)
-		return 1;
-
-	// Party must have an instance
-	if(p->instance_id == 0)
-		return 2;
-
-	if(db == NULL)
-		return 3;
-
-	im = &instance_data[p->instance_id];
-	if(im->party_id != p->party.party_id)
+	if (im->state != INSTANCE_BUSY)
 		return 3;
-	if(im->state != INSTANCE_BUSY)
-		return 3;
-	if(im->type != db->id)
+	if (im->type != db->id)
 		return 3;
 
 	// Does the instance match?
-	if((m = instance_mapname2mapid(StringBuf_Value(db->enter.mapname), p->instance_id)) < 0)
+	if ((m = instance_mapname2mapid(StringBuf_Value(db->enter.mapname), instance_id)) < 0)
 		return 3;
 
-	if(pc_setpos(sd, map_id2index(m), x, y, CLR_OUTSIGHT))
+	if (pc_setpos(sd, map_id2index(m), x, y, CLR_OUTSIGHT))
 		return 3;
 
 	// If there was an idle timer, let's stop it
-	instance_stopidletimer(im);
+	instance_stopidletimer(im, instance_id);
 
 	// Now we start the instance timer
-	instance_startkeeptimer(im, p->instance_id);
+	instance_startkeeptimer(im, instance_id);
 
 	return 0;
 }
@@ -540,14 +733,14 @@ int instance_enter_position(struct map_session_data *sd, const char *name, short
 /*==========================================
  * Request some info about the instance
  *------------------------------------------*/
-int instance_reqinfo(struct map_session_data *sd, short instance_id)
+int instance_reqinfo(struct map_session_data *sd, unsigned short instance_id)
 {
 	struct instance_data *im;
 	struct instance_db *db;
 
 	nullpo_retr(1, sd);
 
-	if(instance_id <= 0 || instance_id > MAX_INSTANCE_DATA)
+	if(instance_id == 0 || instance_id > MAX_INSTANCE_DATA)
 		return 1;
 
 	im = &instance_data[instance_id];
@@ -561,12 +754,12 @@ int instance_reqinfo(struct map_session_data *sd, short instance_id)
 
 		for(i = 0; i < instance_wait.count; i++) {
 			if(instance_wait.id[i] == instance_id) {
-				clif_instance_create(sd, StringBuf_Value(db->name), i+1, 0);
+				clif_instance_create(instance_id, i + 1);
 				break;
 			}
 		}
 	} else if(im->state == INSTANCE_BUSY) // Give info on the instance if busy
-		clif_instance_status(sd, StringBuf_Value(db->name), im->keep_limit, im->idle_limit, 0);
+		clif_instance_status(instance_id, im->keep_limit, im->idle_limit);
 
 	return 0;
 }
@@ -574,11 +767,11 @@ int instance_reqinfo(struct map_session_data *sd, short instance_id)
 /*==========================================
  * Add players to the instance (for timers)
  *------------------------------------------*/
-int instance_addusers(short instance_id)
+int instance_addusers(unsigned short instance_id)
 {
 	struct instance_data *im;
 
-	if(instance_id <= 0 || instance_id > MAX_INSTANCE_DATA)
+	if(instance_id == 0 || instance_id > MAX_INSTANCE_DATA)
 		return 1;
 
 	im = &instance_data[instance_id];
@@ -586,7 +779,7 @@ int instance_addusers(short instance_id)
 		return 1;
 
 	// Stop the idle timer if we had one
-	instance_stopidletimer(im);
+	instance_stopidletimer(im, instance_id);
 
 	// Start the instance keep timer
 	instance_startkeeptimer(im, instance_id);
@@ -597,12 +790,12 @@ int instance_addusers(short instance_id)
 /*==========================================
  * Delete players from the instance (for timers)
  *------------------------------------------*/
-int instance_delusers(short instance_id)
+int instance_delusers(unsigned short instance_id)
 {
 	struct instance_data *im;
 	int i, idle = 0;
 
-	if(instance_id <= 0 || instance_id > MAX_INSTANCE_DATA)
+	if(instance_id == 0 || instance_id > MAX_INSTANCE_DATA)
 		return 1;
 
 	im = &instance_data[instance_id];
@@ -637,8 +830,8 @@ static bool instance_readdb_sub(char* str[], int columns, int current)
 		return false;
 	}
 
-	if (mapindex_name2id(str[3]) == 0) {
-		ShowError("instance_readdb_sub: Invalid map '%s' as entrance map.\n", str[3]);
+	if (mapindex_name2id(str[4]) == 0) {
+		ShowError("instance_readdb_sub: Invalid map '%s' as entrance map.\n", str[4]);
 		return false;
 	}
 
@@ -662,12 +855,13 @@ static bool instance_readdb_sub(char* str[], int columns, int current)
 
 	StringBuf_AppendStr(db->name, str[1]);
 	db->limit = atoi(str[2]);
-	StringBuf_AppendStr(db->enter.mapname, str[3]);
-	db->enter.x = atoi(str[4]);
-	db->enter.y = atoi(str[5]);
+	db->timeout = atoi(str[3]);
+	StringBuf_AppendStr(db->enter.mapname, str[4]);
+	db->enter.x = atoi(str[5]);
+	db->enter.y = atoi(str[6]);
 
 	//Instance maps
-	for (i = 6; i < columns; i++) {
+	for (i = 7; i < columns; i++) {
 		if (strlen(str[i])) {
 			if (mapindex_name2id(str[i]) == 0) {
 				ShowWarning("instance_readdb_sub: Invalid map '%s' in maplist, skipping...\n", str[i]);
@@ -675,7 +869,7 @@ static bool instance_readdb_sub(char* str[], int columns, int current)
 			}
 			RECREATE(db->maplist, StringBuf *, db->maplist_count+1);
 			db->maplist[db->maplist_count] = StringBuf_Malloc();
-			if (strcmpi(str[i], str[3]) == 0)
+			if (strcmpi(str[i], str[4]) == 0)
 				defined = true;
 			StringBuf_AppendStr(db->maplist[db->maplist_count], str[i]);
 			db->maplist_count++;
@@ -732,7 +926,7 @@ void instance_readdb(void) {
 	int f;
 
 	for (f = 0; f<ARRAYLENGTH(filename); f++) {
-		sv_readdb(db_path, filename[f], ',', 7, 7+MAX_MAP_PER_INSTANCE, -1, &instance_readdb_sub, f);
+		sv_readdb(db_path, filename[f], ',', 8, 8+MAX_MAP_PER_INSTANCE, -1, &instance_readdb_sub, f);
 	}
 }
 
@@ -754,7 +948,7 @@ void do_reload_instance(void)
 	struct instance_db *db;
 	struct s_mapiterator* iter;
 	struct map_session_data *sd;
-	int i;
+	unsigned short i;
 
 	for( i = 1; i < MAX_INSTANCE_DATA; i++ ) {
 		im = &instance_data[i];
@@ -775,10 +969,14 @@ void do_reload_instance(void)
 	for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
 		if(sd && map[sd->bl.m].instance_id) {
 			struct party_data *p;
-			if(!(p = party_search(sd->status.party_id)) || p->instance_id != map[sd->bl.m].instance_id) // Someone not in party is on instance map
+			struct guild *g;
+
+			if (instance_data[map[sd->bl.m].instance_id].mode == IM_PARTY && (!(p = party_search(sd->status.party_id)) || p->instance_id != map[sd->bl.m].instance_id)) // Someone not in party is on instance map
+				continue;
+			if (instance_data[map[sd->bl.m].instance_id].mode == IM_GUILD && (!(g = guild_search(sd->status.guild_id)) || g->instance_id != map[sd->bl.m].instance_id)) // Someone not in guild is on instance map
 				continue;
 			im = &instance_data[p->instance_id];
-			if((db = instance_searchtype_db(im->type)) != NULL && !instance_enter(sd,StringBuf_Value(db->name))) { // All good
+			if((db = instance_searchtype_db(im->type)) != NULL && !instance_enter(sd, i, StringBuf_Value(db->name))) { // All good
 				clif_displaymessage(sd->fd, msg_txt(sd,515)); // Instance has been reloaded
 				instance_reqinfo(sd,p->instance_id);
 			} else // Something went wrong

+ 28 - 12
src/map/instance.h

@@ -14,13 +14,27 @@ struct block_list;
 
 #define INSTANCE_NAME_LENGTH (60+1)
 
-typedef enum instance_state { INSTANCE_FREE, INSTANCE_IDLE, INSTANCE_BUSY } instance_state;
+typedef enum instance_state {
+	INSTANCE_FREE,
+	INSTANCE_IDLE,
+	INSTANCE_BUSY
+} instance_state;
+
+enum instance_mode {
+	IM_NONE,
+	IM_CHAR,
+	IM_PARTY,
+	IM_GUILD,
+	IM_MAX,
+};
 
 struct instance_data {
 	unsigned short type, ///< Instance DB ID
 		cnt_map;
-	int state;
-	int party_id;
+	char name[INSTANCE_NAME_LENGTH];
+	enum instance_state state;
+	enum instance_mode mode;
+	int owner_id;
 	unsigned int keep_limit;
 	int keep_timer;
 	unsigned int idle_limit;
@@ -37,15 +51,17 @@ struct instance_data {
 extern int instance_start;
 extern struct instance_data instance_data[MAX_INSTANCE_DATA];
 
-int instance_create(int party_id, const char *name);
-int instance_destroy(short instance_id);
-int instance_enter(struct map_session_data *sd, const char *name);
-int instance_enter_position(struct map_session_data *sd, const char *name, short x, short y);
-int instance_reqinfo(struct map_session_data *sd, short instance_id);
-int instance_addusers(short instance_id);
-int instance_delusers(short instance_id);
-int instance_mapname2mapid(const char *name, short instance_id);
-int instance_addmap(short instance_id);
+void instance_getsd(unsigned short instance_id, struct map_session_data **sd, enum send_target *target);
+
+int instance_create(int owner_id, const char *name, enum instance_mode mode);
+int instance_destroy(unsigned short instance_id);
+int instance_enter(struct map_session_data *sd, unsigned short instance_id, const char *name);
+int instance_enter_position(struct map_session_data *sd, unsigned short instance_id, const char *name, short x, short y);
+int instance_reqinfo(struct map_session_data *sd, unsigned short instance_id);
+int instance_addusers(unsigned short instance_id);
+int instance_delusers(unsigned short instance_id);
+int instance_mapname2mapid(const char *name, unsigned short instance_id);
+int instance_addmap(unsigned short instance_id);
 
 void instance_addnpc(struct instance_data *im);
 void instance_readdb(void);

+ 4 - 4
src/map/map.c

@@ -2554,7 +2554,7 @@ bool map_addnpc(int16 m,struct npc_data *nd)
 /*==========================================
  * Add an instance map
  *------------------------------------------*/
-int map_addinstancemap(const char *name, int id)
+int map_addinstancemap(const char *name, unsigned short instance_id)
 {
 	int src_m = map_mapname2mapid(name);
 	int dst_m = -1, i;
@@ -2594,9 +2594,9 @@ int map_addinstancemap(const char *name, int id)
 	// This also allows us to maintain complete independence with main map functions
 	if((strchr(iname,'@') == NULL) && strlen(iname) > 8) {
 		memmove(iname, iname+(strlen(iname)-9), strlen(iname));
-		snprintf(map[dst_m].name, sizeof(map[dst_m].name),"%d#%s", id, iname);
+		snprintf(map[dst_m].name, sizeof(map[dst_m].name),"%hu#%s", instance_id, iname);
 	} else
-		snprintf(map[dst_m].name, sizeof(map[dst_m].name),"%.3d%s", id, iname);
+		snprintf(map[dst_m].name, sizeof(map[dst_m].name),"%.3hu%s", instance_id, iname);
 	map[dst_m].name[MAP_NAME_LENGTH-1] = '\0';
 
 	// Mimic questinfo
@@ -2607,7 +2607,7 @@ int map_addinstancemap(const char *name, int id)
 	}
 
 	map[dst_m].m = dst_m;
-	map[dst_m].instance_id = id;
+	map[dst_m].instance_id = instance_id;
 	map[dst_m].instance_src_map = src_m;
 	map[dst_m].users = 0;
 

+ 3 - 3
src/map/map.h

@@ -689,7 +689,7 @@ struct map_data {
 	} skill_damage;
 #endif
 	// Instance Variables
-	int instance_id;
+	unsigned short instance_id;
 	int instance_src_map;
 
 	/* rAthena Local Chat */
@@ -800,8 +800,8 @@ void map_clearflooritem(struct block_list* bl);
 int map_addflooritem(struct item *item, int amount, int16 m, int16 x, int16 y, int first_charid, int second_charid, int third_charid, int flags, unsigned short mob_id);
 
 // instances
-int map_addinstancemap(const char*,int);
-int map_delinstancemap(int);
+int map_addinstancemap(const char *name, unsigned short instance_id);
+int map_delinstancemap(int m);
 
 // player to map session
 void map_addnickdb(int charid, const char* nick);

+ 1 - 1
src/map/party.c

@@ -660,7 +660,7 @@ int party_broken(int party_id)
 		return 0;
 
 	if( p->instance_id ) {
-		instance_data[p->instance_id].party_id = 0;
+		instance_data[p->instance_id].owner_id = 0;
 		instance_destroy( p->instance_id );
 	}
 

+ 1 - 1
src/map/party.h

@@ -25,7 +25,7 @@ struct party_data {
 	struct party party;
 	struct party_member_data data[MAX_PARTY];
 	uint8 itemc; //For item distribution, position of last picker in party
-	unsigned int instance_id;
+	unsigned short instance_id;
 	struct {
 		unsigned monk : 1; //There's at least one monk in party?
 		unsigned sg : 1;	//There's at least one Star Gladiator in party?

+ 14 - 3
src/map/pc.c

@@ -5285,10 +5285,21 @@ enum e_setpos pc_setpos(struct map_session_data* sd, unsigned short mapindex, in
 	sd->state.changemap = (sd->mapindex != mapindex);
 	sd->state.warping = 1;
 
-	if(sd->status.party_id && map[sd->bl.m].instance_id && sd->state.changemap && !map[m].instance_id) {
-		struct party_data *p;
-		if((p = party_search(sd->status.party_id)) != NULL && p->instance_id )
+	if(map[sd->bl.m].instance_id && sd->state.changemap && !map[m].instance_id) {
+		bool instance_found = false;
+		struct party_data *p = NULL;
+		struct guild *g = NULL;
+
+		if (sd->instance_id) {
+			instance_delusers(sd->instance_id);
+			instance_found = true;
+		}
+		if (!instance_found && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id) {
 			instance_delusers(p->instance_id);
+			instance_found = true;
+		}
+		if (!instance_found && sd->status.guild_id && (g = guild_search(sd->status.guild_id)) != NULL && g->instance_id)
+			instance_delusers(g->instance_id);
 	}
 	if( sd->state.changemap ) { // Misc map-changing settings
 		int i;

+ 2 - 0
src/map/pc.h

@@ -679,6 +679,8 @@ struct map_session_data {
 		short prizeStage;
 		bool claimPrize;
 	} roulette;
+
+	unsigned short instance_id;
 };
 
 struct eri *pc_sc_display_ers; /// Player's SC display table

+ 159 - 50
src/map/script.c

@@ -295,7 +295,7 @@ struct {
  *------------------------------------------*/
 const char* parse_subexpr(const char* p,int limit);
 int run_func(struct script_state *st);
-int script_instancegetid(struct script_state *st);
+unsigned short script_instancegetid(struct script_state *st);
 
 enum {
 	MF_NOMEMO,	//0
@@ -2593,7 +2593,7 @@ void get_val_(struct script_state* st, struct script_data* data, struct map_sess
 				break;
 			case '\'':
 				{
-					int instance_id = script_instancegetid(st);
+					unsigned short instance_id = script_instancegetid(st);
 					if( instance_id )
 						data->u.str = (char*)i64db_get(instance_data[instance_id].regs.vars,reference_getuid(data));
 					else {
@@ -2651,7 +2651,7 @@ void get_val_(struct script_state* st, struct script_data* data, struct map_sess
 					break;
 				case '\'':
 					{
-						int instance_id = script_instancegetid(st);
+						unsigned short instance_id = script_instancegetid(st);
 						if( instance_id )
 							data->u.num = (int)i64db_iget(instance_data[instance_id].regs.vars,reference_getuid(data));
 						else {
@@ -2867,7 +2867,7 @@ struct reg_db *script_array_src(struct script_state *st, struct map_session_data
 			break;
 		case '\'': // instance
 			{
-				int instance_id = script_instancegetid(st);
+				unsigned short instance_id = script_instancegetid(st);
 
 				if( instance_id ) {
 					src = &instance_data[instance_id].regs;
@@ -2981,7 +2981,7 @@ int set_reg(struct script_state* st, TBL_PC* sd, int64 num, const char* name, co
 				return 1;
 			case '\'':
 				{
-					int instance_id = script_instancegetid(st);
+					unsigned short instance_id = script_instancegetid(st);
 					if( instance_id ) {
 						if( str[0] ) {
 							i64db_put(instance_data[instance_id].regs.vars, num, aStrdup(str));
@@ -3044,7 +3044,7 @@ int set_reg(struct script_state* st, TBL_PC* sd, int64 num, const char* name, co
 				return 1;
 			case '\'':
 				{
-					int instance_id = script_instancegetid(st);
+					unsigned short instance_id = script_instancegetid(st);
 					if( instance_id ) {
 						if( val != 0 ) {
 							i64db_iput(instance_data[instance_id].regs.vars, num, val);
@@ -18827,19 +18827,27 @@ BUILDIN_FUNC(bg_get_data)
  * Instancing System
  *------------------------------------------*/
 //Returns an Instance ID
-//Checks NPC first, then if player is attached we check party
-int script_instancegetid(struct script_state* st)
+//Checks NPC first, then if player is attached we check
+unsigned short script_instancegetid(struct script_state* st)
 {
-	short instance_id = 0;
-
+	unsigned short instance_id = 0;
 	struct npc_data *nd;
+
 	if( (nd = map_id2nd(st->oid)) && nd->instance_id > 0 )
 		instance_id = nd->instance_id;
 	else {
-		struct map_session_data *sd;
-		struct party_data *p;
-		if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
-			instance_id = p->instance_id;
+		struct map_session_data *sd = NULL;
+		struct party_data *p = NULL;
+		struct guild *g = NULL;
+
+		if ((sd = script_rid2sd(st)) != NULL) {
+			if (sd->instance_id)
+				instance_id = sd->instance_id;
+			if (instance_id == 0 && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id)
+				instance_id = p->instance_id;
+			if (instance_id == 0 && sd->status.guild_id && (g = guild_search(sd->status.guild_id)) != NULL && g->instance_id)
+				instance_id = g->instance_id;
+		}
 	}
 
 	return instance_id;
@@ -18851,12 +18859,20 @@ int script_instancegetid(struct script_state* st)
  *------------------------------------------*/
 BUILDIN_FUNC(instance_create)
 {
-	struct map_session_data *sd;
+	enum instance_mode mode = IM_PARTY;
+	int owner_id;
 
-	if((sd = script_rid2sd(st)) == NULL)
-		return -1;
+	owner_id = script_getnum(st, 3);
+	if (script_hasdata(st, 4)) {
+		mode = script_getnum(st, 4);
+
+		if (mode < IM_NONE || mode >= IM_MAX) {
+			ShowError("buildin_instance_create: Unknown instance owner type %d for '%s'\n", mode, script_getstr(st, 2));
+			return SCRIPT_CMD_FAILURE;
+		}
+	}
 
-	script_pushint(st,instance_create(sd->status.party_id, script_getstr(st, 2)));
+	script_pushint(st, instance_create(owner_id, script_getstr(st, 2), mode));
 	return SCRIPT_CMD_SUCCESS;
 }
 
@@ -18868,7 +18884,7 @@ BUILDIN_FUNC(instance_create)
  *------------------------------------------*/
 BUILDIN_FUNC(instance_destroy)
 {
-	short instance_id;
+	unsigned short instance_id;
 
 	if( script_hasdata(st,2) )
 		instance_id = script_getnum(st,2);
@@ -18876,7 +18892,7 @@ BUILDIN_FUNC(instance_destroy)
 		instance_id = script_instancegetid(st);
 
 	if( instance_id <= 0 || instance_id >= MAX_MAP_PER_SERVER ) {
-		ShowError("script:instance_destroy: Trying to destroy invalid instance %d.\n", instance_id);
+		ShowError("buildin_instance_destroy: Trying to destroy invalid instance %d.\n", instance_id);
 		return SCRIPT_CMD_SUCCESS;
 	}
 
@@ -18888,9 +18904,9 @@ BUILDIN_FUNC(instance_destroy)
  * Warps player to instance
  * Results:
  *	0: Success
- *	1: Character not in party
- *	2: Party doesn't have instance
- *	3: Other errors (instance not in DB, instance doesn't match with party, etc.)
+ *	1: Character not in party/guild (for party/guild type instances)
+ *	2: Character/Party/Guild doesn't have instance
+ *	3: Other errors (instance not in DB, instance doesn't match with character/party/guild, etc.)
  *------------------------------------------*/
 BUILDIN_FUNC(instance_enter)
 {
@@ -18902,9 +18918,9 @@ BUILDIN_FUNC(instance_enter)
 		return SCRIPT_CMD_FAILURE;
 
 	if (x != -1 && y != -1)
-		script_pushint(st,instance_enter_position(sd,script_getstr(st, 2),x,y));
+		script_pushint(st, instance_enter_position(sd, script_instancegetid(st), script_getstr(st, 2), x, y));
 	else
-		script_pushint(st,instance_enter(sd,script_getstr(st, 2)));
+		script_pushint(st, instance_enter(sd, script_instancegetid(st), script_getstr(st, 2)));
 
 	return SCRIPT_CMD_SUCCESS;
 }
@@ -18918,8 +18934,7 @@ BUILDIN_FUNC(instance_enter)
 BUILDIN_FUNC(instance_npcname)
 {
 	const char *str;
-	short instance_id = 0;
-
+	unsigned short instance_id = 0;
 	struct npc_data *nd;
 
 	str = script_getstr(st,2);
@@ -18933,7 +18948,7 @@ BUILDIN_FUNC(instance_npcname)
 		snprintf(npcname, sizeof(npcname), "dup_%d_%d", instance_id, nd->bl.id);
 		script_pushconststr(st,npcname);
 	} else {
-		ShowError("script:instance_npcname: invalid instance NPC (instance_id: %d, NPC name: \"%s\".)\n", instance_id, str);
+		ShowError("buildin_instance_npcname: Invalid instance NPC (instance_id: %d, NPC name: \"%s\".)\n", instance_id, str);
 		st->state = END;
 		return SCRIPT_CMD_FAILURE;
 	}
@@ -18950,7 +18965,7 @@ BUILDIN_FUNC(instance_mapname)
 {
  	const char *str;
 	int16 m;
-	short instance_id = 0;
+	unsigned short instance_id = 0;
 
 	str = script_getstr(st,2);
 
@@ -18973,12 +18988,12 @@ BUILDIN_FUNC(instance_mapname)
  *------------------------------------------*/
 BUILDIN_FUNC(instance_id)
 {
-	short instance_id;
+	unsigned short instance_id;
 
 	instance_id = script_instancegetid(st);
 
 	if(!instance_id) {
-		//ShowError("script:instance_id: No instance attached to NPC or player");
+		//ShowError("buildin_instance_id: No instance attached to NPC or player");
 		script_pushint(st, 0);
 		return SCRIPT_CMD_SUCCESS;
 	}
@@ -18991,11 +19006,29 @@ BUILDIN_FUNC(instance_id)
  *
  * instance_warpall <map_name>,<x>,<y>{,<instance_id>};
  *------------------------------------------*/
+static int buildin_instance_warpall_sub(struct block_list *bl, va_list ap)
+{
+	unsigned int m = va_arg(ap,unsigned int);
+	int x = va_arg(ap,int);
+	int y = va_arg(ap,int);
+
+	nullpo_retr(0, bl);
+
+	if (bl->type != BL_PC)
+		return 0;
+
+	pc_setpos((TBL_PC *)bl, m, x, y, CLR_TELEPORT);
+
+	return 0;
+}
+
 BUILDIN_FUNC(instance_warpall)
 {
-	struct party_data *p;
+	struct map_session_data *sd = NULL;
+	struct party_data *p = NULL;
+	struct guild *g = NULL;
 	int16 m, i;
-	short instance_id;
+	unsigned short instance_id;
 	const char *mapn;
 	int x, y;
 
@@ -19008,16 +19041,30 @@ BUILDIN_FUNC(instance_warpall)
 		instance_id = script_instancegetid(st);
 
 	if( !instance_id || (m = map_mapname2mapid(mapn)) < 0 || (m = instance_mapname2mapid(map[m].name,instance_id)) < 0)
-		return SCRIPT_CMD_SUCCESS;
-
-	if( !(p = party_search(instance_data[instance_id].party_id)) )
-		return SCRIPT_CMD_SUCCESS;
+		return SCRIPT_CMD_FAILURE;
 
-	for( i = 0; i < MAX_PARTY; i++ ) {
-		struct map_session_data *pl_sd;
-		if( (pl_sd = p->data[i].sd) && map[pl_sd->bl.m].instance_id == instance_id ) pc_setpos(pl_sd,map_id2index(m),x,y,CLR_TELEPORT);
+	switch(instance_data[instance_id].mode) {
+		case IM_NONE:
+			break;
+		case IM_CHAR:
+			if (!(sd = map_id2sd(instance_data[instance_id].owner_id)))
+				return SCRIPT_CMD_FAILURE;
+			break;
+		case IM_PARTY:
+			if (!(p = party_search(instance_data[instance_id].owner_id)))
+				return SCRIPT_CMD_FAILURE;
+			break;
+		case IM_GUILD:
+			if (!(g = guild_search(instance_data[instance_id].owner_id)))
+				return SCRIPT_CMD_FAILURE;
+		default:
+			ShowError("buildin_instance_warpall: Invalid instance owner type (instance_id: %d)\n", instance_id);
+			break;
 	}
 
+	for(i = 0; i < instance_data[instance_id].cnt_map; i++)
+		map_foreachinmap(buildin_instance_warpall_sub, instance_data[instance_id].map[i].m, BL_PC, map_id2index(m), x, y);
+
 	return SCRIPT_CMD_SUCCESS;
 }
 
@@ -19028,15 +19075,14 @@ BUILDIN_FUNC(instance_warpall)
  * Using -1 for <instance id> will auto-detect the id.
  *------------------------------------------*/
 BUILDIN_FUNC(instance_announce) {
-	int         instance_id = script_getnum(st,2);
-	const char *mes         = script_getstr(st,3);
-	int         flag        = script_getnum(st,4);
-	const char *fontColor   = script_hasdata(st,5) ? script_getstr(st,5) : NULL;
-	int         fontType    = script_hasdata(st,6) ? script_getnum(st,6) : FW_NORMAL; // default fontType
-	int         fontSize    = script_hasdata(st,7) ? script_getnum(st,7) : 12;    // default fontSize
-	int         fontAlign   = script_hasdata(st,8) ? script_getnum(st,8) : 0;     // default fontAlign
-	int         fontY       = script_hasdata(st,9) ? script_getnum(st,9) : 0;     // default fontY
-
+	unsigned short instance_id = script_getnum(st,2);
+	const char     *mes        = script_getstr(st,3);
+	int            flag        = script_getnum(st,4);
+	const char     *fontColor  = script_hasdata(st,5) ? script_getstr(st,5) : NULL;
+	int            fontType    = script_hasdata(st,6) ? script_getnum(st,6) : FW_NORMAL; // default fontType
+	int            fontSize    = script_hasdata(st,7) ? script_getnum(st,7) : 12;    // default fontSize
+	int            fontAlign   = script_hasdata(st,8) ? script_getnum(st,8) : 0;     // default fontAlign
+	int            fontY       = script_hasdata(st,9) ? script_getnum(st,9) : 0;     // default fontY
 	int i;
 
 	if( instance_id == -1 ) {
@@ -19114,6 +19160,68 @@ BUILDIN_FUNC(instance_check_party)
 	return SCRIPT_CMD_SUCCESS;
 }
 
+/*==========================================
+ * instance_check_guild
+ * Values:
+ * guild_id : Guild ID of the invoking character. [Required Parameter]
+ * amount : Amount of needed Guild members for the Instance. [Optional Parameter]
+ * min : Minimum Level needed to join the Instance. [Optional Parameter]
+ * max : Maxium Level allowed to join the Instance. [Optional Parameter]
+ * Example: instance_check_guild (getcharid(2){,amount}{,min}{,max});
+ * Example 2: instance_check_guild (getcharid(2),1,1,99);
+ *------------------------------------------*/
+BUILDIN_FUNC(instance_check_guild)
+{
+	int amount, min, max, i, guild_id, c = 0;
+	struct guild *g = NULL;
+
+	amount = script_hasdata(st,3) ? script_getnum(st,3) : 1; // Amount of needed Guild members for the Instance.
+	min = script_hasdata(st,4) ? script_getnum(st,4) : 1; // Minimum Level needed to join the Instance.
+	max  = script_hasdata(st,5) ? script_getnum(st,5) : MAX_LEVEL; // Maxium Level allowed to join the Instance.
+
+	if (min < 1 || min > MAX_LEVEL) {
+		ShowError("buildin_instance_check_guild: Invalid min level, %d\n", min);
+		return SCRIPT_CMD_FAILURE;
+	} else if (max < 1 || max > MAX_LEVEL) {
+		ShowError("buildin_instance_check_guild: Invalid max level, %d\n", max);
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	if (script_hasdata(st,2))
+		guild_id = script_getnum(st,2);
+	else
+		return SCRIPT_CMD_SUCCESS;
+
+	if (!(g = guild_search(guild_id))) {
+		script_pushint(st, 0); // Returns false if guild does not exist.
+		return SCRIPT_CMD_SUCCESS;
+	}
+
+	for(i = 0; i < MAX_GUILD; i++) {
+		struct map_session_data *pl_sd;
+
+		if ((pl_sd = g->member[i].sd)) {
+			if (map_id2bl(pl_sd->bl.id)) {
+				if (pl_sd->status.base_level < min) {
+					script_pushint(st, 0);
+					return SCRIPT_CMD_SUCCESS;
+				} else if (pl_sd->status.base_level > max) {
+					script_pushint(st, 0);
+					return SCRIPT_CMD_SUCCESS;
+				}
+				c++;
+			}
+		}
+	}
+
+	if (c < amount)
+		script_pushint(st, 0); // Not enough Members in the Guild to join Instance.
+	else
+		script_pushint(st, 1);
+
+	return SCRIPT_CMD_SUCCESS;
+}
+
 /*==========================================
  * Custom Fonts
  *------------------------------------------*/
@@ -21783,7 +21891,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(bg_updatescore,"sii"),
 
 	// Instancing
-	BUILDIN_DEF(instance_create,"s"),
+	BUILDIN_DEF(instance_create,"si?"),
 	BUILDIN_DEF(instance_destroy,"?"),
 	BUILDIN_DEF(instance_id,""),
 	BUILDIN_DEF(instance_enter,"s???"),
@@ -21792,6 +21900,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(instance_warpall,"sii?"),
 	BUILDIN_DEF(instance_announce,"isi?????"),
 	BUILDIN_DEF(instance_check_party,"i???"),
+	BUILDIN_DEF(instance_check_guild,"i???"),
 	/**
 	 * 3rd-related
 	 **/

+ 6 - 0
src/map/script_constants.h

@@ -3062,6 +3062,12 @@
 	export_constant(DIR_EAST);
 	export_constant(DIR_NORTHEAST);
 
+	/* instance modes */
+	export_constant(IM_NONE);
+	export_constant(IM_CHAR);
+	export_constant(IM_PARTY);
+	export_constant(IM_GUILD);
+
 	#undef export_constant
 
 #endif /* _SCRIPT_CONSTANTS_H_ */