Allow creating instance without timer or data (#5112)
* Allow creating instance with no timer * Added NoNpc to prevent copying NPCs from the source map * Added NoMapFlag to prevent copying Mapflags from the source map * Added instance_list script command to retrieve the instance IDs for the given map name/instance mode Co-authored-by: Aleos <aleos89@users.noreply.github.com> Co-authored-by: Atemo <atemo@users.noreply.github.com> Co-authored-by: Lemongrass3110 <3517879+Lemongrass3110@users.noreply.github.com>
This commit is contained in:
parent
c429747f73
commit
ac7292c92d
@ -24,8 +24,10 @@
|
||||
###########################################################################
|
||||
# - Id Instance ID.
|
||||
# Name Instance Name.
|
||||
# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
|
||||
# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
|
||||
# TimeLimit Total lifetime of instance in seconds. Use 0 to define infinite time. (Default: 3600)
|
||||
# IdleTimeOut Time before an idle instance is destroyed in seconds. Use 0 to define infinite idle time. (Default: 300)
|
||||
# NoNpc Prevent copying NPCs from the source map. (Default: false)
|
||||
# NoMapFlag Prevent copying Mapflags from the source map. (Default: false)
|
||||
# Destroyable Toggles the ability to destroy the instance using instance 'Destroy' button. (Default: true)
|
||||
# Note: the button is displayed based on parties. For any mode, it requires the party leader to be the instance owner to destroy it.
|
||||
# Enter: Instance entrance coordinates.
|
||||
@ -37,4 +39,4 @@
|
||||
|
||||
Header:
|
||||
Type: INSTANCE_DB
|
||||
Version: 1
|
||||
Version: 2
|
||||
|
@ -24,8 +24,10 @@
|
||||
###########################################################################
|
||||
# - Id Instance ID.
|
||||
# Name Instance Name.
|
||||
# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
|
||||
# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
|
||||
# TimeLimit Total lifetime of instance in seconds. Use 0 to define infinite time. (Default: 3600)
|
||||
# IdleTimeOut Time before an idle instance is destroyed in seconds. Use 0 to define infinite idle time. (Default: 300)
|
||||
# NoNpc Prevent copying NPCs from the source map. (Default: false)
|
||||
# NoMapFlag Prevent copying Mapflags from the source map. (Default: false)
|
||||
# Destroyable Toggles the ability to destroy the instance using instance 'Destroy' button. (Default: true)
|
||||
# Note: the button is displayed based on parties. For any mode, it requires the party leader to be the instance owner to destroy it.
|
||||
# Enter: Instance entrance coordinates.
|
||||
@ -37,7 +39,7 @@
|
||||
|
||||
Header:
|
||||
Type: INSTANCE_DB
|
||||
Version: 1
|
||||
Version: 2
|
||||
|
||||
Footer:
|
||||
Imports:
|
||||
|
@ -24,8 +24,10 @@
|
||||
###########################################################################
|
||||
# - Id Instance ID.
|
||||
# Name Instance Name.
|
||||
# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
|
||||
# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
|
||||
# TimeLimit Total lifetime of instance in seconds. Use 0 to define infinite time. (Default: 3600)
|
||||
# IdleTimeOut Time before an idle instance is destroyed in seconds. Use 0 to define infinite idle time. (Default: 300)
|
||||
# NoNpc Prevent copying NPCs from the source map. (Default: false)
|
||||
# NoMapFlag Prevent copying Mapflags from the source map. (Default: false)
|
||||
# Destroyable Toggles the ability to destroy the instance using instance 'Destroy' button. (Default: true)
|
||||
# Note: the button is displayed based on parties. For any mode, it requires the party leader to be the instance owner to destroy it.
|
||||
# Enter: Instance entrance coordinates.
|
||||
@ -37,7 +39,7 @@
|
||||
|
||||
Header:
|
||||
Type: INSTANCE_DB
|
||||
Version: 1
|
||||
Version: 2
|
||||
|
||||
Body:
|
||||
- Id: 1
|
||||
|
@ -24,8 +24,10 @@
|
||||
###########################################################################
|
||||
# - Id Instance ID.
|
||||
# Name Instance Name.
|
||||
# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
|
||||
# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
|
||||
# TimeLimit Total lifetime of instance in seconds. Use 0 to define infinite time. (Default: 3600)
|
||||
# IdleTimeOut Time before an idle instance is destroyed in seconds. Use 0 to define infinite idle time. (Default: 300)
|
||||
# NoNpc Prevent copying NPCs from the source map. (Default: false)
|
||||
# NoMapFlag Prevent copying Mapflags from the source map. (Default: false)
|
||||
# Destroyable Toggles the ability to destroy the instance using instance 'Destroy' button. (Default: true)
|
||||
# Note: the button is displayed based on parties. For any mode, it requires the party leader to be the instance owner to destroy it.
|
||||
# Enter: Instance entrance coordinates.
|
||||
@ -37,7 +39,7 @@
|
||||
|
||||
Header:
|
||||
Type: INSTANCE_DB
|
||||
Version: 1
|
||||
Version: 2
|
||||
|
||||
Body:
|
||||
- Id: 1
|
||||
|
@ -9481,6 +9481,23 @@ Examples:
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*instance_list(<"map name">{,<instance mode>});
|
||||
|
||||
Creates the array '.@instance_list' with possible instance IDs for the given <map name> and optional <mode>.
|
||||
Return '.@instance_list' array size.
|
||||
|
||||
Instance mode options: IM_NONE, IM_CHAR, IM_PARTY, IM_GUILD, or IM_CLAN
|
||||
If the instance mode is not provided then it will return all the instance IDs for that map.
|
||||
|
||||
Examples:
|
||||
// This example assumes that there are several instances on the map of Prontera.
|
||||
.@size = instance_list("prontera");
|
||||
for ( .@i = 0; .@i < .@size; ++.@i )
|
||||
mes instance_mapname("prontera", .@instance_list[.@i]);
|
||||
//the output would be a list of all prontera copies that are active in the server.
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*getinstancevar(<variable>,<instance id>);
|
||||
|
||||
Returns a reference to an instance variable (' prefix) of the specific instance ID.
|
||||
|
@ -7,8 +7,10 @@
|
||||
###########################################################################
|
||||
# - Id Instance ID.
|
||||
# Name Instance Name.
|
||||
# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
|
||||
# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
|
||||
# TimeLimit Total lifetime of instance in seconds. Use 0 to define infinite time. (Default: 3600)
|
||||
# IdleTimeOut Time before an idle instance is destroyed in seconds. Use 0 to define infinite idle time. (Default: 300)
|
||||
# NoNpc Prevent copying NPCs from the source map. (Default: false)
|
||||
# NoMapFlag Prevent copying Mapflags from the source map. (Default: false)
|
||||
# Destroyable Toggles the ability to destroy the instance using instance 'Destroy' button. (Default: true)
|
||||
# Note: the button is displayed based on parties. For any mode, it requires the party leader to be the instance owner to destroy it.
|
||||
# Enter: Instance entrance coordinates.
|
||||
|
@ -112,6 +112,32 @@ uint64 InstanceDatabase::parseBodyNode(const YAML::Node &node) {
|
||||
instance->timeout = 300;
|
||||
}
|
||||
|
||||
if (this->nodeExists(node, "NoNpc")) {
|
||||
bool nonpc;
|
||||
|
||||
if (!this->asBool(node, "NoNpc", nonpc))
|
||||
return 0;
|
||||
|
||||
instance->nonpc = nonpc;
|
||||
}
|
||||
else {
|
||||
if (!exists)
|
||||
instance->nonpc = false;
|
||||
}
|
||||
|
||||
if (this->nodeExists(node, "NoMapFlag")) {
|
||||
bool nomapflag;
|
||||
|
||||
if (!this->asBool(node, "NoMapFlag", nomapflag))
|
||||
return 0;
|
||||
|
||||
instance->nomapflag = nomapflag;
|
||||
}
|
||||
else {
|
||||
if (!exists)
|
||||
instance->nomapflag = false;
|
||||
}
|
||||
|
||||
if (this->nodeExists(node, "Destroyable")) {
|
||||
bool destroy;
|
||||
|
||||
@ -332,7 +358,7 @@ static TIMER_FUNC(instance_subscription_timer){
|
||||
bool instance_startkeeptimer(std::shared_ptr<s_instance_data> idata, int instance_id)
|
||||
{
|
||||
// No timer
|
||||
if (!idata || idata->keep_timer != INVALID_TIMER)
|
||||
if (!idata || idata->keep_timer != INVALID_TIMER || idata->keep_limit == 0)
|
||||
return false;
|
||||
|
||||
std::shared_ptr<s_instance_db> db = instance_db.find(idata->id);
|
||||
@ -430,7 +456,6 @@ bool instance_stopidletimer(std::shared_ptr<s_instance_data> idata, int instance
|
||||
return false;
|
||||
|
||||
// Delete the timer - Party has returned or instance is destroyed
|
||||
idata->idle_limit = 0;
|
||||
delete_timer(idata->idle_timer, instance_delete_timer);
|
||||
idata->idle_timer = INVALID_TIMER;
|
||||
|
||||
@ -439,19 +464,19 @@ bool instance_stopidletimer(std::shared_ptr<s_instance_data> idata, int instance
|
||||
break;
|
||||
case IM_CHAR:
|
||||
if (map_charid2sd(idata->owner_id)) // Notify the player
|
||||
clif_instance_changestatus(instance_id, IN_NOTIFY, idata->idle_limit);
|
||||
clif_instance_changestatus(instance_id, IN_NOTIFY, 0);
|
||||
break;
|
||||
case IM_PARTY:
|
||||
if (party_search(idata->owner_id)) // Notify the party
|
||||
clif_instance_changestatus(instance_id, IN_NOTIFY, idata->idle_limit);
|
||||
clif_instance_changestatus(instance_id, IN_NOTIFY, 0);
|
||||
break;
|
||||
case IM_GUILD:
|
||||
if (guild_search(idata->owner_id)) // Notify the guild
|
||||
clif_instance_changestatus(instance_id, IN_NOTIFY, idata->idle_limit);
|
||||
clif_instance_changestatus(instance_id, IN_NOTIFY, 0);
|
||||
break;
|
||||
case IM_CLAN:
|
||||
if (clan_search(idata->owner_id)) // Notify the clan
|
||||
clif_instance_changestatus(instance_id, IN_NOTIFY, idata->idle_limit);
|
||||
clif_instance_changestatus(instance_id, IN_NOTIFY, 0);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
@ -651,13 +676,22 @@ int instance_addmap(int instance_id) {
|
||||
|
||||
// Set to busy, update timers
|
||||
idata->state = INSTANCE_BUSY;
|
||||
idata->idle_limit = static_cast<unsigned int>(time(nullptr)) + db->timeout;
|
||||
idata->idle_timer = add_timer(gettick() + db->timeout * 1000, instance_delete_timer, instance_id, 0);
|
||||
if (db->timeout > 0) {
|
||||
idata->idle_limit = static_cast<unsigned int>(time(nullptr)) + db->timeout;
|
||||
idata->idle_timer = add_timer(gettick() + db->timeout * 1000, instance_delete_timer, instance_id, 0);
|
||||
}
|
||||
|
||||
if (db->limit > 0) {
|
||||
//This will allow the instance to get a time in 'instance_startkeeptimer'
|
||||
idata->keep_limit = 1;
|
||||
}
|
||||
idata->nomapflag = db->nomapflag;
|
||||
idata->nonpc = db->nonpc;
|
||||
|
||||
int16 m;
|
||||
|
||||
// Add initial map
|
||||
if ((m = map_addinstancemap(db->enter.map, instance_id)) < 0) {
|
||||
if ((m = map_addinstancemap(db->enter.map, instance_id, db->nomapflag)) < 0) {
|
||||
ShowError("instance_addmap: Failed to create initial map for instance '%s' (%d).\n", db->name.c_str(), instance_id);
|
||||
return 0;
|
||||
}
|
||||
@ -670,7 +704,7 @@ int instance_addmap(int instance_id) {
|
||||
|
||||
// Add extra maps (if any)
|
||||
for (const auto &it : db->maplist) {
|
||||
if ((m = map_addinstancemap(it, instance_id)) < 0) { // An error occured adding a map
|
||||
if ((m = map_addinstancemap(it, instance_id, db->nomapflag)) < 0) { // An error occured adding a map
|
||||
ShowError("instance_addmap: No maps added to instance '%s' (%d).\n", db->name.c_str(), instance_id);
|
||||
return 0;
|
||||
} else {
|
||||
@ -681,7 +715,8 @@ int instance_addmap(int instance_id) {
|
||||
}
|
||||
|
||||
// Create NPCs on all maps
|
||||
instance_addnpc(idata);
|
||||
if(!db->nonpc)
|
||||
instance_addnpc(idata);
|
||||
|
||||
switch(idata->mode) {
|
||||
case IM_NONE:
|
||||
@ -1098,7 +1133,7 @@ bool instance_addusers(int instance_id)
|
||||
{
|
||||
std::shared_ptr<s_instance_data> idata = util::umap_find(instances, instance_id);
|
||||
|
||||
if(!idata || idata->state != INSTANCE_BUSY)
|
||||
if(!idata || idata->state != INSTANCE_BUSY || idata->idle_limit == 0)
|
||||
return false;
|
||||
|
||||
// Stop the idle timer if we had one
|
||||
@ -1119,7 +1154,7 @@ bool instance_delusers(int instance_id)
|
||||
{
|
||||
std::shared_ptr<s_instance_data> idata = util::umap_find(instances, instance_id);
|
||||
|
||||
if(!idata || idata->state != INSTANCE_BUSY)
|
||||
if(!idata || idata->state != INSTANCE_BUSY || idata->idle_limit == 0)
|
||||
return false;
|
||||
|
||||
int users = 0;
|
||||
@ -1148,12 +1183,13 @@ void do_reload_instance(void)
|
||||
continue;
|
||||
else {
|
||||
// First we load the NPCs again
|
||||
instance_addnpc(idata);
|
||||
if(!idata->nonpc)
|
||||
instance_addnpc(idata);
|
||||
|
||||
// Create new keep timer
|
||||
std::shared_ptr<s_instance_db> db = instance_db.find(idata->id);
|
||||
|
||||
if (db)
|
||||
if (db && db->limit > 0)
|
||||
idata->keep_limit = static_cast<unsigned int>(time(nullptr)) + db->limit;
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,8 @@ struct s_instance_data {
|
||||
int keep_timer; ///< Life time ID
|
||||
unsigned int idle_limit; ///< Idle time of instance
|
||||
int idle_timer; ///< Idle timer ID
|
||||
bool nonpc;
|
||||
bool nomapflag;
|
||||
struct reg_db regs; ///< Instance variables for scripts
|
||||
std::vector<s_instance_map> map; ///< Array of maps in instance
|
||||
|
||||
@ -89,6 +91,8 @@ struct s_instance_db {
|
||||
std::string name; ///< Instance name
|
||||
uint32 limit, ///< Duration limit
|
||||
timeout; ///< Timeout limit
|
||||
bool nonpc;
|
||||
bool nomapflag;
|
||||
bool destroyable; ///< Destroyable flag
|
||||
struct point enter; ///< Instance entry point
|
||||
std::vector<int16> maplist; ///< Maps in instance
|
||||
@ -96,7 +100,7 @@ struct s_instance_db {
|
||||
|
||||
class InstanceDatabase : public TypesafeYamlDatabase<int32, s_instance_db> {
|
||||
public:
|
||||
InstanceDatabase() : TypesafeYamlDatabase("INSTANCE_DB", 1) {
|
||||
InstanceDatabase() : TypesafeYamlDatabase("INSTANCE_DB", 2, 1) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -2705,7 +2705,7 @@ bool map_addnpc(int16 m,struct npc_data *nd)
|
||||
/*==========================================
|
||||
* Add an instance map
|
||||
*------------------------------------------*/
|
||||
int map_addinstancemap(int src_m, int instance_id)
|
||||
int map_addinstancemap(int src_m, int instance_id, bool no_mapflag)
|
||||
{
|
||||
if(src_m < 0)
|
||||
return -1;
|
||||
@ -2771,7 +2771,8 @@ int map_addinstancemap(int src_m, int instance_id)
|
||||
dst_map->channel = nullptr;
|
||||
dst_map->mob_delete_timer = INVALID_TIMER;
|
||||
|
||||
map_data_copy(dst_map, src_map);
|
||||
if(!no_mapflag)
|
||||
map_data_copy(dst_map, src_map);
|
||||
|
||||
ShowInfo("[Instance] Created map '%s' (%d) from '%s' (%d).\n", dst_map->name, dst_map->m, name, src_map->m);
|
||||
|
||||
@ -3707,7 +3708,8 @@ void map_data_copyall (void) {
|
||||
return;
|
||||
for (int i = instance_start; i < map_num; i++) {
|
||||
struct map_data *mapdata = &map[i];
|
||||
if (!mapdata || mapdata->name[0] == '\0' || !mapdata->instance_src_map)
|
||||
std::shared_ptr<s_instance_data> idata = util::umap_find(instances, mapdata->instance_id);
|
||||
if (!mapdata || mapdata->name[0] == '\0' || !mapdata->instance_src_map || (idata && idata->nomapflag))
|
||||
continue;
|
||||
map_data_copy(mapdata, &map[mapdata->instance_src_map]);
|
||||
}
|
||||
|
@ -1085,7 +1085,7 @@ 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, bool canShowEffect = false);
|
||||
|
||||
// instances
|
||||
int map_addinstancemap(int src_m, int instance_id);
|
||||
int map_addinstancemap(int src_m, int instance_id, bool no_mapflag);
|
||||
int map_delinstancemap(int m);
|
||||
void map_data_copyall(void);
|
||||
void map_data_copy(struct map_data *dst_map, struct map_data *src_map);
|
||||
|
@ -21589,6 +21589,42 @@ BUILDIN_FUNC(instance_live_info)
|
||||
}
|
||||
return SCRIPT_CMD_SUCCESS;
|
||||
}
|
||||
/*==========================================
|
||||
* instance_list(<"map name">{,<instance mode>});
|
||||
* set '.@instance_list' to a list of the live instance ids for the map with the mode.
|
||||
* return the array size of '.@instance_list'
|
||||
*------------------------------------------*/
|
||||
BUILDIN_FUNC(instance_list)
|
||||
{
|
||||
int src_id = map_mapname2mapid(script_getstr(st, 2));
|
||||
if (src_id == 0) {
|
||||
ShowError("buildin_instance_list: map '%s' doesn't exist\n", script_getstr(st, 2));
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
}
|
||||
|
||||
e_instance_mode mode = IM_MAX;
|
||||
if (script_hasdata(st, 3)) {
|
||||
mode = static_cast<e_instance_mode>(script_getnum(st, 3));
|
||||
if (mode < IM_NONE || mode >= IM_MAX) {
|
||||
ShowError("buildin_instance_list: Unknown instance mode %d for '%s'\n", mode, script_getstr(st, 3));
|
||||
return SCRIPT_CMD_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
for (int i = instance_start; i < map_num; i++) {
|
||||
struct map_data* mapdata = &map[i];
|
||||
if (mapdata->instance_src_map == src_id) {
|
||||
std::shared_ptr<s_instance_data> idata = util::umap_find(instances, mapdata->instance_id);
|
||||
if (idata && (mode == IM_MAX || idata->mode == mode)) {
|
||||
setd_sub_num(st, nullptr, ".@instance_list", j, mapdata->instance_id, nullptr);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
script_pushint(st, j);
|
||||
return SCRIPT_CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* Custom Fonts
|
||||
@ -26242,6 +26278,7 @@ struct script_function buildin_func[] = {
|
||||
BUILDIN_DEF(instance_check_clan,"i???"),
|
||||
BUILDIN_DEF(instance_info,"si?"),
|
||||
BUILDIN_DEF(instance_live_info,"i?"),
|
||||
BUILDIN_DEF(instance_list, "s?"),
|
||||
/**
|
||||
* 3rd-related
|
||||
**/
|
||||
|
Loading…
x
Reference in New Issue
Block a user