Skip to content

Commit

Permalink
Allow creating instance without timer or data (#5112)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
4 people committed Feb 11, 2022
1 parent c429747 commit ac7292c
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 34 deletions.
8 changes: 5 additions & 3 deletions db/import-tmpl/instance_db.yml
Expand Up @@ -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.
Expand All @@ -37,4 +39,4 @@

Header:
Type: INSTANCE_DB
Version: 1
Version: 2
8 changes: 5 additions & 3 deletions db/instance_db.yml
Expand Up @@ -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.
Expand All @@ -37,7 +39,7 @@

Header:
Type: INSTANCE_DB
Version: 1
Version: 2

Footer:
Imports:
Expand Down
8 changes: 5 additions & 3 deletions db/pre-re/instance_db.yml
Expand Up @@ -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.
Expand All @@ -37,7 +39,7 @@

Header:
Type: INSTANCE_DB
Version: 1
Version: 2

Body:
- Id: 1
Expand Down
8 changes: 5 additions & 3 deletions db/re/instance_db.yml
Expand Up @@ -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.
Expand All @@ -37,7 +39,7 @@

Header:
Type: INSTANCE_DB
Version: 1
Version: 2

Body:
- Id: 1
Expand Down
17 changes: 17 additions & 0 deletions doc/script_commands.txt
Expand Up @@ -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.
Expand Down
6 changes: 4 additions & 2 deletions doc/yaml/db/instance_db.yml
Expand Up @@ -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.
Expand Down
66 changes: 51 additions & 15 deletions src/map/instance.cpp
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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 {
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/map/instance.hpp
Expand Up @@ -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

Expand All @@ -89,14 +91,16 @@ 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
};

class InstanceDatabase : public TypesafeYamlDatabase<int32, s_instance_db> {
public:
InstanceDatabase() : TypesafeYamlDatabase("INSTANCE_DB", 1) {
InstanceDatabase() : TypesafeYamlDatabase("INSTANCE_DB", 2, 1) {

}

Expand Down
8 changes: 5 additions & 3 deletions src/map/map.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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]);
}
Expand Down
2 changes: 1 addition & 1 deletion src/map/map.hpp
Expand Up @@ -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);
Expand Down
37 changes: 37 additions & 0 deletions src/map/script.cpp
Expand Up @@ -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
Expand Down Expand Up @@ -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
**/
Expand Down

0 comments on commit ac7292c

Please sign in to comment.