summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/map/channel.c158
-rw-r--r--src/map/channel.h11
-rw-r--r--src/map/map.c4
-rw-r--r--src/map/pc.c2
4 files changed, 90 insertions, 85 deletions
diff --git a/src/map/channel.c b/src/map/channel.c
index aa7b10ba3..88e0c4689 100644
--- a/src/map/channel.c
+++ b/src/map/channel.c
@@ -80,10 +80,13 @@ struct channel_data *channel_search(const char *name, struct map_session_data *s
struct channel_data *channel_create(enum channel_types type, const char *name, unsigned char color)
{
struct channel_data *chan;
+
+ if (!name)
+ return NULL;
+
CREATE(chan, struct channel_data, 1);
chan->users = idb_alloc(DB_OPT_BASE);
- if (name)
- safestrncpy(chan->name, name, HCS_NAME_LENGTH);
+ safestrncpy(chan->name, name, HCS_NAME_LENGTH);
chan->color = color;
chan->options = HCS_OPT_BASE;
@@ -97,50 +100,37 @@ struct channel_data *channel_create(enum channel_types type, const char *name, u
return chan;
}
+/**
+ * Deletes a chat channel.
+ *
+ * @param chan The channel to delete
+ */
void channel_delete(struct channel_data *chan)
{
+ nullpo_retv(chan);
+
if (db_size(chan->users) && !channel->config->closing) {
DBIterator *iter;
struct map_session_data *sd;
- unsigned char i;
iter = db_iterator(chan->users);
- for( sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter) ) {
- for( i = 0; i < sd->channel_count; i++ ) {
- if( sd->channels[i] == chan ) {
- sd->channels[i] = NULL;
- break;
- }
- }
- if( i < sd->channel_count ) {
- unsigned char cursor = 0;
- for( i = 0; i < sd->channel_count; i++ ) {
- if( sd->channels[i] == NULL )
- continue;
- if( cursor != i ) {
- sd->channels[cursor] = sd->channels[i];
- }
- cursor++;
- }
- if ( !(sd->channel_count = cursor) ) {
- aFree(sd->channels);
- sd->channels = NULL;
- }
- }
+ for (sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter)) {
+ channel->leave_sub(chan, sd);
}
dbi_destroy(iter);
}
- if( chan->banned ) {
+ if (chan->banned) {
db_destroy(chan->banned);
chan->banned = NULL;
}
db_destroy(chan->users);
- if( chan->m ) {
+ if (chan->m) {
map->list[chan->m].channel = NULL;
aFree(chan);
- } else if ( chan->type == HCS_TYPE_ALLY )
+ } else if (chan->type == HCS_TYPE_ALLY) {
aFree(chan);
- else if (!channel->config->closing)
+ } else if (!channel->config->closing) {
strdb_remove(channel->db, chan->name);
+ }
}
/**
@@ -294,7 +284,7 @@ void channel_join_sub(struct channel_data *chan, struct map_session_data *sd, bo
return;
RECREATE(sd->channels, struct channel_data *, ++sd->channel_count);
- sd->channels[ sd->channel_count - 1 ] = chan;
+ sd->channels[sd->channel_count - 1] = chan;
if (!stealth && (chan->options&HCS_OPT_ANNOUNCE_JOIN)) {
char message[60];
@@ -351,7 +341,7 @@ enum channel_operation_status channel_join(struct channel_data *chan, struct map
if (!silent && !(chan->options&HCS_OPT_ANNOUNCE_JOIN)) {
char output[CHAT_SIZE_MAX];
if (chan->type == HCS_TYPE_MAP) {
- sprintf(output, msg_txt(1435), chan->name, map->list[sd->bl.m].name); // You're now in the '#%s' channel for '%s'
+ sprintf(output, msg_txt(1435), chan->name, map->list[chan->m].name); // You're now in the '#%s' channel for '%s'
} else {
sprintf(output, msg_txt(1403), chan->name); // You're now in the '%s' channel
}
@@ -376,75 +366,88 @@ enum channel_operation_status channel_join(struct channel_data *chan, struct map
return HCS_STATUS_OK;
}
-void channel_leave(struct channel_data *chan, struct map_session_data *sd)
+/**
+ * Removes a channel from a character's join lists.
+ *
+ * @param chan The channel to leave
+ * @param sd The character
+ */
+void channel_leave_sub(struct channel_data *chan, struct map_session_data *sd)
{
unsigned char i;
- if ( !idb_remove(chan->users,sd->status.char_id) )
- return;
-
- if( chan == sd->gcbind )
- sd->gcbind = NULL;
-
- if( !db_size(chan->users) && chan->type == HCS_TYPE_PRIVATE ) {
- channel->delete(chan);
- } else if( !channel->config->closing && (chan->options & HCS_OPT_ANNOUNCE_JOIN) ) {
- char message[60];
- sprintf(message, "#%s '%s' left",chan->name,sd->status.name);
- clif->channel_msg(chan,sd,message);
- }
-
- for( i = 0; i < sd->channel_count; i++ ) {
- if( sd->channels[i] == chan ) {
+ nullpo_retv(chan);
+ nullpo_retv(sd);
+ for (i = 0; i < sd->channel_count; i++) {
+ if (sd->channels[i] == chan) {
sd->channels[i] = NULL;
break;
}
}
-
- if( i < sd->channel_count ) {
+ if (i < sd->channel_count) {
unsigned char cursor = 0;
- for( i = 0; i < sd->channel_count; i++ ) {
- if( sd->channels[i] == NULL )
+ for (i = 0; i < sd->channel_count; i++) {
+ if (sd->channels[i] == NULL)
continue;
- if( cursor != i ) {
+ if (cursor != i) {
sd->channels[cursor] = sd->channels[i];
}
cursor++;
}
- if ( !(sd->channel_count = cursor) ) {
+ if (!(sd->channel_count = cursor)) {
aFree(sd->channels);
sd->channels = NULL;
}
}
-
}
-
-void channel_quit(struct map_session_data *sd)
+/**
+ * Leaves a channel.
+ *
+ * @param chan The channel to leave
+ * @param sd The character
+ */
+void channel_leave(struct channel_data *chan, struct map_session_data *sd)
{
- unsigned char i;
+ nullpo_retv(chan);
+ nullpo_retv(sd);
- for (i = 0; i < sd->channel_count; i++) {
- struct channel_data *chan = sd->channels[i];
- if (chan != NULL) {
- idb_remove(chan->users,sd->status.char_id);
+ if (!idb_remove(chan->users,sd->status.char_id))
+ return;
- if( chan == sd->gcbind )
- sd->gcbind = NULL;
+ if (chan == sd->gcbind)
+ sd->gcbind = NULL;
- if (!db_size(chan->users) && chan->type == HCS_TYPE_PRIVATE) {
- channel->delete(chan);
- } else if (!channel->config->closing && (chan->options & HCS_OPT_ANNOUNCE_JOIN)) {
- char message[60];
- sprintf(message, "#%s '%s' left",chan->name,sd->status.name);
- clif->channel_msg(chan,sd,message);
- }
+ if (!db_size(chan->users) && chan->type == HCS_TYPE_PRIVATE) {
+ channel->delete(chan);
+ } else if (!channel->config->closing && (chan->options & HCS_OPT_ANNOUNCE_JOIN)) {
+ char message[60];
+ sprintf(message, "#%s '%s' left",chan->name,sd->status.name);
+ clif->channel_msg(chan,sd,message);
+ }
+
+ channel->leave_sub(chan, sd);
+}
+
+/**
+ * Quits the channel system.
+ *
+ * Leaves all joined channels.
+ *
+ * @param sd The target character
+ */
+void channel_quit(struct map_session_data *sd)
+{
+ while (sd->channel_count > 0) {
+ // Loop downward to avoid unnecessary array compactions by channel_leave
+ struct channel_data *chan = sd->channels[sd->channel_count-1];
+ if (chan == NULL) {
+ sd->channel_count--;
+ continue;
}
- }
- sd->channel_count = 0;
- aFree(sd->channels);
- sd->channels = NULL;
+ channel->leave(chan, sd);
+ }
}
/**
@@ -807,9 +810,11 @@ void channel_defaults(void)
{
channel = &channel_s;
+ channel->db = NULL;
+ channel->config = &channel_config;
+
channel->init = do_init_channel;
channel->final = do_final_channel;
- channel->config = &channel_config;
channel->search = channel_search;
channel->create = channel_create;
@@ -824,6 +829,7 @@ void channel_defaults(void)
channel->join_sub = channel_join_sub;
channel->join = channel_join;
channel->leave = channel_leave;
+ channel->leave_sub = channel_leave_sub;
channel->quit = channel_quit;
channel->map_join = channel_map_join;
diff --git a/src/map/channel.h b/src/map/channel.h
index 39127f3b9..b518dfb8e 100644
--- a/src/map/channel.h
+++ b/src/map/channel.h
@@ -88,6 +88,8 @@ struct channel_interface {
struct channel_data *(*search) (const char *name, struct map_session_data *sd);
struct channel_data *(*create) (enum channel_types type, const char *name, unsigned char color);
+ void (*delete) (struct channel_data *chan);
+
void (*set_password) (struct channel_data *chan, const char *password);
enum channel_operation_status (*ban) (struct channel_data *chan, const struct map_session_data *ssd, struct map_session_data *tsd);
enum channel_operation_status (*unban) (struct channel_data *chan, const struct map_session_data *ssd, struct map_session_data *tsd);
@@ -96,14 +98,15 @@ struct channel_interface {
void (*send) (struct channel_data *chan, struct map_session_data *sd, const char *msg);
void (*join_sub) (struct channel_data *chan, struct map_session_data *sd, bool stealth);
enum channel_operation_status (*join) (struct channel_data *chan, struct map_session_data *sd, const char *password, bool silent);
-
void (*leave) (struct channel_data *chan, struct map_session_data *sd);
- void (*delete) (struct channel_data *chan);
- void (*map_join) (struct map_session_data *sd);
+ void (*leave_sub) (struct channel_data *chan, struct map_session_data *sd);
void (*quit) (struct map_session_data *sd);
- void (*quit_guild) (struct map_session_data *sd);
+
+ void (*map_join) (struct map_session_data *sd);
void (*guild_join) (struct guild *g1,struct guild *g2);
void (*guild_leave) (struct guild *g1,struct guild *g2);
+ void (*quit_guild) (struct map_session_data *sd);
+
void (*config_read) (void);
};
diff --git a/src/map/map.c b/src/map/map.c
index 4ce581ff2..1f893269b 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -1857,10 +1857,6 @@ int map_quit(struct map_session_data *sd) {
unit->remove_map(&sd->ed->bl,CLR_TELEPORT,ALC_MARK);
}
- if (channel->config->local && map->list[sd->bl.m].channel && idb_exists(map->list[sd->bl.m].channel->users, sd->status.char_id)) {
- channel->leave(map->list[sd->bl.m].channel,sd);
- }
-
channel->quit(sd);
unit->remove_map_pc(sd,CLR_RESPAWN);
diff --git a/src/map/pc.c b/src/map/pc.c
index a301f8ada..2013bb652 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -5043,7 +5043,7 @@ int pc_setpos(struct map_session_data* sd, unsigned short map_index, int x, int
vending->close(sd);
}
- if (channel->config->local && map->list[sd->bl.m].channel && idb_exists(map->list[sd->bl.m].channel->users, sd->status.char_id)) {
+ if (map->list[sd->bl.m].channel) {
channel->leave(map->list[sd->bl.m].channel,sd);
}
}