channel.cpp 48 KB

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