Cleaned up instance script commands (#4090)

* Script command instance_id now supports an instance mode argument. If no mode is given it will return the attached script's instance.
* Script commands instance_destroy, instance_npcname, instance_mapname, instance_announce now attach themselves to the script's instance by default.
* Script commands instance_enter and instance_warpall attach themselves to the player's IM_PARTY instance by default.
* Added getvariableofinstance command (similar to getvariableofnpc) to retrieve the instance variable outside the instance.
* Update documentation to match changes.
Thanks to @vykimo, @Atemo, and @Lemongrass3110!
This commit is contained in:
Aleos
2019-04-19 09:02:42 -04:00
committed by GitHub
parent c264d3e94a
commit 21a5854c16
4 changed files with 224 additions and 103 deletions

View File

@@ -477,7 +477,8 @@ nothing - A permanent variable attached to the character, the default variable
('return .@var;' returns a value, not a reference).
"'" - An instance variable.
These are used with the instancing system and are unique to each
instance type.
instance type. Can be accessed from inside the instance or by calling
'getvariableofinstance'.
"#" - A permanent local account variable.
They are stored by char-server in the `acc_reg_num` table and
`acc_reg_str`.
@@ -8897,18 +8898,17 @@ The command returns the instance ID upon success, and these values upon failure:
*instance_destroy {<instance id>};
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 is used (if it is a character, party,
guild or clan mode). If it is not owned by anyone, no player needs to be attached. If
that fails, the script will come to a halt. This will also trigger the "OnInstanceDestroy"
label in all NPCs inside the instance.
the script is attached to is used. If that fails, the script will come to a halt.
This will also trigger the "OnInstanceDestroy" label in all NPCs inside the instance.
---------------------------------------
*instance_enter("<instance name>",{<x>,<y>,<char_id>,<instance id>});
Warps player to the specified instance after the script terminates. The map and
coordinates are located in 'db/(pre-)re/instance_db.txt'.
Warps the attached player to the specified <instance id>. If no ID is specified,
the IM_PARTY instance the invoking player is attached to is used.
The map and coordinates are located in 'db/(pre-)re/instance_db.txt'.
The command returns IE_OK upon success, and these values upon failure:
IE_NOMEMBER: Party/Guild/Clan not found (for party/guild/clan modes).
@@ -8922,49 +8922,46 @@ Put -1 for x and y if want to warp player with default entrance coordinates.
*instance_npcname("<npc name>"{,<instance id>})
Returns the unique name of the instanced script. 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 NPC, player, party, guild
or clan is used. If that fails, the script will come to a halt.
the instance the script is attached to is used. If that fails, the script
will come to a halt.
---------------------------------------
*instance_mapname("<map name>"{,<instance id>})
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 is used (if it is a
character, party, guild or clan mode). If it is not owned by anyone, no player needs
to be attached. If that fails, the command returns an empty string instead.
the instance the script is attached to is used. If that fails, the command
returns an empty string instead.
---------------------------------------
*instance_id()
*instance_id({<instance mode>})
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 is
used (if it is a character, party, guild or clan mode). If it is not owned by anyone, no
player needs to be attached. If that fails, the function will return 0.
Returns the unique instance ID of the given mode. By default it returns the
attached script instance. If <instance mode> is provided then the instance
of the currently attached player is used. If that fails, the function will return 0.
Instance Mode options:
IM_CHAR: Attached to character.
IM_PARTY: Attached to character's party.
IM_GUILD: Attached to character's guild.
IM_CLAN: Attached to character's clan.
---------------------------------------
*instance_warpall "<map name>",<x>,<y>{,<instance id>};
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 is used (if it is a character, party, guild or clan
mode). If it is not owned by anyone, no player needs to be attached. If that
fails, the script will come to a halt.
Warps all players in the <instance id> to <map name> to the given coordinates.
If no ID is specified, the IM_PARTY instance the invoking player is attached
to is used. If that fails, the script will come to a halt.
---------------------------------------
*instance_announce <instance id>,"<text>",<flag>{,<fontColor>{,<fontType>{,<fontSize>{,<fontAlign>{,<fontY>}}}}};
Broadcasts a message to all players in the instance <instance id> currently
residing on an instance map. If 0 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 is used (if it is a character,
party, guild or clan mode). If it is not owned by anyone, no player needs to be attached.
Broadcasts a message to all players in the <instance id> currently residing on
an instance map. If 0 is specified for <instance id>, the instance the script
is attached to is used.
For details on the other parameters, see 'announce'.
@@ -9060,6 +9057,20 @@ mes .@name$ + " will be destroyed if no one is in the instance for " + instance_
---------------------------------------
*getvariableofinstance(<variable>,<instance id>);
Returns a reference to an instance variable (' prefix) of the specific instance ID.
This can only be used to get ' variables.
Examples:
// This will set the .@s variable to the value of 'var variable of the specific instance ID.
set .@s, getvariableofinstance('var, instance_id(IM_PARTY));
// This will set the 'var variable of the specific instance ID to 1.
set getvariableofinstance('var, instance_id(IM_GUILD)), 1;
---------------------------------------
=========================
|8.- Quest Log commands.|
=========================

View File

@@ -153,8 +153,7 @@ xmas,237,303,3 script Catherine Jet Johnson 4_F_SKULL06GIRL,{
}
if (select( "Unlock Horror Toy Factory", "Cancel" ) == 1) {
mes "Door will be.. opened soon.. Would you wait for a moment?";
if (instance_create("Horror Toy Factory") >= 0)
'xm_d_map$ = instance_mapname("1@xm_d");
instance_create("Horror Toy Factory");
}
close;
case 0:
@@ -1549,6 +1548,8 @@ OnTimer1000:
end;
OnInstanceInit:
'xm_d_map$ = instance_mapname("1@xm_d");
// Warps
disablenpc instance_npcname("#fac3wp");
disablenpc instance_npcname("#fac3wp2");

View File

@@ -150,8 +150,7 @@ moro_cav,61,69,3 script Senior Tracker#a1 4_M_JOB_ASSASSIN,{
mes "It will only stay open for a while.";
mes "You'd better use it";
mes "while you can.";
if (instance_create("Morse's Cave") >= 0)
'party_id = getcharid(1);
instance_create("Morse's Cave");
}
close;
}
@@ -223,6 +222,7 @@ OnInit:
OnTouch:
// note : party member can also trigger this event
disablenpc instance_npcname("#RZ Memorial Start");
'party_id = getcharid(1);
'soul_name$ = strcharinfo(0); // name displayed on soul is defined at entrance
setpcblock PCBLOCK_NPC, true;
sleep2 500;
@@ -1164,18 +1164,6 @@ OnInstanceInit:
// Debuff - Battle 1 & 2
for ( .@i = 1; .@i <= 15; .@i++ )
disablenpc instance_npcname( "#RZ Debuff_" + .@i );
// reload
if ('party_id > 0) {
getpartymember 'party_id, 1, .@char_id;
getpartymember 'party_id, 2, .@account_id;
for ( .@i = 0; .@i < $@partymembercount; .@i++ ) {
if (isloggedin(.@account_id[.@i],.@char_id[.@i]) == false)
continue;
if (strcharinfo(3,.@char_id[.@i]) == 'map_rev$)
setpcblock PCBLOCK_MOVE, false, .@account_id[.@i];
}
}
end;
}

View File

@@ -379,7 +379,7 @@ static struct linkdb_node *sleep_db; // int oid -> struct script_state *
*------------------------------------------*/
const char* parse_subexpr(const char* p,int limit);
int run_func(struct script_state *st);
unsigned short script_instancegetid(struct script_state *st);
unsigned short script_instancegetid(struct script_state *st, enum instance_mode mode = IM_NONE);
const char* script_op2name(int op)
{
@@ -2741,15 +2741,22 @@ struct script_data *get_val_(struct script_state* st, struct script_data* data,
break;
case '\'':
{
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));
struct DBMap* n = nullptr;
if (data->ref)
n = data->ref->vars;
else {
unsigned short instance_id = script_instancegetid(st);
if (instance_id != 0)
n = instance_data[instance_id].regs.vars;
}
if (n)
data->u.str = (char*)i64db_get(n,reference_getuid(data));
else {
ShowWarning("script:get_val: cannot access instance variable '%s', defaulting to \"\"\n", name);
data->u.str = NULL;
}
break;
}
break;
default:
data->u.str = pc_readglobalreg_str(sd, data->u.num);
break;
@@ -2799,15 +2806,22 @@ struct script_data *get_val_(struct script_state* st, struct script_data* data,
break;
case '\'':
{
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));
struct DBMap* n = nullptr;
if (data->ref)
n = data->ref->vars;
else {
unsigned short instance_id = script_instancegetid(st);
if (instance_id != 0)
n = instance_data[instance_id].regs.vars;
}
if (n)
data->u.num = (int)i64db_iget(n,reference_getuid(data));
else {
ShowWarning("script:get_val: cannot access instance variable '%s', defaulting to 0\n", name);
data->u.num = 0;
}
break;
}
break;
default:
data->u.num = pc_readglobalreg(sd, data->u.num);
break;
@@ -3015,10 +3029,13 @@ struct reg_db *script_array_src(struct script_state *st, struct map_session_data
break;
case '\'': // instance
{
unsigned short instance_id = script_instancegetid(st);
if (ref)
src = ref;
else {
unsigned short instance_id = script_instancegetid(st);
if( instance_id ) {
src = &instance_data[instance_id].regs;
if (instance_id != 0)
src = &instance_data[instance_id].regs;
}
break;
}
@@ -3135,22 +3152,30 @@ int set_reg(struct script_state* st, struct map_session_data* sd, int64 num, con
return 1;
case '\'':
{
unsigned short instance_id = script_instancegetid(st);
if( instance_id ) {
if( str[0] ) {
i64db_put(instance_data[instance_id].regs.vars, num, aStrdup(str));
if( script_getvaridx(num) )
script_array_update(&instance_data[instance_id].regs, num, false);
struct reg_db *src = nullptr;
if (ref)
src = ref;
else {
unsigned short instance_id = script_instancegetid(st);
if (instance_id != 0)
src = &instance_data[instance_id].regs;
}
if (src) {
bool empty;
if (str[0]) {
i64db_put(src->vars, num, aStrdup(str));
empty = false;
} else {
i64db_remove(instance_data[instance_id].regs.vars, num);
if (script_getvaridx(num))
script_array_update(&instance_data[instance_id].regs, num, true);
i64db_remove(src->vars, num);
empty = true;
}
if (script_getvaridx(num) != 0)
script_array_update(src, num, empty);
} else {
ShowError("script_set_reg: cannot write instance variable '%s', NPC not in a instance!\n", name);
script_reportsrc(st);
}
return 1;
return 1;
}
default:
return pc_setglobalreg_str(sd, num, str);
@@ -3198,22 +3223,30 @@ int set_reg(struct script_state* st, struct map_session_data* sd, int64 num, con
return 1;
case '\'':
{
unsigned short instance_id = script_instancegetid(st);
if( instance_id ) {
if( val != 0 ) {
i64db_iput(instance_data[instance_id].regs.vars, num, val);
if( script_getvaridx(num) )
script_array_update(&instance_data[instance_id].regs, num, false);
struct reg_db *src = nullptr;
if (ref)
src = ref;
else {
unsigned short instance_id = script_instancegetid(st);
if (instance_id != 0)
src = &instance_data[instance_id].regs;
}
if (src) {
bool empty;
if (val != 0) {
i64db_iput(src->vars, num, val);
empty = false;
} else {
i64db_remove(instance_data[instance_id].regs.vars, num);
if (script_getvaridx(num))
script_array_update(&instance_data[instance_id].regs, num, true);
i64db_remove(src->vars, num);
empty = true;
}
if (script_getvaridx(num) != 0)
script_array_update(src, num, empty);
} else {
ShowError("script_set_reg: cannot write instance variable '%s', NPC not in a instance!\n", name);
script_reportsrc(st);
}
return 1;
return 1;
}
default:
return pc_setglobalreg(sd, num, val);
@@ -19887,30 +19920,54 @@ BUILDIN_FUNC(bg_get_data)
/*==========================================
* Instancing System
*------------------------------------------*/
//Returns an Instance ID
//Checks NPC first, then if player is attached we check
unsigned short script_instancegetid(struct script_state* st)
/**
* Returns an Instance ID.
* @param st: Script state
* @param mode: Instance mode
* @return instance ID on success or 0 otherwise
*/
unsigned short script_instancegetid(struct script_state* st, enum instance_mode mode)
{
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 = NULL;
struct party_data *pd = NULL;
struct guild *gd = NULL;
struct clan *cd = NULL;
if (mode == IM_NONE) {
struct npc_data *nd = map_id2nd(st->oid);
if ((sd = map_id2sd(st->rid))) {
if (sd->instance_id)
instance_id = sd->instance_id;
if (instance_id == 0 && sd->status.party_id && (pd = party_search(sd->status.party_id)) != NULL && pd->instance_id)
instance_id = pd->instance_id;
if (instance_id == 0 && sd->status.guild_id && (gd = guild_search(sd->status.guild_id)) != NULL && gd->instance_id)
instance_id = gd->instance_id;
if (instance_id == 0 && sd->status.clan_id && (cd = clan_search(sd->status.clan_id)) != NULL && cd->instance_id)
instance_id = cd->instance_id;
if (nd->instance_id > 0)
instance_id = nd->instance_id;
} else {
struct map_session_data *sd = map_id2sd(st->rid);
if (sd) {
switch (mode) {
case IM_CHAR:
if (sd->instance_id)
instance_id = sd->instance_id;
break;
case IM_PARTY: {
struct party_data *pd = party_search(sd->status.party_id);
if (pd && pd->instance_id)
instance_id = pd->instance_id;
}
break;
case IM_GUILD: {
struct guild *gd = guild_search(sd->status.guild_id);
if (gd && gd->instance_id)
instance_id = gd->instance_id;
}
break;
case IM_CLAN: {
struct clan *cd = clan_search(sd->status.clan_id);
if (cd && cd->instance_id)
instance_id = cd->instance_id;
}
break;
default: // Unsupported type
break;
}
}
}
@@ -20012,7 +20069,7 @@ BUILDIN_FUNC(instance_enter)
if (script_hasdata(st, 6))
instance_id = script_getnum(st, 6);
else
instance_id = script_instancegetid(st);
instance_id = script_instancegetid(st, IM_PARTY);
if (!script_charid2sd(5,sd))
return SCRIPT_CMD_FAILURE;
@@ -20085,7 +20142,19 @@ BUILDIN_FUNC(instance_mapname)
*------------------------------------------*/
BUILDIN_FUNC(instance_id)
{
script_pushint(st, script_instancegetid(st));
int mode = IM_NONE; // Default to the attached NPC
if (script_hasdata(st, 2)) {
mode = script_getnum(st, 2);
if (mode <= IM_NONE || mode >= IM_MAX) {
ShowError("buildin_instance_id: Unknown instance mode %d.\n", mode);
script_pushint(st, 0);
return SCRIPT_CMD_SUCCESS;
}
}
script_pushint(st, script_instancegetid(st, static_cast<instance_mode>(mode)));
return SCRIPT_CMD_SUCCESS;
}
@@ -20147,7 +20216,7 @@ BUILDIN_FUNC(instance_warpall)
if( script_hasdata(st,5) )
instance_id = script_getnum(st,5);
else
instance_id = script_instancegetid(st);
instance_id = script_instancegetid(st, IM_PARTY);
if( !instance_id || (m = map_mapname2mapid(mapn)) < 0 || (m = instance_mapname2mapid(map_getmapdata(m)->name,instance_id)) < 0)
return SCRIPT_CMD_FAILURE;
@@ -24271,6 +24340,57 @@ BUILDIN_FUNC(achievement_condition){
return SCRIPT_CMD_SUCCESS;
}
/// Returns a reference to a variable of the specific instance ID.
/// Returns 0 if an error occurs.
///
/// getvariableofinstance(<variable>, <instance ID>) -> <reference>
BUILDIN_FUNC(getvariableofinstance)
{
struct script_data* data = script_getdata(st, 2);
if (!data_isreference(data)) {
ShowError("buildin_getvariableofinstance: %s is not a variable.\n", script_getstr(st, 2));
script_reportdata(data);
script_pushnil(st);
st->state = END;
return SCRIPT_CMD_FAILURE;
}
const char* name = reference_getname(data);
if (*name != '\'') {
ShowError("buildin_getvariableofinstance: Invalid scope. %s is not an instance variable.\n", name);
script_reportdata(data);
script_pushnil(st);
st->state = END;
return SCRIPT_CMD_FAILURE;
}
unsigned short instance_id = script_getnum(st, 3);
if (instance_id == 0 || instance_id > MAX_INSTANCE_DATA) {
ShowError("buildin_getvariableofinstance: Invalid instance ID %d.\n", instance_id);
script_pushnil(st);
st->state = END;
return SCRIPT_CMD_FAILURE;
}
struct instance_data *im = &instance_data[instance_id];
if (im->state != INSTANCE_BUSY) {
ShowError("buildin_getvariableofinstance: Unknown instance ID %d.\n", instance_id);
script_pushnil(st);
st->state = END;
return SCRIPT_CMD_FAILURE;
}
if (!im->regs.vars)
im->regs.vars = i64db_alloc(DB_OPT_RELEASE_DATA);
push_val2(st->stack, C_NAME, reference_getuid(data), &im->regs);
return SCRIPT_CMD_SUCCESS;
}
#include "../custom/script.inc"
// declarations that were supposed to be exported from npc_chat.cpp
@@ -24780,7 +24900,7 @@ struct script_function buildin_func[] = {
// Instancing
BUILDIN_DEF(instance_create,"s??"),
BUILDIN_DEF(instance_destroy,"?"),
BUILDIN_DEF(instance_id,""),
BUILDIN_DEF(instance_id,"?"),
BUILDIN_DEF(instance_enter,"s????"),
BUILDIN_DEF(instance_npcname,"s?"),
BUILDIN_DEF(instance_mapname,"s?"),
@@ -24938,6 +25058,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(camerainfo,"iii?"),
BUILDIN_DEF(achievement_condition,"i"),
BUILDIN_DEF(getvariableofinstance,"ri"),
#include "../custom/script_def.inc"
{NULL,NULL,NULL},