channel.cpp 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "channel.hpp"
  4. #include <stdlib.h>
  5. #include "../common/cbasetypes.hpp"
  6. #include "../common/conf.hpp" //libconfig
  7. #include "../common/malloc.hpp"
  8. #include "../common/nullpo.hpp"
  9. #include "../common/showmsg.hpp"
  10. #include "../common/socket.hpp" //set_eof
  11. #include "../common/strlib.hpp" //safestrncpy
  12. #include "../common/timer.hpp" // DIFF_TICK
  13. #include "battle.hpp"
  14. #include "clif.hpp" //clif_chsys_msg
  15. #include "guild.hpp"
  16. #include "map.hpp" //msg_conf
  17. #include "pc.hpp"
  18. #include "pc_groups.hpp"
  19. static DBMap* channel_db; // channels
  20. struct Channel_Config channel_config;
  21. DBMap* channel_get_db(void){ return channel_db; }
  22. /**
  23. * Create a channel
  24. * - Will then add it in the channel_db if the type is not map or ally
  25. * @param name: Channel name, can't be null
  26. * @param pass: Channel password, can be null
  27. * @param color: Display color
  28. * @param chantype: Channel type
  29. * @return NULL on failure or Channel on success
  30. */
  31. struct Channel* channel_create(struct Channel *tmp_chan) {
  32. struct Channel* channel;
  33. if (!tmp_chan->name[0])
  34. return NULL;
  35. CREATE(channel, struct Channel, 1); //will exit on fail allocation
  36. //channel->id = tmp_chan->id;
  37. channel->users = idb_alloc(DB_OPT_BASE);
  38. channel->banned = idb_alloc(static_cast<DBOptions>(DB_OPT_BASE|DB_OPT_RELEASE_DATA) );
  39. channel->opt = tmp_chan->opt;
  40. channel->type = tmp_chan->type;
  41. channel->color = tmp_chan->color;
  42. safestrncpy(channel->name, tmp_chan->name, CHAN_NAME_LENGTH); // Store channel cname without '#'
  43. safestrncpy(channel->alias, tmp_chan->alias[0] ? tmp_chan->alias : tmp_chan->name, CHAN_NAME_LENGTH);
  44. if (!tmp_chan->pass[0])
  45. channel->pass[0] = '\0';
  46. else
  47. safestrncpy(channel->pass, tmp_chan->pass, CHAN_NAME_LENGTH);
  48. channel->msg_delay = tmp_chan->msg_delay;
  49. switch (channel->type) {
  50. case CHAN_TYPE_MAP:
  51. channel->m = tmp_chan->m;
  52. break;
  53. case CHAN_TYPE_ALLY:
  54. channel->gid = tmp_chan->gid;
  55. break;
  56. case CHAN_TYPE_PRIVATE:
  57. channel->char_id = tmp_chan->char_id;
  58. default:
  59. strdb_put(channel_db, channel->name, channel);
  60. break;
  61. }
  62. if (battle_config.etc_log)
  63. ShowInfo("Create channel %s alias %s type=%d, owner=%d/%d/%d\n",channel->name,channel->alias,channel->type,channel->char_id,channel->m,channel->gid);
  64. return channel;
  65. }
  66. /**
  67. * Allocates the proper settings depending on the channel type
  68. * @param name: Channel name, can't be null
  69. * @param pass: Channel password, can be null
  70. * @param chantype: Channel type
  71. * @param owner: Owner ID
  72. * @return NULL on failure or Channel on success
  73. */
  74. struct Channel* channel_create_simple(char *name, char *pass, enum Channel_Type chantype, unsigned int owner) {
  75. struct Channel tmp_chan;
  76. memset(&tmp_chan, 0, sizeof(struct Channel));
  77. switch (chantype) {
  78. case CHAN_TYPE_ALLY:
  79. memcpy(&tmp_chan, &channel_config.ally_tmpl, sizeof(channel_config.ally_tmpl));
  80. tmp_chan.gid = (int)owner;
  81. break;
  82. case CHAN_TYPE_MAP:
  83. memcpy(&tmp_chan, &channel_config.map_tmpl, sizeof(channel_config.map_tmpl));
  84. tmp_chan.m = (uint16)owner;
  85. break;
  86. case CHAN_TYPE_PUBLIC:
  87. safestrncpy(tmp_chan.name, name+1, sizeof(tmp_chan.name));
  88. if (pass)
  89. safestrncpy(tmp_chan.pass, pass, sizeof(tmp_chan.pass));
  90. else
  91. tmp_chan.pass[0] = '\0';
  92. safestrncpy(tmp_chan.alias, name, sizeof(tmp_chan.name));
  93. tmp_chan.type = CHAN_TYPE_PUBLIC;
  94. tmp_chan.opt = CHAN_OPT_BASE;
  95. tmp_chan.msg_delay = 1000;
  96. tmp_chan.color = channel_getColor("Default");
  97. break;
  98. case CHAN_TYPE_PRIVATE:
  99. safestrncpy(tmp_chan.name, name+1, sizeof(tmp_chan.name));
  100. if (pass)
  101. safestrncpy(tmp_chan.pass, pass, sizeof(tmp_chan.pass));
  102. else
  103. tmp_chan.pass[0] = '\0';
  104. safestrncpy(tmp_chan.alias, name, sizeof(tmp_chan.name));
  105. tmp_chan.type = CHAN_TYPE_PRIVATE;
  106. tmp_chan.opt = channel_config.private_channel.opt;
  107. tmp_chan.msg_delay = channel_config.private_channel.delay;
  108. tmp_chan.color = channel_config.private_channel.color;
  109. tmp_chan.char_id = owner;
  110. break;
  111. default:
  112. return NULL;
  113. }
  114. return channel_create(&tmp_chan);
  115. }
  116. /**
  117. * Delete a channel
  118. * - Checks if there is any user in channel and make them quit
  119. * @param channel: Channel data
  120. * @param force: Forcefully remove channel
  121. * @return
  122. * 0: Success
  123. * -1: Invalid channel
  124. * -2: Can't delete now
  125. */
  126. int channel_delete(struct Channel *channel, bool force) {
  127. if(!channel)
  128. return -1;
  129. if(!force && channel->type == CHAN_TYPE_PUBLIC && runflag == MAPSERVER_ST_RUNNING) //only delete those serv stop
  130. return -2;
  131. if( db_size(channel->users)) {
  132. struct map_session_data *sd;
  133. DBIterator *iter = db_iterator(channel->users);
  134. for( sd = (struct map_session_data *)dbi_first(iter); dbi_exists(iter); sd = (struct map_session_data *)dbi_next(iter) ) { //for all users
  135. channel_clean(channel,sd,1); //make all quit
  136. }
  137. dbi_destroy(iter);
  138. }
  139. if (battle_config.etc_log)
  140. ShowInfo("Deleting channel %s alias %s type %d\n",channel->name,channel->alias,channel->type);
  141. db_destroy(channel->users);
  142. db_destroy(channel->banned);
  143. if (channel->groups)
  144. aFree(channel->groups);
  145. channel->groups = NULL;
  146. channel->group_count = 0;
  147. switch(channel->type){
  148. case CHAN_TYPE_MAP:
  149. map_getmapdata(channel->m)->channel = NULL;
  150. aFree(channel);
  151. break;
  152. case CHAN_TYPE_ALLY: {
  153. struct guild *g = guild_search(channel->gid);
  154. if(g) g->channel = NULL;
  155. aFree(channel);
  156. break;
  157. }
  158. default:
  159. strdb_remove(channel_db, channel->name);
  160. break;
  161. }
  162. return 0;
  163. }
  164. /**
  165. * Make a player join a channel
  166. * - Add player to channel user list
  167. * - Add channel to user channel list
  168. * @param channel: Channel data
  169. * @param sd: Player data
  170. * @return
  171. * 0: Success
  172. * -1: Invalid channel or player
  173. * -2: Player already in channel
  174. * -3: Player banned
  175. * -4: Reached max limit
  176. */
  177. int channel_join(struct Channel *channel, struct map_session_data *sd) {
  178. if(!channel || !sd)
  179. return -1;
  180. if(sd->state.autotrade)
  181. return 0; // fake success
  182. if(channel_haspc(channel,sd)==1)
  183. return -2;
  184. if (!pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) && !channel_pccheckgroup(channel, sd->group_id))
  185. return -2;
  186. if(channel_haspcbanned(channel,sd)==1){
  187. char output[CHAT_SIZE_MAX];
  188. sprintf(output, msg_txt(sd,1438),channel->name); //You're currently banned from the '%s' channel.
  189. clif_displaymessage(sd->fd, output);
  190. return -3;
  191. }
  192. if (channel->type == CHAN_TYPE_PRIVATE && db_size(channel->users) >= channel_config.private_channel.max_member) {
  193. char output[CHAT_SIZE_MAX];
  194. sprintf(output, msg_txt(sd,760), channel->name, channel_config.private_channel.max_member); // You cannot join channel '%s'. Limit of %d has been met.
  195. clif_displaymessage(sd->fd, output);
  196. return -4;
  197. }
  198. RECREATE(sd->channels, struct Channel *, ++sd->channel_count);
  199. sd->channels[ sd->channel_count - 1 ] = channel;
  200. idb_put(channel->users, sd->status.char_id, sd);
  201. RECREATE(sd->channel_tick, t_tick, sd->channel_count);
  202. sd->channel_tick[sd->channel_count-1] = 0;
  203. if( sd->stealth ) {
  204. sd->stealth = false;
  205. } else if( channel->opt & CHAN_OPT_ANNOUNCE_JOIN ) {
  206. char output[CHAT_SIZE_MAX];
  207. safesnprintf(output, CHAT_SIZE_MAX, msg_txt(sd,761), channel->alias, sd->status.name); // %s %s has joined.
  208. clif_channel_msg(channel,output,channel->color);
  209. }
  210. /* someone is cheating, we kindly disconnect the bastard */
  211. if( sd->channel_count > 200 ) {
  212. set_eof(sd->fd);
  213. }
  214. return 0;
  215. }
  216. /**
  217. * Make a player join the map channel
  218. * - Create the map_channel if it does not exist
  219. * @param sd: Player data
  220. * @return
  221. * -1: Invalid player
  222. * -2: Player already in channel (channel_join)
  223. * -3: Player banned (channel_join)
  224. */
  225. int channel_mjoin(struct map_session_data *sd) {
  226. char mout[60];
  227. if(!sd) return -1;
  228. struct map_data *mapdata = map_getmapdata(sd->bl.m);
  229. if( !mapdata->channel ) {
  230. mapdata->channel = channel_create_simple(NULL,NULL,CHAN_TYPE_MAP,sd->bl.m);
  231. }
  232. if( mapdata->channel->opt & CHAN_OPT_ANNOUNCE_SELF ) {
  233. sprintf(mout, msg_txt(sd,1435),mapdata->channel->name,mapdata->name); // You're now in the '#%s' channel for '%s'.
  234. clif_messagecolor(&sd->bl, color_table[COLOR_LIGHT_GREEN], mout, false, SELF);
  235. }
  236. return channel_join(mapdata->channel,sd);
  237. }
  238. /**
  239. * Make all ally members of a guild join the guild channel
  240. * - They only join if they are in their own guild channel (if not they probably left it)
  241. * @param g: Guild data
  242. * @return
  243. * 0: Success
  244. * -1: Invalid guild or no channel for guild
  245. */
  246. int channel_ajoin(struct guild *g){
  247. int i, j;
  248. struct map_session_data *pl_sd;
  249. if(!g || !g->channel) return -1;
  250. for (i = 0; i < MAX_GUILDALLIANCE; i++){
  251. struct guild *ag; //allied guld
  252. struct guild_alliance *ga = &g->alliance[i]; //guild alliance
  253. if(ga->guild_id && (ga->opposition==0) && (ag=guild_search(ga->guild_id))){
  254. for (j = 0; j < ag->max_member; j++){ //load all guildmember
  255. pl_sd = ag->member[j].sd;
  256. if(channel_haspc(ag->channel,pl_sd)==1) //only if they are in their own guildchan
  257. channel_join(g->channel,pl_sd);
  258. }
  259. }
  260. }
  261. return 0;
  262. }
  263. /**
  264. * Make a player join the guild channel
  265. * - Create a guild channel if it does not exist
  266. * @param sd: Player data
  267. * @param flag: Join type (1 - Guild chat, 2 - Ally chat)
  268. * @return
  269. * 0: Success
  270. * -1: Invalid player
  271. * -2: Player has no guild attached
  272. */
  273. int channel_gjoin(struct map_session_data *sd, int flag){
  274. struct Channel *channel;
  275. struct guild *g;
  276. if(!sd || sd->state.autotrade) return -1;
  277. g = sd->guild;
  278. if(!g) return -2;
  279. channel = g->channel;
  280. if(!channel){
  281. channel = channel_create_simple(NULL,NULL,CHAN_TYPE_ALLY,g->guild_id);
  282. g->channel = channel;
  283. channel_ajoin(g);
  284. }
  285. if(flag&1) {
  286. channel_join(channel,sd); //join our guild chat
  287. }
  288. if(flag&2){
  289. int i;
  290. for (i = 0; i < MAX_GUILDALLIANCE; i++){
  291. struct guild *ag; //allied guld
  292. struct guild_alliance *ga = &g->alliance[i]; //guild alliance
  293. if(ga->guild_id && (ga->opposition==0) && (ag=guild_search(ga->guild_id)) ) //only join allies
  294. channel_join(ag->channel,sd);
  295. }
  296. }
  297. return 0;
  298. }
  299. /**
  300. * Make player leave the channel and cleanup association
  301. * - If no one remains in the chat, delete it
  302. * @param channel: Channel data
  303. * @param sd: Player data
  304. * @param flag: Called from deletion process, do not recall delete
  305. * @return
  306. * 0: Success
  307. * -1: Invalid player or channel
  308. */
  309. int channel_clean(struct Channel *channel, struct map_session_data *sd, int flag) {
  310. unsigned char i;
  311. if(!channel || !sd)
  312. return -1;
  313. if( channel == sd->gcbind )
  314. sd->gcbind = NULL;
  315. ARR_FIND(0, sd->channel_count, i, sd->channels[i] == channel);
  316. if( i < sd->channel_count ) {
  317. unsigned char cursor = i;
  318. sd->channels[i] = NULL;
  319. sd->channel_tick[i] = 0;
  320. for(; i < sd->channel_count; i++ ) { //slice move list down
  321. if( sd->channels[i] == NULL )
  322. continue;
  323. if(i != cursor) {
  324. sd->channels[cursor] = sd->channels[i];
  325. sd->channel_tick[cursor] = sd->channel_tick[i];
  326. }
  327. cursor++;
  328. }
  329. if ( !(sd->channel_count = cursor) ) { //if in no more chan delete db
  330. aFree(sd->channels);
  331. aFree(sd->channel_tick);
  332. sd->channels = NULL;
  333. sd->channel_tick = NULL;
  334. }
  335. }
  336. idb_remove(channel->users,sd->status.char_id); //remove user for channel user list
  337. //auto delete when no more user in
  338. if( !db_size(channel->users) && !(flag&1) )
  339. channel_delete(channel,false);
  340. return 0;
  341. }
  342. /**
  343. * Make a player leave a type of channel
  344. * @param sd: Player data
  345. * @param type: Quit type (1 - Quit guild channel, 2 - Quit ally channel, 4 - Quit map channel, 8 - Quit all users in channel)
  346. * @return
  347. * 0: Success
  348. * -1: Invalid player
  349. */
  350. int channel_pcquit(struct map_session_data *sd, int type){
  351. int i;
  352. //On closing state we could have clean all chan by sd but pcquit is more used to free unit when
  353. //he quit a map_server, not call in map_quit cause we need to cleanup when we switch map-server as well
  354. if(!sd) return -1;
  355. // Leave all chat channels.
  356. if(type&(1|2) && channel_config.ally_tmpl.name[0] && sd->guild){ //quit guild and ally chan
  357. struct guild *g = sd->guild;
  358. if(type&1 && channel_haspc(g->channel,sd)==1){
  359. channel_clean(g->channel,sd,0); //leave guild chan
  360. }
  361. if(type&2){
  362. for (i = 0; i < MAX_GUILDALLIANCE; i++) { //leave all alliance chan
  363. struct guild *ag; //allied guild
  364. if( g->alliance[i].guild_id && (ag = guild_search(g->alliance[i].guild_id) ) ) {
  365. if(channel_haspc(ag->channel,sd) == 1)
  366. channel_clean(ag->channel,sd,0);
  367. break;
  368. }
  369. }
  370. }
  371. }
  372. struct map_data *mapdata = map_getmapdata(sd->bl.m);
  373. if(type&4 && channel_config.map_tmpl.name[0] && channel_haspc(mapdata->channel,sd)==1){ //quit map chan
  374. channel_clean(mapdata->channel,sd,0);
  375. }
  376. if(type&8 && sd->channel_count ) { //quit all chan
  377. uint8 count = sd->channel_count;
  378. for( i = count-1; i >= 0; i--) { //going backward to avoid shifting
  379. channel_clean(sd->channels[i],sd,0);
  380. }
  381. }
  382. return 0;
  383. }
  384. /**
  385. * Format message from player to send to the channel
  386. * - Also truncate extra characters if message is too long
  387. * @param channel: Channel data
  388. * @param sd: Player data
  389. * @param msg: Message to send
  390. * @return
  391. * 0: Success
  392. * -1: Invalid player, channel, or message
  393. * -2: Delay message from last message
  394. */
  395. int channel_send(struct Channel *channel, struct map_session_data *sd, const char *msg) {
  396. int idx = 0;
  397. if(!channel || !sd || !msg || (idx = channel_pc_haschan(sd, channel)) < 0)
  398. return -1;
  399. if(!pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) && channel->msg_delay != 0 && DIFF_TICK(sd->channel_tick[idx] + channel->msg_delay, gettick()) > 0) {
  400. clif_messagecolor(&sd->bl,color_table[COLOR_RED],msg_txt(sd,1455),false,SELF); //You're talking too fast!
  401. return -2;
  402. }
  403. else {
  404. char output[CHAT_SIZE_MAX];
  405. unsigned long color = channel->color;
  406. if((channel->opt&CHAN_OPT_COLOR_OVERRIDE) && sd->fontcolor && sd->fontcolor < channel_config.colors_count && channel_config.colors[sd->fontcolor])
  407. color = channel_config.colors[sd->fontcolor];
  408. safesnprintf(output, CHAT_SIZE_MAX, "%s %s : %s", channel->alias, sd->status.name, msg);
  409. clif_channel_msg(channel,output,color);
  410. sd->channel_tick[idx] = gettick();
  411. }
  412. return 0;
  413. }
  414. /**
  415. * Check parameters for channel creation
  416. * @param chname: Channel name
  417. * @param chpass: Channel password
  418. * @param type: Check types (1 - Check name # + length, 2 - Check if channel already exists, 4 - Check password length)
  419. * @return
  420. * 0: Success
  421. * -1: Bad channel name
  422. * -2: bad channel name length
  423. * -3: Password given too long
  424. * -4: Channel already exists
  425. */
  426. int channel_chk(char *chname, char *chpass, int type){
  427. if(type&1){ //check name
  428. if( chname[0] != '#' )
  429. return -1;
  430. if ( strlen(chname) < 3 || strlen(chname) > CHAN_NAME_LENGTH )
  431. return -2;
  432. if( (type&2) && (
  433. strcmpi(chname + 1,channel_config.map_tmpl.name) == 0
  434. || strcmpi(chname + 1,channel_config.ally_tmpl.name) == 0
  435. || strdb_exists(channel_db, chname + 1) )
  436. ) {
  437. return -4;
  438. }
  439. }
  440. if (type&4 && (chpass[0] != '\0' && strlen(chpass) > CHAN_NAME_LENGTH ) ) {
  441. return -3;
  442. }
  443. return 0;
  444. }
  445. /**
  446. * Lookup a channel name
  447. * @param chname: Channel name
  448. * @param sd: Player data, can be NULL, used to solve #map and #ally cases
  449. * @param flag: Lookup types (1 - Create channel if it does not exist (map or ally only), 2 - Join the channel if not joined yet (map or ally only))
  450. * @return NULL on channel not found or channel data on success
  451. */
  452. struct Channel* channel_name2channel(char *chname, struct map_session_data *sd, int flag){
  453. if(channel_chk(chname, NULL, 1))
  454. return NULL;
  455. struct map_data *mapdata = sd ? map_getmapdata(sd->bl.m) : NULL;
  456. if(sd && strcmpi(chname + 1,channel_config.map_tmpl.name) == 0){
  457. if(flag&1 && !mapdata->channel)
  458. mapdata->channel = channel_create_simple(NULL,NULL,CHAN_TYPE_MAP,sd->bl.m);
  459. if(flag&2 && channel_pc_haschan(sd,mapdata->channel) < 1)
  460. channel_mjoin(sd);
  461. return mapdata->channel;
  462. }
  463. else if(sd && (strcmpi(chname + 1,channel_config.ally_tmpl.name) == 0) && sd->guild){
  464. if(flag&1 && !sd->guild->channel)
  465. sd->guild->channel = channel_create_simple(NULL,NULL,CHAN_TYPE_ALLY,sd->guild->guild_id);
  466. if(flag&2 && channel_pc_haschan(sd,mapdata->channel) < 1)
  467. channel_gjoin(sd,3);
  468. return sd->guild->channel;
  469. }
  470. else
  471. return (struct Channel*) strdb_get(channel_db, chname + 1);
  472. }
  473. /**
  474. * Check if player is in a channel
  475. * @param channel: Channel data
  476. * @param sd: Player data
  477. * @return
  478. * -1: Invalid player or channel
  479. * 0: Player not found or not banned
  480. * 1: Player is in channel
  481. */
  482. int channel_haspc(struct Channel *channel,struct map_session_data *sd){
  483. if(!channel || !sd) return -1;
  484. return (idb_exists(channel->users, sd->status.char_id))?1:0;
  485. }
  486. /**
  487. * Check if player is banned from channel
  488. * @return
  489. * -1: Invalid player or channel
  490. * 0: Player not found or not banned
  491. * 1: Player is banned
  492. */
  493. int channel_haspcbanned(struct Channel *channel,struct map_session_data *sd){
  494. if(!channel || !sd) return -1;
  495. return (idb_exists(channel->banned, sd->status.char_id))?1:0;
  496. }
  497. /**
  498. * Check if player has channel in their channel list
  499. * @param sd: Player data
  500. * @param channel: Channel data
  501. * @return
  502. * -1: Invalid channel or player
  503. * -2: Player not found or not in channel
  504. * x > 0: has_channel at index x
  505. */
  506. int channel_pc_haschan(struct map_session_data *sd, struct Channel *channel){
  507. int k;
  508. if(!channel || !sd) return -1; //channel or player doesn't exist
  509. ARR_FIND(0, sd->channel_count, k, strcmpi(channel->name,sd->channels[k]->name) == 0);
  510. if( k >= sd->channel_count ) return -2;
  511. return k;
  512. }
  513. /**
  514. * Display some information to users in channel
  515. * @param sd: Player data
  516. * @param options:
  517. * colors: Display available colors for channel system
  518. * mine: List of players in channel and number of users
  519. * void: List of public channel and map and guild and number of users
  520. * @return 0 on success or -1 on failure
  521. */
  522. int channel_display_list(struct map_session_data *sd, const char *options){
  523. if(!sd || !options)
  524. return -1;
  525. //display availaible colors
  526. if( options[0] != '\0' && strcmpi(options,"colors") == 0 ) {
  527. char msg[40];
  528. unsigned char k;
  529. clif_displaymessage(sd->fd, msg_txt(sd,1444)); // ---- Available Colors ----
  530. for( k = 0; k < channel_config.colors_count; k++ ) {
  531. if (channel_config.colors[k]) {
  532. sprintf(msg, msg_txt(sd,1445),channel_config.colors_name[k]);// - '%s'
  533. clif_messagecolor(&sd->bl,channel_config.colors[k],msg,false,SELF);
  534. }
  535. }
  536. }
  537. else if( options[0] != '\0' && strcmpi(options,"mine") == 0 ) { //display chan I'm into
  538. clif_displaymessage(sd->fd, msg_txt(sd,1475)); // ---- My Channels ----
  539. if(!sd->channel_count)
  540. clif_displaymessage(sd->fd, msg_txt(sd,1476)); // You have not joined any channels.
  541. else {
  542. unsigned char k;
  543. for(k = 0; k < sd->channel_count; k++) {
  544. char output[CHAT_SIZE_MAX];
  545. struct Channel *channel;
  546. if (!(channel = sd->channels[k]))
  547. continue;
  548. sprintf(output, msg_txt(sd,1409), channel->name, db_size(channel->users));// - #%s (%d users)
  549. clif_displaymessage(sd->fd, output);
  550. }
  551. }
  552. }
  553. else { //display public chanels
  554. DBIterator *iter;
  555. bool has_perm = pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ? true : false;
  556. struct Channel *channel;
  557. char output[CHAT_SIZE_MAX];
  558. struct map_data *mapdata = map_getmapdata(sd->bl.m);
  559. clif_displaymessage(sd->fd, msg_txt(sd,1410)); // ---- Public Channels ----
  560. if( channel_config.map_tmpl.name[0] && mapdata->channel ) {
  561. sprintf(output, msg_txt(sd,1409), mapdata->channel->name, db_size(mapdata->channel->users));// - #%s (%d users)
  562. clif_displaymessage(sd->fd, output);
  563. }
  564. if( channel_config.ally_tmpl.name[0] && sd->status.guild_id ) {
  565. struct guild *g = sd->guild;
  566. if (g && g->channel) {
  567. sprintf(output, msg_txt(sd,1409), g->channel->name, db_size(((struct Channel *)g->channel)->users));// - #%s (%d users)
  568. clif_displaymessage(sd->fd, output);
  569. }
  570. }
  571. iter = db_iterator(channel_db);
  572. for(channel = (struct Channel *)dbi_first(iter); dbi_exists(iter); channel = (struct Channel *)dbi_next(iter)) {
  573. if (!has_perm && !channel_pccheckgroup(channel, sd->group_id))
  574. continue;
  575. if( has_perm || channel->type == CHAN_TYPE_PUBLIC ) {
  576. sprintf(output, msg_txt(sd,1409), channel->name, db_size(channel->users));// - #%s (%d users)
  577. clif_displaymessage(sd->fd, output);
  578. }
  579. }
  580. dbi_destroy(iter);
  581. }
  582. return 0;
  583. }
  584. /**
  585. * A player is attempting to create a channel
  586. * @param sd: Player data
  587. * @param chname: Channel name
  588. * @param chpass: Channel password
  589. * @return 0 on success or -1 on failure
  590. */
  591. int channel_pccreate(struct map_session_data *sd, char *chname, char *chpass){
  592. char output[CHAT_SIZE_MAX];
  593. int8 res;
  594. if(!sd || !chname)
  595. return 0;
  596. res = channel_chk(chname,chpass,7);
  597. if(res==0){ //success
  598. struct Channel *channel = channel_create_simple(chname,chpass,CHAN_TYPE_PRIVATE,sd->status.char_id);
  599. channel_join(channel,sd);
  600. if( ( channel->opt & CHAN_OPT_ANNOUNCE_SELF ) ) {
  601. sprintf(output, msg_txt(sd,1403),chname); // You're now in the '%s' channel.
  602. clif_displaymessage(sd->fd, output);
  603. }
  604. } else { //failure display cause
  605. switch(res){
  606. case -1: sprintf(output, msg_txt(sd,1405), CHAN_NAME_LENGTH); break;// Channel name must start with '#'.
  607. case -2: sprintf(output, msg_txt(sd,1406), CHAN_NAME_LENGTH); break;// Channel length must be between 3 and %d.
  608. case -3: sprintf(output, msg_txt(sd,1436), CHAN_NAME_LENGTH); break;// Channel password can't be over %d characters.
  609. case -4: sprintf(output, msg_txt(sd,1407), chname);// Channel '%s' is not available.
  610. }
  611. clif_displaymessage(sd->fd, output);
  612. return -1;
  613. }
  614. return 0;
  615. }
  616. /**
  617. * A player is attempting to delete a channel
  618. * @param sd: Player data
  619. * @param chname: Channel name
  620. * @return 0 on success or -1 on failure
  621. */
  622. int channel_pcdelete(struct map_session_data *sd, char *chname){
  623. struct Channel *channel;
  624. char output[CHAT_SIZE_MAX];
  625. if(!sd || !chname) return 0;
  626. if( channel_chk(chname,NULL,1) ) {
  627. clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'.
  628. return -1;
  629. }
  630. channel = channel_name2channel(chname,sd,0);
  631. if(channel_pc_haschan(sd,channel)<0){
  632. sprintf(output, msg_txt(sd,1425),chname);// You're not part of the '%s' channel.
  633. clif_displaymessage(sd->fd, output);
  634. return -2; //channel doesn't exist or player don't have it
  635. }
  636. channel_delete(channel,false);
  637. sprintf(output, msg_txt(sd,1448),chname); // Channel '%s' deleted.
  638. clif_displaymessage(sd->fd, output);
  639. return 0;
  640. }
  641. /**
  642. * A player is attempting to leave a channel
  643. * @param sd: Player data
  644. * @param chname: Channel name
  645. * @return 0 on success or -1 on failure
  646. */
  647. int channel_pcleave(struct map_session_data *sd, char *chname){
  648. struct Channel *channel;
  649. char output[CHAT_SIZE_MAX];
  650. if(!sd || !chname)
  651. return 0;
  652. if( channel_chk(chname,NULL,1) ) {
  653. clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'.
  654. return -1;
  655. }
  656. channel = channel_name2channel(chname,sd,0);
  657. if(channel_pc_haschan(sd,channel)<0){
  658. sprintf(output, msg_txt(sd,1425),chname);// You're not part of the '%s' channel.
  659. clif_displaymessage(sd->fd, output);
  660. return -2; //channel doesn't exist or player don't have it
  661. }
  662. if (!(channel->opt&CHAN_OPT_CAN_LEAVE)) {
  663. sprintf(output, msg_txt(sd,762), chname); // You cannot leave channel '%s'.
  664. clif_displaymessage(sd->fd, output);
  665. return -1;
  666. }
  667. if( !channel_config.closing && (channel->opt & CHAN_OPT_ANNOUNCE_LEAVE) ) {
  668. safesnprintf(output, CHAT_SIZE_MAX, msg_txt(sd,763), channel->alias, sd->status.name); // %s %s left.
  669. clif_channel_msg(channel,output,channel->color);
  670. }
  671. switch(channel->type){
  672. case CHAN_TYPE_ALLY: channel_pcquit(sd,3); break;
  673. case CHAN_TYPE_MAP: channel_pcquit(sd,4); break;
  674. default: //private and public atm
  675. channel_clean(channel,sd,0);
  676. }
  677. sprintf(output, msg_txt(sd,1426),chname); // You've left the '%s' channel.
  678. clif_displaymessage(sd->fd, output);
  679. return 0;
  680. }
  681. /**
  682. * A player is attempting to join a channel
  683. * @param sd: Player data
  684. * @param chname: Channel name
  685. * @param pass: Channel password
  686. * @return 0 on success or -1 on failure
  687. */
  688. int channel_pcjoin(struct map_session_data *sd, char *chname, char *pass){
  689. struct Channel *channel;
  690. char output[CHAT_SIZE_MAX];
  691. if(!sd || !chname)
  692. return 0;
  693. if( channel_chk(chname,NULL,1) ) {
  694. clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'.
  695. return -1;
  696. }
  697. channel = channel_name2channel(chname,sd,1);
  698. if(channel){
  699. if (!pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) && !channel_pccheckgroup(channel, sd->group_id)) {
  700. sprintf(output, msg_txt(sd,1407), chname); // Channel '%s' is not available.
  701. clif_displaymessage(sd->fd, output);
  702. return -1;
  703. }
  704. if(channel_haspc(channel,sd)==1) {
  705. sprintf(output, msg_txt(sd,1434),chname); // You're already in the '%s' channel.
  706. clif_displaymessage(sd->fd, output);
  707. return -1;
  708. }
  709. else if( channel->pass[0] != '\0') { //chan has a pass
  710. if(strcmp(channel->pass,pass) != 0){ //wrong pass entry
  711. if( pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) {
  712. sd->stealth = true;
  713. } else {
  714. sprintf(output, msg_txt(sd,1401),chname,"@join"); // Channel '%s' is password-protected (usage: %s <#channel_name> <password>).
  715. clif_displaymessage(sd->fd, output);
  716. return -1;
  717. }
  718. }
  719. }
  720. }
  721. else {
  722. sprintf(output, msg_txt(sd,1400),chname,"@join"); // Unknown channel '%s' (usage: %s <#channel_name>).
  723. clif_displaymessage(sd->fd, output);
  724. return -1;
  725. }
  726. switch(channel->type){
  727. case CHAN_TYPE_ALLY: channel_gjoin(sd,3); break;
  728. case CHAN_TYPE_MAP: channel_mjoin(sd); break;
  729. default: //private and public atm
  730. if (channel_join(channel,sd) != 0)
  731. return -1;
  732. }
  733. if( ( channel->opt & CHAN_OPT_ANNOUNCE_SELF ) ) {
  734. sprintf(output, msg_txt(sd,1403),chname); // You're now in the '%s' channel.
  735. clif_displaymessage(sd->fd, output);
  736. }
  737. return 0;
  738. }
  739. /**
  740. * A player is attempting to change the channel color
  741. * @param sd: Player data
  742. * @param chname: Channel name
  743. * @param color: New color
  744. * @return 0 on success or -1 on failure
  745. */
  746. int channel_pccolor(struct map_session_data *sd, char *chname, char *color){
  747. struct Channel *channel;
  748. char output[CHAT_SIZE_MAX];
  749. int k;
  750. if(!sd)
  751. return 0;
  752. if( channel_chk(chname,NULL,1) ) {
  753. clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'.
  754. return -1;
  755. }
  756. channel = channel_name2channel(chname,sd,0);
  757. if( !channel ) {
  758. sprintf(output, msg_txt(sd,1407), chname);// Channel '%s' is not available.
  759. clif_displaymessage(sd->fd, output);
  760. return -1;
  761. }
  762. if( !pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) {
  763. if (channel->char_id != sd->status.char_id) {
  764. sprintf(output, msg_txt(sd,1412), chname);// You're not the owner of channel '%s'.
  765. clif_displaymessage(sd->fd, output);
  766. return -1;
  767. }
  768. else if (!(channel->opt&CHAN_OPT_COLOR_OVERRIDE)) {
  769. sprintf(output, msg_txt(sd,764), chname); // You cannot change the color for channel '%s'.
  770. clif_displaymessage(sd->fd, output);
  771. return -1;
  772. }
  773. }
  774. ARR_FIND(0,channel_config.colors_count,k,( strcmpi(color,channel_config.colors_name[k]) == 0 ) );
  775. if( k >= channel_config.colors_count ) {
  776. sprintf(output, msg_txt(sd,1411), color);// Unknown color '%s'.
  777. clif_displaymessage(sd->fd, output);
  778. return -1;
  779. }
  780. channel->color = channel_config.colors[k];
  781. sprintf(output, msg_txt(sd,1413),chname,channel_config.colors_name[k]);// '%s' channel color updated to '%s'.
  782. clif_displaymessage(sd->fd, output);
  783. return 0;
  784. }
  785. /**
  786. * A player is attempting to bind
  787. * - Makes default message output display to the channel
  788. * @param sd: Player data
  789. * @param chname: Channel name
  790. * @return 0 on success, -1 on incorrect channel name, or -2 channel doesn't exist or player didn't join
  791. */
  792. int channel_pcbind(struct map_session_data *sd, char *chname){
  793. struct Channel *channel;
  794. char output[CHAT_SIZE_MAX];
  795. if(!sd)
  796. return 0;
  797. if( channel_chk(chname,NULL,1) ) {
  798. clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'.
  799. return -1;
  800. }
  801. channel = channel_name2channel(chname,sd,0);
  802. if(channel_pc_haschan(sd,channel)<0){
  803. sprintf(output, msg_txt(sd,1425),chname);// You're not part of the '%s' channel.
  804. clif_displaymessage(sd->fd, output);
  805. return -2; //channel doesn't exist or player don't have it
  806. }
  807. sd->gcbind = channel;
  808. sprintf(output, msg_txt(sd,1431),chname); // Your global chat is now binded to the '%s' channel.
  809. clif_displaymessage(sd->fd, output);
  810. return 0;
  811. }
  812. /**
  813. * A player is attempting to unbind
  814. * @param sd: Player data
  815. * @return 0 on success or -1 on failure
  816. */
  817. int channel_pcunbind(struct map_session_data *sd){
  818. char output[CHAT_SIZE_MAX];
  819. if(!sd)
  820. return 0;
  821. if( sd->gcbind == NULL ) {
  822. clif_displaymessage(sd->fd, msg_txt(sd,1432));// Your global chat is not binded to any channel.
  823. return -1;
  824. }
  825. sprintf(output, msg_txt(sd,1433),sd->gcbind->name); // Your global chat is now unbinded from the '#%s' channel.
  826. clif_displaymessage(sd->fd, output);
  827. sd->gcbind = NULL;
  828. return 0;
  829. }
  830. /**
  831. * A player is attempting to modify the banlist
  832. * @param sd: Player data
  833. * @param chname: Channel name
  834. * @param pname: Player to ban or unban
  835. * @param flag: Ban options (0 - Ban, 1 - Unban, 2 - Unban all, 3 - Ban list)
  836. * @return 0 on success or -1 on failure
  837. */
  838. int channel_pcban(struct map_session_data *sd, char *chname, char *pname, int flag){
  839. struct Channel *channel;
  840. char output[CHAT_SIZE_MAX];
  841. struct map_session_data *tsd = map_nick2sd(pname,false);
  842. if( channel_chk(chname,NULL,1) ) {
  843. clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'.
  844. return -1;
  845. }
  846. channel = channel_name2channel(chname,sd,0);
  847. if( !channel ) {
  848. sprintf(output, msg_txt(sd,1407), chname);// Channel '%s' is not available.
  849. clif_displaymessage(sd->fd, output);
  850. return -1;
  851. }
  852. if( !pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) {
  853. if (channel->char_id != sd->status.char_id) {
  854. sprintf(output, msg_txt(sd,1412), chname);// You're not the owner of channel '%s'.
  855. clif_displaymessage(sd->fd, output);
  856. return -1;
  857. } else if (!channel_config.private_channel.ban) {
  858. sprintf(output, msg_txt(sd,765), chname); // You're not allowed to ban a player.
  859. clif_displaymessage(sd->fd, output);
  860. return -1;
  861. }
  862. }
  863. if(flag != 2 && flag != 3){
  864. char banned;
  865. if(!tsd || pc_has_permission(tsd, PC_PERM_CHANNEL_ADMIN) ) {
  866. sprintf(output, msg_txt(sd,1464), pname);// Ban failed for player '%s'.
  867. clif_displaymessage(sd->fd, output);
  868. return -1;
  869. }
  870. banned = channel_haspcbanned(channel,tsd);
  871. if(!flag && banned==1) {
  872. sprintf(output, msg_txt(sd,1465), tsd->status.name);// Player '%s' is already banned from this channel.
  873. clif_displaymessage(sd->fd, output);
  874. return -1;
  875. }
  876. else if(flag==1 && banned==0) {
  877. sprintf(output, msg_txt(sd,1440), tsd->status.name);// Player '%s' is not banned from this channel.
  878. clif_displaymessage(sd->fd, output);
  879. return -1;
  880. }
  881. }
  882. else {
  883. if( !db_size(channel->banned) ) {
  884. sprintf(output, msg_txt(sd,1439), chname);// Channel '%s' contains no banned players.
  885. clif_displaymessage(sd->fd, output);
  886. return 0;
  887. }
  888. }
  889. //let properly alter the list now
  890. switch(flag){
  891. case 0: {
  892. struct chan_banentry *cbe;
  893. if (!tsd)
  894. return -1;
  895. CREATE(cbe, struct chan_banentry, 1);
  896. cbe->char_id = tsd->status.char_id;
  897. strcpy(cbe->char_name,tsd->status.name);
  898. idb_put(channel->banned, tsd->status.char_id, cbe);
  899. channel_clean(channel,tsd,0);
  900. sprintf(output, msg_txt(sd,1437),tsd->status.name,chname); // Player '%s' is banned from the '%s' channel.
  901. break;
  902. }
  903. case 1:
  904. if (!tsd)
  905. return -1;
  906. idb_remove(channel->banned, tsd->status.char_id);
  907. sprintf(output, msg_txt(sd,1441),tsd->status.name,chname); // Player '%s' is unbanned from the '%s' channel.
  908. break;
  909. case 2:
  910. db_clear(channel->banned);
  911. sprintf(output, msg_txt(sd,1442),chname); // Cleared all bans from the '%s' channel.
  912. break;
  913. case 3: {
  914. DBIterator *iter = db_iterator(channel->banned);
  915. struct chan_banentry *cbe;
  916. sprintf(output, msg_txt(sd,1443), channel->name);// ---- '#%s' Ban List:
  917. clif_displaymessage(sd->fd, output);
  918. for( cbe = (struct chan_banentry *)dbi_first(iter); dbi_exists(iter); cbe = (struct chan_banentry *)dbi_next(iter) ) { //for all users
  919. if (cbe->char_name[0])
  920. sprintf(output, "%d: %s",cbe->char_id,cbe->char_name);
  921. else
  922. sprintf(output, "%d: ****",cbe->char_id);
  923. clif_displaymessage(sd->fd, output);
  924. }
  925. dbi_destroy(iter);
  926. }
  927. return 0;
  928. }
  929. clif_displaymessage(sd->fd, output);
  930. return 0;
  931. }
  932. /**
  933. * A player is attemting to kick a player
  934. * @param sd: Player data
  935. * @param chname: Channel name
  936. * @param pname: Player name to kick
  937. * @return 0 on success or -1 on failure
  938. */
  939. int channel_pckick(struct map_session_data *sd, char *chname, char *pname) {
  940. struct Channel *channel;
  941. char output[CHAT_SIZE_MAX];
  942. struct map_session_data *tsd = map_nick2sd(pname,false);
  943. if( channel_chk(chname,NULL,1) ) {
  944. clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'.
  945. return -1;
  946. }
  947. channel = channel_name2channel(chname,sd,0);
  948. if( !channel ) {
  949. sprintf(output, msg_txt(sd,1407), chname);// Channel '%s' is not available.
  950. clif_displaymessage(sd->fd, output);
  951. return -1;
  952. }
  953. if (!tsd) {
  954. clif_displaymessage(sd->fd, msg_txt(sd,3));
  955. return -1;
  956. }
  957. if( !pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) {
  958. if (channel->char_id != sd->status.char_id) {
  959. sprintf(output, msg_txt(sd,1412), chname);// You're not the owner of channel '%s'.
  960. clif_displaymessage(sd->fd, output);
  961. } else if (!channel_config.private_channel.kick) {
  962. sprintf(output, msg_txt(sd,766), chname); // You cannot kick a player from channel '%s'.
  963. clif_displaymessage(sd->fd, output);
  964. }
  965. return -1;
  966. }
  967. if (channel_pc_haschan(sd, channel) < 0) {
  968. sprintf(output, msg_txt(sd,1425), chname); // You're not part of the '%s' channel.
  969. clif_displaymessage(sd->fd, output);
  970. return -1;
  971. }
  972. if (channel->char_id == sd->status.char_id) {
  973. clif_displaymessage(sd->fd, msg_txt(sd, 767)); // You're not allowed to kick a player.
  974. return -1;
  975. }
  976. if( !channel_config.closing && (channel->opt & CHAN_OPT_ANNOUNCE_LEAVE) ) {
  977. safesnprintf(output, CHAT_SIZE_MAX, msg_txt(sd,768), channel->alias, tsd->status.name); // %s %s has been kicked.
  978. clif_channel_msg(channel,output,channel->color);
  979. }
  980. switch(channel->type){
  981. case CHAN_TYPE_ALLY: channel_pcquit(tsd,3); break;
  982. case CHAN_TYPE_MAP: channel_pcquit(tsd,4); break;
  983. default: //private and public atm
  984. channel_clean(channel,tsd,0);
  985. }
  986. return 1;
  987. }
  988. /**
  989. * A player is attempting to set an option on the channel
  990. * @param sd: Player data
  991. * @param chname: Channel name
  992. * @param option: Option to change
  993. * @param val: Option value
  994. * @return 0 on success or -1 on failure
  995. */
  996. int channel_pcsetopt(struct map_session_data *sd, char *chname, const char *option, const char *val){
  997. struct Channel *channel;
  998. char output[CHAT_SIZE_MAX];
  999. int k, s = 0, opt;
  1000. const char* opt_str[] = {
  1001. "None",
  1002. "SelfAnnounce",
  1003. "JoinAnnounce",
  1004. "LeaveAnnounce",
  1005. "MessageDelay",
  1006. "ColorOverride",
  1007. "CanChat",
  1008. "CanLeave",
  1009. "Autojoin",
  1010. };
  1011. if( channel_chk(chname,NULL,1) ) {
  1012. clif_displaymessage(sd->fd, msg_txt(sd,1405));// Channel name must start with '#'.
  1013. return -1;
  1014. }
  1015. if (!sd)
  1016. return - 1;
  1017. channel = channel_name2channel(chname,sd,0);
  1018. if( !channel ) {
  1019. sprintf(output, msg_txt(sd,1407), chname);// Channel '%s' is not available.
  1020. clif_displaymessage(sd->fd, output);
  1021. return -1;
  1022. }
  1023. if( sd && channel->char_id != sd->status.char_id && !pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) {
  1024. sprintf(output, msg_txt(sd,1412), chname);// You're not the owner of channel '%s'.
  1025. clif_displaymessage(sd->fd, output);
  1026. return -1;
  1027. }
  1028. s = ARRAYLENGTH(opt_str);
  1029. ARR_FIND(1,s,k,( strncmpi(option,opt_str[k],3) == 0 )); //we only cmp 3 letter atm
  1030. if(!option || option[0] == '\0' || k >= s ) {
  1031. sprintf(output, msg_txt(sd,1447), option);// Unknown channel option '%s'.
  1032. clif_displaymessage(sd->fd, output);
  1033. clif_displaymessage(sd->fd, msg_txt(sd,1414));// ---- Available options:
  1034. for( k = 1; k < s; k++ ) {
  1035. sprintf(output, msg_txt(sd,1445), opt_str[k]);// - '%s'
  1036. clif_displaymessage(sd->fd, output);
  1037. }
  1038. return -1;
  1039. }
  1040. opt = 1<<(k-1);
  1041. if (channel->type == CHAN_TYPE_PRIVATE && !pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN)) {
  1042. switch (opt) {
  1043. case CHAN_OPT_MSG_DELAY:
  1044. if (!channel_config.private_channel.change_delay)
  1045. return -1;
  1046. break;
  1047. case CHAN_OPT_COLOR_OVERRIDE:
  1048. if (!channel_config.private_channel.color_override)
  1049. return -1;
  1050. break;
  1051. }
  1052. }
  1053. if( val[0] == '\0' ) {
  1054. if ( opt == CHAN_OPT_MSG_DELAY ) {
  1055. sprintf(output, msg_txt(sd,1466), opt_str[k]);// Input the number of seconds (0-10) for the '%s' option.
  1056. clif_displaymessage(sd->fd, output);
  1057. return -1;
  1058. } else if( channel->opt & opt ) {
  1059. sprintf(output, msg_txt(sd,1449), opt_str[k],opt_str[k]); // Option '%s' is already enabled (use '@channel setopt %s 0' to disable).
  1060. clif_displaymessage(sd->fd, output);
  1061. return -1;
  1062. } else {
  1063. channel->opt |= opt;
  1064. sprintf(output, msg_txt(sd,1450), opt_str[k],channel->name);// Option '%s' is enabled for channel '#%s'.
  1065. clif_displaymessage(sd->fd, output);
  1066. }
  1067. } else {
  1068. int v = atoi(val);
  1069. if( opt == CHAN_OPT_MSG_DELAY ) {
  1070. if( v < 0 || v > 10 ) {
  1071. sprintf(output, msg_txt(sd,1451), v, opt_str[k]);// Value '%d' for option '%s' is out of range (limit 0-10).
  1072. clif_displaymessage(sd->fd, output);
  1073. return -1;
  1074. }
  1075. if( v == 0 ) {
  1076. channel->opt &=~ opt;
  1077. channel->msg_delay = 0;
  1078. sprintf(output, msg_txt(sd,1453), opt_str[k],channel->name,v);// Option '%s' is disabled for channel '#%s'.
  1079. clif_displaymessage(sd->fd, output);
  1080. } else {
  1081. channel->opt |= opt;
  1082. channel->msg_delay = v * 1000;
  1083. sprintf(output, msg_txt(sd,1452), opt_str[k],channel->name,v);// Option '%s' is enabled for channel '#%s' at %d seconds.
  1084. clif_displaymessage(sd->fd, output);
  1085. }
  1086. } else {
  1087. if( v ) {
  1088. if( channel->opt & opt ) {
  1089. sprintf(output, msg_txt(sd,1449), opt_str[k],opt_str[k]); // Option '%s' is already enabled (use '@channel setopt %s 0' to disable).
  1090. clif_displaymessage(sd->fd, output);
  1091. return -1;
  1092. } else {
  1093. channel->opt |= opt;
  1094. sprintf(output, msg_txt(sd,1450), opt_str[k],channel->name);// Option '%s' is enabled for channel '#%s'.
  1095. clif_displaymessage(sd->fd, output);
  1096. }
  1097. } else {
  1098. if( !(channel->opt & opt) ) {
  1099. sprintf(output, msg_txt(sd,1450), opt_str[k],channel->name); // Option '%s' is enabled for channel '#%s'.
  1100. clif_displaymessage(sd->fd, output);
  1101. return -1;
  1102. } else {
  1103. channel->opt &=~ opt;
  1104. sprintf(output, msg_txt(sd,1453), opt_str[k],channel->name);// Option '%s' is disabled for channel '#%s'.
  1105. clif_displaymessage(sd->fd, output);
  1106. }
  1107. }
  1108. }
  1109. }
  1110. return 0;
  1111. }
  1112. /**
  1113. * Check if the given group ID can join the channel
  1114. * @param channel: Channel data
  1115. * @param group_id: Group ID to check
  1116. * @return True on success or false on failure
  1117. */
  1118. bool channel_pccheckgroup(struct Channel *channel, int group_id) {
  1119. unsigned short i;
  1120. nullpo_ret(channel);
  1121. if (!channel->groups || !channel->group_count)
  1122. return true;
  1123. for (i = 0; i < channel->group_count; i++) {
  1124. if (channel->groups[i] == group_id)
  1125. return true;
  1126. }
  1127. return false;
  1128. }
  1129. /**
  1130. * Attempt to autojoin a player to a channel
  1131. */
  1132. int channel_pcautojoin_sub(DBKey key, DBData *data, va_list ap) {
  1133. struct Channel *channel = (struct Channel *)db_data2ptr(data);
  1134. struct map_session_data *sd = NULL;
  1135. char channame[CHAN_NAME_LENGTH+1];
  1136. nullpo_ret(channel);
  1137. nullpo_ret((sd = va_arg(ap, struct map_session_data *)));
  1138. if (channel->pass[0])
  1139. return 0;
  1140. if (!(channel->opt&CHAN_OPT_AUTOJOIN))
  1141. return 0;
  1142. if (!pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) && !channel_pccheckgroup(channel, sd->group_id))
  1143. return 0;
  1144. safesnprintf(channame, sizeof(channame), "#%s", channel->name);
  1145. channel_pcjoin(sd, channame, NULL);
  1146. return 1;
  1147. }
  1148. /**
  1149. * Attempt to autojoin a player to a channel
  1150. * @param sd: Player data
  1151. */
  1152. void channel_autojoin(struct map_session_data *sd) {
  1153. nullpo_retv(sd);
  1154. if (sd->state.autotrade || !sd->fd)
  1155. return;
  1156. channel_db->foreach(channel_db, channel_pcautojoin_sub, sd);
  1157. }
  1158. /**
  1159. * Get color by name or RGB hex code
  1160. * @param color_str: Color name
  1161. * @return color in RGB
  1162. */
  1163. unsigned long channel_getColor(const char *color_str) {
  1164. int i;
  1165. for (i = 0; i < channel_config.colors_count; i++) {
  1166. if (strcmpi(channel_config.colors_name[i], color_str) == 0)
  1167. return channel_config.colors[i];
  1168. }
  1169. return channel_config.colors[0];
  1170. }
  1171. /**
  1172. * Attempt to create a global channel from the channel config
  1173. * @param chan: Channel list
  1174. * @param tmp_chan: Temporary channel data
  1175. * @param i: Index
  1176. * @return True on success or false on failure
  1177. */
  1178. bool channel_read_sub(config_setting_t *chan, struct Channel *tmp_chan, uint8 i) {
  1179. config_setting_t *group_list = NULL;
  1180. int delay = 1000, autojoin = 0, leave = 1, chat = 1, color_override = 0,
  1181. self_notif = 1, join_notif = 0, leave_notif = 0;
  1182. int64 type = CHAN_TYPE_PUBLIC;
  1183. int group_count = 0;
  1184. const char *name = NULL, *password = NULL, *alias = NULL, *color_str = "Default", *type_str = NULL;
  1185. if (tmp_chan == NULL)
  1186. return false;
  1187. if (!config_setting_lookup_string(chan, "name", &name)) {
  1188. ShowError("Please input channel 'name' at '%s' line '%d'! Skipping...\n", chan->file, chan->line);
  1189. return false;
  1190. }
  1191. if (config_setting_lookup_string(chan, "type", &type_str) && !script_get_constant(type_str, &type)) {
  1192. ShowError("Invalid channel type %s at '%s' line '%d'! Skipping...\n", type_str, chan->file, chan->line);
  1193. return false;
  1194. }
  1195. config_setting_lookup_string(chan, "password", &password);
  1196. config_setting_lookup_string(chan, "alias", &alias);
  1197. config_setting_lookup_string(chan, "color", &color_str);
  1198. config_setting_lookup_int(chan, "delay", &delay);
  1199. config_setting_lookup_bool(chan, "autojoin", &autojoin);
  1200. config_setting_lookup_bool(chan, "leave", &leave);
  1201. config_setting_lookup_bool(chan, "chat", &chat);
  1202. config_setting_lookup_bool(chan, "color_override", &color_override);
  1203. config_setting_lookup_bool(chan, "self_notif", &self_notif);
  1204. config_setting_lookup_bool(chan, "join_notif", &join_notif);
  1205. config_setting_lookup_bool(chan, "leave_notif", &leave_notif);
  1206. safestrncpy(tmp_chan->name,name+1,sizeof(tmp_chan->name));
  1207. if (password)
  1208. safestrncpy(tmp_chan->pass,password,sizeof(tmp_chan->pass));
  1209. else
  1210. tmp_chan->pass[0] = '\0';
  1211. safestrncpy(tmp_chan->alias,alias?alias:name,sizeof(tmp_chan->alias));
  1212. tmp_chan->msg_delay = delay;
  1213. tmp_chan->type = (enum Channel_Type)type;
  1214. tmp_chan->color = channel_getColor(color_str);
  1215. tmp_chan->opt = (autojoin ? CHAN_OPT_AUTOJOIN : 0) |
  1216. (leave ? CHAN_OPT_CAN_LEAVE : 0) |
  1217. (chat ? CHAN_OPT_CAN_CHAT : 0) |
  1218. (color_override ? CHAN_OPT_COLOR_OVERRIDE : 0) |
  1219. (self_notif ? CHAN_OPT_ANNOUNCE_SELF : 0) |
  1220. (join_notif ? CHAN_OPT_ANNOUNCE_JOIN : 0) |
  1221. (leave_notif ? CHAN_OPT_ANNOUNCE_LEAVE : 0);
  1222. if ((group_list = config_setting_get_member(chan, "groupid")) && (group_count = config_setting_length(group_list)) > 0) {
  1223. int j;
  1224. CREATE(tmp_chan->groups, unsigned short, group_count);
  1225. tmp_chan->group_count = group_count;
  1226. for (j = 0; j < group_count; j++) {
  1227. int groupid = config_setting_get_int_elem(group_list, j);
  1228. tmp_chan->groups[j] = groupid;
  1229. }
  1230. }
  1231. return true;
  1232. }
  1233. /**
  1234. * Read and verify configuration in file
  1235. * Assign table value with value
  1236. */
  1237. void channel_read_config(void) {
  1238. config_t channels_conf;
  1239. config_setting_t *chan_setting = NULL;
  1240. if (conf_read_file(&channels_conf, channel_conf)) {
  1241. ShowError("Cannot read file '%s' for channel connfig.\n", channel_conf);
  1242. return;
  1243. }
  1244. chan_setting = config_lookup(&channels_conf, "channel_config");
  1245. if (chan_setting != NULL) {
  1246. config_setting_t *colors, *private_channel = NULL, *channels = NULL;
  1247. int count = 0, channel_count = 0;
  1248. colors = config_setting_get_member(chan_setting, "colors");
  1249. if (colors != NULL) {
  1250. int i, color_count = config_setting_length(colors);
  1251. CREATE(channel_config.colors, unsigned long, color_count);
  1252. CREATE(channel_config.colors_name, char *, color_count);
  1253. for (i = 0; i < color_count; i++) {
  1254. config_setting_t *color = config_setting_get_elem(colors, i);
  1255. CREATE(channel_config.colors_name[i], char, CHAN_NAME_LENGTH);
  1256. safestrncpy(channel_config.colors_name[i], config_setting_name(color), CHAN_NAME_LENGTH);
  1257. channel_config.colors[i] = strtoul(config_setting_get_string_elem(colors,i),NULL,0);
  1258. channel_config.colors[i] = (channel_config.colors[i] & 0x0000FF) << 16 | (channel_config.colors[i] & 0x00FF00) | (channel_config.colors[i] & 0xFF0000) >> 16;//RGB to BGR
  1259. }
  1260. channel_config.colors_count = color_count;
  1261. }
  1262. private_channel = config_setting_get_member(chan_setting, "private_channel");
  1263. if (private_channel != NULL) {
  1264. int allow = 1, ban = 1, kick = 1, color_override = 0, change_delay = 0,
  1265. self_notif = 1, join_notif = 0, leave_notif = 0,
  1266. delay = 1000, max_member = 1000;
  1267. const char *color_str = "Default";
  1268. config_setting_lookup_bool(private_channel, "allow", &allow);
  1269. config_setting_lookup_int(private_channel, "delay", &delay);
  1270. config_setting_lookup_string(private_channel, "color", &color_str);
  1271. config_setting_lookup_int(private_channel, "max_member", &max_member);
  1272. config_setting_lookup_bool(private_channel, "self_notif", &self_notif);
  1273. config_setting_lookup_bool(private_channel, "join_notif", &join_notif);
  1274. config_setting_lookup_bool(private_channel, "leave_notif", &leave_notif);
  1275. config_setting_lookup_bool(private_channel, "ban", &ban);
  1276. config_setting_lookup_bool(private_channel, "kick", &kick);
  1277. config_setting_lookup_bool(private_channel, "color_override", &color_override);
  1278. config_setting_lookup_bool(private_channel, "change_delay", &change_delay);
  1279. channel_config.private_channel.allow = allow;
  1280. channel_config.private_channel.color = channel_getColor(color_str);
  1281. channel_config.private_channel.delay = delay;
  1282. channel_config.private_channel.max_member = min(max_member, UINT16_MAX);
  1283. channel_config.private_channel.ban = ban;
  1284. channel_config.private_channel.kick = kick;
  1285. channel_config.private_channel.color_override = color_override;
  1286. channel_config.private_channel.change_delay = change_delay;
  1287. channel_config.private_channel.opt = CHAN_OPT_CAN_CHAT|CHAN_OPT_CAN_LEAVE|
  1288. (color_override ? CHAN_OPT_COLOR_OVERRIDE : 0) |
  1289. (self_notif ? CHAN_OPT_ANNOUNCE_SELF : 0) |
  1290. (join_notif ? CHAN_OPT_ANNOUNCE_JOIN : 0) |
  1291. (leave_notif ? CHAN_OPT_ANNOUNCE_LEAVE : 0);
  1292. }
  1293. channels = config_setting_get_member(chan_setting, "ally");
  1294. if (channels != NULL) {
  1295. memset(&channel_config.ally_tmpl, 0, sizeof(struct Channel));
  1296. channel_read_sub(channels, &channel_config.ally_tmpl, 0);
  1297. }
  1298. channels = config_setting_get_member(chan_setting, "map");
  1299. if (channels != NULL) {
  1300. memset(&channel_config.map_tmpl, 0, sizeof(struct Channel));
  1301. channel_read_sub(channels, &channel_config.map_tmpl, 0);
  1302. }
  1303. channels = config_setting_get_member(chan_setting, "channels");
  1304. if (channels != NULL && (count = config_setting_length(channels)) > 0) {
  1305. int i;
  1306. for (i = 0; i < count; i++) {
  1307. config_setting_t *chan = config_setting_get_elem(channels, i);
  1308. struct Channel *channel = NULL, tmp_chan;
  1309. memset(&tmp_chan, 0, sizeof(struct Channel));
  1310. if (!channel_read_sub(chan, &tmp_chan, i))
  1311. continue;
  1312. if ((channel = channel_create(&tmp_chan))) {
  1313. channel_count++;
  1314. channel->group_count = tmp_chan.group_count;
  1315. channel->groups = tmp_chan.groups;
  1316. }
  1317. }
  1318. }
  1319. ShowStatus("Done reading '" CL_WHITE "%d" CL_RESET "' channels in '" CL_WHITE "%s" CL_RESET "'.\n", db_size(channel_db), channel_conf);
  1320. config_destroy(&channels_conf);
  1321. }
  1322. }
  1323. /**
  1324. * Initialise db and read configuration
  1325. */
  1326. void do_init_channel(void) {
  1327. channel_db = stridb_alloc(static_cast<DBOptions>(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA), CHAN_NAME_LENGTH);
  1328. memset(&channel_config.private_channel, 0, sizeof(struct Channel));
  1329. memset(&channel_config.ally_tmpl, 0, sizeof(struct Channel));
  1330. memset(&channel_config.map_tmpl, 0, sizeof(struct Channel));
  1331. channel_read_config();
  1332. }
  1333. /**
  1334. * Close all channels and cleanup
  1335. */
  1336. void do_final_channel(void) {
  1337. DBIterator *iter;
  1338. struct Channel *channel;
  1339. //delete all in remaining chan db
  1340. iter = db_iterator(channel_db);
  1341. for( channel = (struct Channel *)dbi_first(iter); dbi_exists(iter); channel = (struct Channel *)dbi_next(iter) ) {
  1342. channel_delete(channel,false);
  1343. }
  1344. dbi_destroy(iter);
  1345. //at this point all user should have left their channel (private and public should be gone)
  1346. db_destroy(channel_db);
  1347. //delete all color thing
  1348. if( channel_config.colors_count ) {
  1349. int i=0;
  1350. for(i = 0; i < channel_config.colors_count; i++) {
  1351. aFree(channel_config.colors_name[i]);
  1352. }
  1353. aFree(channel_config.colors_name);
  1354. aFree(channel_config.colors);
  1355. }
  1356. }