Skip to content

Commit

Permalink
Adds support for instance destruction button (rathena#5073)
Browse files Browse the repository at this point in the history
* Adds support for instance destruction button
* Adds an extra parameter in the instance database to toggle if an instance is destroy-able or not.
* Adds support for being notified about character and Clan instances on login.
* Fixes an issue with the instance window displaying wrong instance information on an instance map when multiples instances were running for the character.
Co-authored-by: atemo <[email protected]>
  • Loading branch information
aleos89 authored Jun 17, 2020
1 parent 04ba3e3 commit 3804d7f
Show file tree
Hide file tree
Showing 18 changed files with 185 additions and 34 deletions.
2 changes: 2 additions & 0 deletions db/import-tmpl/instance_db.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
# Name Instance Name.
# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
# 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.
# Map Map Name where players start.
# X X Coordinate where players start.
Expand Down
2 changes: 2 additions & 0 deletions db/instance_db.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
# Name Instance Name.
# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
# 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.
# Map Map Name where players start.
# X X Coordinate where players start.
Expand Down
2 changes: 2 additions & 0 deletions db/pre-re/instance_db.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
# Name Instance Name.
# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
# 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.
# Map Map Name where players start.
# X X Coordinate where players start.
Expand Down
2 changes: 2 additions & 0 deletions db/re/instance_db.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
# Name Instance Name.
# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
# 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.
# Map Map Name where players start.
# X X Coordinate where players start.
Expand Down
2 changes: 2 additions & 0 deletions doc/yaml/db/instance_db.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
# Name Instance Name.
# TimeLimit Total lifetime of instance in seconds. (Default: 3600)
# IdleTimeOut Time before an idle instance is destroyed in seconds. (Default: 300)
# 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.
# Map Map Name where players start.
# X X Coordinate where players start.
Expand Down
2 changes: 1 addition & 1 deletion src/common/mmo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ struct guild {
struct guild_expulsion expulsion[MAX_GUILDEXPULSION];
struct guild_skill skill[MAX_GUILDSKILL];
struct Channel *channel;
unsigned short instance_id;
int instance_id;
time_t last_leader_change;

/* Used by char-server to save events for guilds */
Expand Down
4 changes: 4 additions & 0 deletions src/map/clan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "../common/showmsg.hpp"

#include "clif.hpp"
#include "instance.hpp"
#include "intif.hpp"
#include "log.hpp"
#include "pc.hpp"
Expand Down Expand Up @@ -128,6 +129,9 @@ void clan_member_joined( struct map_session_data* sd ){

intif_clan_member_joined(clan->id);
clif_clan_onlinecount(clan);

if (clan->instance_id > 0)
instance_reqinfo(sd, clan->instance_id);
}
}

Expand Down
25 changes: 25 additions & 0 deletions src/map/clif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17968,6 +17968,22 @@ void clif_instance_changestatus(int instance_id, e_instance_notify type, unsigne
return;
}

/// Destroy an instance from the status window
/// 02cf <command>.L (CZ_MEMORIALDUNGEON_COMMAND)
void clif_parse_MemorialDungeonCommand(int fd, map_session_data *sd)
{
if (pc_istrading(sd) || pc_isdead(sd) || map_getmapdata(sd->bl.m)->instance_id > 0)
return;

const PACKET_CZ_MEMORIALDUNGEON_COMMAND *p = (PACKET_CZ_MEMORIALDUNGEON_COMMAND *)RFIFOP(fd, 0);

switch (p->command) {
case COMMAND_MEMORIALDUNGEON_DESTROY_FORCE:
instance_destroy_command(sd);
break;
}
}

/// Notifies clients about item picked up by a party member.
/// 02b8 <account id>.L <name id>.W <identified>.B <damaged>.B <refine>.B <card1>.W <card2>.W <card3>.W <card4>.W <equip location>.W <item type>.B (ZC_ITEM_PICKUP_PARTY)
void clif_party_show_picker( struct map_session_data* sd, struct item* item_data ){
Expand Down Expand Up @@ -19047,6 +19063,15 @@ static void clif_loadConfirm( struct map_session_data *sd ){
p.packetType = HEADER_ZC_LOAD_CONFIRM;

clif_send( &p, sizeof(p), &sd->bl, SELF );

if (sd->instance_id > 0)
instance_reqinfo(sd, sd->instance_id);
if (sd->status.party_id > 0)
party_member_joined(sd);
if (sd->status.guild_id > 0)
guild_member_joined(sd);
if (sd->status.clan_id > 0)
clan_member_joined(sd);
#endif
}

Expand Down
5 changes: 5 additions & 0 deletions src/map/clif.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,10 @@ enum e_config_type : uint32 {
CONFIG_HOMUNCULUS_AUTOFEED
};

enum e_memorial_dungeon_command : uint16 {
COMMAND_MEMORIALDUNGEON_DESTROY_FORCE = 0x3,
};

int clif_setip(const char* ip);
void clif_setbindip(const char* ip);
void clif_setport(uint16 port);
Expand Down Expand Up @@ -843,6 +847,7 @@ void clif_instance_create(int instance_id, int num);
void clif_instance_changewait(int instance_id, int num);
void clif_instance_status(int instance_id, unsigned int limit1, unsigned int limit2);
void clif_instance_changestatus(int instance_id, e_instance_notify type, unsigned int limit);
void clif_parse_MemorialDungeonCommand(int fd, map_session_data *sd);

// Custom Fonts
void clif_font(struct map_session_data *sd);
Expand Down
2 changes: 1 addition & 1 deletion src/map/clif_packetdb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1109,7 +1109,7 @@
packet(0x02cc,4);
packet(0x02cd,26);
packet(0x02ce,10);
packet(0x02cf,6);
parseable_packet(0x02cf,6,clif_parse_MemorialDungeonCommand,2);
packet(0x02d0,-1);
packet(0x02d1,-1);
packet(0x02d2,-1);
Expand Down
6 changes: 3 additions & 3 deletions src/map/guild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@ int guild_recv_info(struct guild *sg) {
clif_guild_notice(sd);
sd->guild_emblem_id = g->emblem_id;
}
if (g->instance_id != 0)
if (g->instance_id > 0)
instance_reqinfo(sd, g->instance_id);
}

Expand Down Expand Up @@ -818,7 +818,7 @@ void guild_member_joined(struct map_session_data *sd) {
g->member[i].sd = sd;
sd->guild = g;

if (g->instance_id != 0)
if (g->instance_id > 0)
instance_reqinfo(sd, g->instance_id);
if( channel_config.ally_tmpl.name[0] && (channel_config.ally_tmpl.opt&CHAN_OPT_AUTOJOIN) ) {
channel_gjoin(sd,3);
Expand Down Expand Up @@ -870,7 +870,7 @@ 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)
if (g->instance_id > 0)
instance_reqinfo(sd, g->instance_id);

return 0;
Expand Down
106 changes: 101 additions & 5 deletions src/map/instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ uint64 InstanceDatabase::parseBodyNode(const YAML::Node &node) {
instance->timeout = 300;
}

/*
if (this->nodeExists(node, "Destroyable")) {
bool destroy;

Expand All @@ -123,7 +122,6 @@ uint64 InstanceDatabase::parseBodyNode(const YAML::Node &node) {
if (!exists)
instance->destroyable = true;
}
*/

if (this->nodeExists(node, "Enter")) {
const YAML::Node &enterNode = node["Enter"];
Expand Down Expand Up @@ -539,7 +537,7 @@ int instance_create(int owner_id, const char *name, e_instance_mode mode) {
return -1;
}

struct map_session_data *sd;
struct map_session_data *sd = nullptr;
struct party_data *pd;
struct guild *gd;
struct clan* cd;
Expand Down Expand Up @@ -603,15 +601,24 @@ int instance_create(int owner_id, const char *name, e_instance_mode mode) {
break;
case IM_PARTY:
pd->instance_id = instance_id;
int32 i;
ARR_FIND(0, MAX_PARTY, i, pd->party.member[i].leader);

if (i < MAX_PARTY)
sd = map_charid2sd(pd->party.member[i].char_id);
break;
case IM_GUILD:
gd->instance_id = instance_id;
sd = map_charid2sd(gd->member[0].char_id);
break;
case IM_CLAN:
cd->instance_id = instance_id;
break;
}

if (sd != nullptr)
sd->instance_mode = mode;

instance_wait.id.push_back(instance_id);
clif_instance_create(instance_id, instance_wait.id.size());
instance_subscription_timer(0,0,0,0);
Expand Down Expand Up @@ -742,6 +749,89 @@ int16 instance_mapid(int16 m, int instance_id)
return m;
}

/**
* Removes an instance, all its maps, and NPCs invoked by the client button.
* @param sd: Player data
*/
void instance_destroy_command(map_session_data *sd) {
nullpo_retv(sd);

std::shared_ptr<s_instance_data> idata;
int instance_id = 0;

if (sd->instance_mode == IM_CHAR && sd->instance_id > 0) {
idata = util::umap_find(instances, sd->instance_id);

if (idata == nullptr)
return;

instance_id = sd->instance_id;
} else if (sd->instance_mode == IM_PARTY && sd->status.party_id > 0) {
party_data *pd = party_search(sd->status.party_id);

if (pd == nullptr)
return;

idata = util::umap_find(instances, pd->instance_id);

if (idata == nullptr)
return;

int32 i;

ARR_FIND(0, MAX_PARTY, i, pd->data[i].sd == sd && pd->party.member[i].leader);

if (i == MAX_PARTY) // Player is not party leader
return;

instance_id = pd->instance_id;
} else if (sd->instance_mode == IM_GUILD && sd->guild != nullptr && sd->guild->instance_id > 0) {
guild *gd = guild_search(sd->status.guild_id);

if (gd == nullptr)
return;

idata = util::umap_find(instances, gd->instance_id);

if (idata == nullptr)
return;

if (strcmp(sd->status.name, gd->master) != 0) // Player is not guild master
return;

instance_id = gd->instance_id;
}

if (instance_id == 0) // Checks above failed
return;

if (!instance_db.find(idata->id)->destroyable) // Instance is flagged as non-destroyable
return;

instance_destroy(instance_id);

// Check for any other active instances and display their info
if (sd->instance_id > 0)
instance_reqinfo(sd, sd->instance_id);
if (sd->status.party_id > 0) {
party_data *pd = party_search(sd->status.party_id);

if (pd == nullptr)
return;

if (pd->instance_id > 0)
instance_reqinfo(sd, pd->instance_id);
}
if (sd->guild != nullptr && sd->guild->instance_id > 0) {
guild *gd = guild_search(sd->status.guild_id);

if (gd == nullptr)
return;

instance_reqinfo(sd, gd->instance_id);
}
}

/**
* Removes an instance, all its maps, and NPCs.
* @param instance_id: Instance to remove
Expand Down Expand Up @@ -972,11 +1062,17 @@ bool instance_reqinfo(struct map_session_data *sd, int instance_id)
for (int i = 0; i < instance_wait.id.size(); i++) {
if (instance_wait.id[i] == instance_id) {
clif_instance_create(instance_id, i + 1);
sd->instance_mode = idata->mode;
break;
}
}
} else if(idata->state == INSTANCE_BUSY) // Give info on the instance if busy
clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
} else if (idata->state == INSTANCE_BUSY) { // Give info on the instance if busy
int map_instance_id = map_getmapdata(sd->bl.m)->instance_id;
if (map_instance_id == 0 || map_instance_id == instance_id) {
clif_instance_status(instance_id, idata->keep_limit, idata->idle_limit);
sd->instance_mode = idata->mode;
}
}

return true;
}
Expand Down
3 changes: 2 additions & 1 deletion src/map/instance.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ struct s_instance_db {
std::string name; ///< Instance name
uint32 limit, ///< Duration limit
timeout; ///< Timeout limit
//bool destroyable; ///< Destroyable flag
bool destroyable; ///< Destroyable flag
struct point enter; ///< Instance entry point
std::vector<int16> maplist; ///< Maps in instance
};
Expand All @@ -113,6 +113,7 @@ void instance_getsd(int instance_id, struct map_session_data *&sd, enum send_tar

int instance_create(int owner_id, const char *name, e_instance_mode mode);
bool instance_destroy(int instance_id);
void instance_destroy_command(map_session_data *sd);
e_instance_enter instance_enter(struct map_session_data *sd, int instance_id, const char *name, short x, short y);
bool instance_reqinfo(struct map_session_data *sd, int instance_id);
bool instance_addusers(int instance_id);
Expand Down
3 changes: 2 additions & 1 deletion src/map/npc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,12 @@ struct npc_data {
struct view_data vd;
struct status_change sc; //They can't have status changes, but.. they want the visual opt values.
struct npc_data *master_nd;
short class_,speed,instance_id;
short class_,speed;
char name[NPC_NAME_LENGTH+1];// display name
char exname[NPC_NAME_LENGTH+1];// unique npc name
int chat_id,touching_id;
unsigned int next_walktime;
int instance_id;

unsigned size : 2;

Expand Down
12 changes: 6 additions & 6 deletions src/map/party.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,8 @@ int party_recv_info(struct party* sp, uint32 char_id)
}
clif_party_info(p,NULL);

if( p->instance_id != 0 )
instance_reqinfo(sd,p->instance_id);
if (p->instance_id > 0)
instance_reqinfo(sd, p->instance_id);
}

// If a player was renamed, make sure to resend the party information
Expand Down Expand Up @@ -504,8 +504,8 @@ void party_member_joined(struct map_session_data *sd)
if (i < MAX_PARTY) {
p->data[i].sd = sd;

if( p->instance_id )
instance_reqinfo(sd,p->instance_id);
if (p->instance_id > 0)
instance_reqinfo(sd, p->instance_id);
} else
sd->status.party_id = 0; //He does not belongs to the party really?
}
Expand Down Expand Up @@ -562,8 +562,8 @@ int party_member_added(int party_id,uint32 account_id,uint32 char_id, int flag)
clif_party_xy(sd);
clif_name_area(&sd->bl); //Update char name's display [Skotlex]

if( p->instance_id )
instance_reqinfo(sd,p->instance_id);
if (p->instance_id > 0)
instance_reqinfo(sd, p->instance_id);

return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion src/map/party.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,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 short instance_id;
int 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?
Expand Down
Loading

0 comments on commit 3804d7f

Please sign in to comment.