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.
This commit is contained in:
aleos89 2016-05-14 11:57:54 -04:00
parent 4c617bcd59
commit c97be60bbf
15 changed files with 662 additions and 241 deletions

View File

@ -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.|
=========================

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);
mode = instance_data[instance_id].mode;
// 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 );
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);
struct map_session_data *sd = NULL;
struct party_data *p = NULL;
struct guild *g = NULL;
unsigned short i;
if(db == NULL)
return -1;
nullpo_retr(-1, db);
if( p == NULL )
return -2;
if( p->instance_id )
return -3; // Party already instancing
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);
// 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;
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;
}
// Party must have an instance
if(p->instance_id == 0)
return 2;
if(db == NULL)
if (im->state != INSTANCE_BUSY)
return 3;
im = &instance_data[p->instance_id];
if(im->party_id != p->party.party_id)
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

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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 );
}

View File

@ -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?

View File

@ -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;

View File

@ -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

View File

@ -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);
script_pushint(st,instance_create(sd->status.party_id, script_getstr(st, 2)));
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(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;
return SCRIPT_CMD_FAILURE;
if( !(p = party_search(instance_data[instance_id].party_id)) )
return SCRIPT_CMD_SUCCESS;
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
**/

View File

@ -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_ */