chat.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include "../common/nullpo.h"
  6. #include "../common/malloc.h"
  7. #include "battle.h"
  8. #include "chat.h"
  9. #include "map.h"
  10. #include "clif.h"
  11. #include "pc.h"
  12. #include "npc.h"
  13. #include "atcommand.h"
  14. int chat_triggerevent(struct chat_data *cd);
  15. /*==========================================
  16. * チャットルーム作成
  17. *------------------------------------------
  18. */
  19. int chat_createchat(struct map_session_data *sd,int limit,int pub,char* pass,char* title,int titlelen)
  20. {
  21. struct chat_data *cd;
  22. nullpo_retr(0, sd);
  23. if (sd->chatID)
  24. return 0; //Prevent people abusing the chat system by creating multiple chats, as pointed out by End of Exam. [Skotlex]
  25. if (map[sd->bl.m].flag.nochat) {
  26. clif_displaymessage (sd->fd, msg_txt(281));
  27. return 0; //Can't create chatrooms on this map.
  28. }
  29. pc_stop_walking(sd,1);
  30. cd = (struct chat_data *) aMalloc(sizeof(struct chat_data));
  31. cd->limit = limit;
  32. cd->pub = pub;
  33. cd->users = 1;
  34. memcpy(cd->pass,pass,8);
  35. cd->pass[7]= '\0'; //Overflow check... [Skotlex]
  36. if(titlelen>=sizeof(cd->title)-1) titlelen=sizeof(cd->title)-1;
  37. memcpy(cd->title,title,titlelen);
  38. cd->title[titlelen]=0;
  39. cd->owner = (struct block_list **)(&cd->usersd[0]);
  40. cd->usersd[0] = sd;
  41. cd->bl.m = sd->bl.m;
  42. cd->bl.x = sd->bl.x;
  43. cd->bl.y = sd->bl.y;
  44. cd->bl.type = BL_CHAT;
  45. cd->bl.next = cd->bl.prev = NULL;
  46. cd->bl.id = map_addobject(&cd->bl);
  47. if(cd->bl.id==0){
  48. clif_createchat(sd,1);
  49. aFree(cd);
  50. return 0;
  51. }
  52. pc_setchatid(sd,cd->bl.id);
  53. clif_createchat(sd,0);
  54. clif_dispchat(cd,0);
  55. return 0;
  56. }
  57. /*==========================================
  58. * 既存チャットルームに参加
  59. *------------------------------------------
  60. */
  61. int chat_joinchat (struct map_session_data *sd, int chatid, char* pass)
  62. {
  63. struct chat_data *cd;
  64. nullpo_retr(0, sd);
  65. cd = (struct chat_data*)map_id2bl(chatid);
  66. //No need for a nullpo check. The chatid was sent by the client, if they lag or mess with the packet
  67. //a wrong chat id can be received. [Skotlex]
  68. if (cd == NULL)
  69. return 1;
  70. if (cd->bl.type != BL_CHAT || cd->bl.m != sd->bl.m || sd->vender_id || sd->chatID || cd->limit <= cd->users) {
  71. clif_joinchatfail(sd,0);
  72. return 0;
  73. }
  74. //Allows Gm access to protected room with any password they want by valaris
  75. if ((cd->pub == 0 && strncmp(pass, (char *)cd->pass, 8) && (pc_isGM(sd) < battle_config.gm_join_chat || !battle_config.gm_join_chat)) ||
  76. chatid == (int)sd->chatID) //Double Chat fix by Alex14, thx CHaNGeTe
  77. {
  78. clif_joinchatfail(sd,1);
  79. return 0;
  80. }
  81. pc_stop_walking(sd,1);
  82. cd->usersd[cd->users] = sd;
  83. cd->users++;
  84. pc_setchatid(sd,cd->bl.id);
  85. clif_joinchatok(sd,cd); // 新たに参加した人には全員のリスト
  86. clif_addchat(cd,sd); // 既に中に居た人には追加した人の報告
  87. clif_dispchat(cd,0); // 周囲の人には人数変化報告
  88. chat_triggerevent(cd); // イベント
  89. return 0;
  90. }
  91. /*==========================================
  92. * チャットルームから抜ける
  93. *------------------------------------------
  94. */
  95. int chat_leavechat(struct map_session_data *sd)
  96. {
  97. struct chat_data *cd;
  98. int i,leavechar;
  99. nullpo_retr(1, sd);
  100. cd=(struct chat_data*)map_id2bl(sd->chatID);
  101. if(cd==NULL) {
  102. sd->chatID = 0;
  103. return 1;
  104. }
  105. for(i = 0,leavechar=-1;i < cd->users;i++){
  106. if(cd->usersd[i] == sd){
  107. leavechar=i;
  108. break;
  109. }
  110. }
  111. if(leavechar<0)
  112. { //Not found in the chatroom?
  113. sd->chatID = 0;
  114. return -1;
  115. }
  116. if(leavechar==0 && cd->users>1 && (*cd->owner)->type==BL_PC){
  117. // 所有者だった&他に人が居る&PCのチャット
  118. clif_changechatowner(cd,cd->usersd[1]);
  119. clif_clearchat(cd,0);
  120. }
  121. // 抜けるPCにも送るのでusersを減らす前に実行
  122. clif_leavechat(cd,sd);
  123. cd->users--;
  124. pc_setchatid(sd,0);
  125. if(cd->users == 0 && (*cd->owner)->type==BL_PC){
  126. //Delete empty chatroom
  127. clif_clearchat(cd,0);
  128. map_delobject(cd->bl.id);
  129. return 1;
  130. }
  131. for(i=leavechar;i < cd->users;i++)
  132. cd->usersd[i] = cd->usersd[i+1];
  133. if(leavechar==0 && (*cd->owner)->type==BL_PC){
  134. //Adjust Chat location after owner has been changed.
  135. map_delblock( &cd->bl );
  136. cd->bl.x=cd->usersd[0]->bl.x;
  137. cd->bl.y=cd->usersd[0]->bl.y;
  138. map_addblock( &cd->bl );
  139. }
  140. clif_dispchat(cd,0);
  141. return 0;
  142. }
  143. /*==========================================
  144. * チャットルームの持ち主を譲る
  145. *------------------------------------------
  146. */
  147. int chat_changechatowner(struct map_session_data *sd,char *nextownername)
  148. {
  149. struct chat_data *cd;
  150. struct map_session_data *tmp_sd;
  151. int i, nextowner;
  152. nullpo_retr(1, sd);
  153. cd = (struct chat_data*)map_id2bl(sd->chatID);
  154. if (cd == NULL || (struct block_list *)sd != (*cd->owner))
  155. return 1;
  156. for(i = 1,nextowner=-1;i < cd->users;i++){
  157. if(strcmp(cd->usersd[i]->status.name,nextownername)==0){
  158. nextowner=i;
  159. break;
  160. }
  161. }
  162. if(nextowner<0) // そんな人は居ない
  163. return -1;
  164. clif_changechatowner(cd,cd->usersd[nextowner]);
  165. // 一旦消す
  166. clif_clearchat(cd,0);
  167. // userlistの順番変更 (0が所有者なので)
  168. if( (tmp_sd = cd->usersd[0]) == NULL ) //FIXME: How is this even possible!? Invoking character should be owner, hence, it SHOULD be on sc->usersd[0]!
  169. return 1; //ありえるのかな?
  170. cd->usersd[0] = cd->usersd[nextowner];
  171. cd->usersd[nextowner] = tmp_sd;
  172. map_delblock( &cd->bl );
  173. cd->bl.x=cd->usersd[0]->bl.x;
  174. cd->bl.y=cd->usersd[0]->bl.y;
  175. map_addblock( &cd->bl );
  176. // 再度表示
  177. clif_dispchat(cd,0);
  178. return 0;
  179. }
  180. /*==========================================
  181. * チャットの状態(タイトル等)を変更
  182. *------------------------------------------
  183. */
  184. int chat_changechatstatus(struct map_session_data *sd,int limit,int pub,char* pass,char* title,int titlelen)
  185. {
  186. struct chat_data *cd;
  187. nullpo_retr(1, sd);
  188. cd=(struct chat_data*)map_id2bl(sd->chatID);
  189. if(cd==NULL || (struct block_list *)sd != (*cd->owner))
  190. return 1;
  191. cd->limit = limit;
  192. cd->pub = pub;
  193. memcpy(cd->pass,pass,8);
  194. cd->pass[7]= '\0'; //Overflow check... [Skotlex]
  195. if(titlelen>=sizeof(cd->title)-1) titlelen=sizeof(cd->title)-1;
  196. memcpy(cd->title,title,titlelen);
  197. cd->title[titlelen]=0;
  198. clif_changechatstatus(cd);
  199. clif_dispchat(cd,0);
  200. return 0;
  201. }
  202. /*==========================================
  203. * チャットルームから蹴り出す
  204. *------------------------------------------
  205. */
  206. int chat_kickchat(struct map_session_data *sd,char *kickusername)
  207. {
  208. struct chat_data *cd;
  209. int i;
  210. nullpo_retr(1, sd);
  211. cd = (struct chat_data *)map_id2bl(sd->chatID);
  212. if (!cd) return -1;
  213. for(i = 0; i < cd->users; i++) {
  214. if (strcmp(cd->usersd[i]->status.name, kickusername) == 0) {
  215. if (battle_config.gm_kick_chat && pc_isGM(cd->usersd[i]) >= battle_config.gm_kick_chat)
  216. //gm kick protection by valaris
  217. return 0;
  218. chat_leavechat(cd->usersd[i]);
  219. return 0;
  220. }
  221. }
  222. return -1;
  223. }
  224. /*==========================================
  225. * npcチャットルーム作成
  226. *------------------------------------------
  227. */
  228. int chat_createnpcchat(struct npc_data *nd,int limit,int pub,int trigger,char* title,int titlelen,const char *ev)
  229. {
  230. struct chat_data *cd;
  231. nullpo_retr(1, nd);
  232. cd = (struct chat_data *) aMalloc(sizeof(struct chat_data));
  233. cd->limit = cd->trigger = limit;
  234. if(trigger>0)
  235. cd->trigger = trigger;
  236. cd->pub = pub;
  237. cd->users = 0;
  238. memcpy(cd->pass,"",1);
  239. if(titlelen>=sizeof(cd->title)-1) titlelen=sizeof(cd->title)-1;
  240. memcpy(cd->title,title,titlelen);
  241. cd->title[titlelen]=0;
  242. cd->bl.m = nd->bl.m;
  243. cd->bl.x = nd->bl.x;
  244. cd->bl.y = nd->bl.y;
  245. cd->bl.type = BL_CHAT;
  246. cd->bl.prev= cd->bl.next = NULL;
  247. cd->owner_ = (struct block_list *)nd;
  248. cd->owner = &cd->owner_;
  249. if (strlen(ev) > 49)
  250. { //npc_event is a char[50] [Skotlex]
  251. memcpy(cd->npc_event,ev,49);
  252. cd->npc_event[49] = '\0';
  253. } else
  254. memcpy(cd->npc_event,ev,strlen(ev)+1); //Include the \0
  255. cd->bl.id = map_addobject(&cd->bl);
  256. if(cd->bl.id==0){
  257. aFree(cd);
  258. return 0;
  259. }
  260. nd->chat_id=cd->bl.id;
  261. clif_dispchat(cd,0);
  262. return 0;
  263. }
  264. /*==========================================
  265. * npcチャットルーム削除
  266. *------------------------------------------
  267. */
  268. int chat_deletenpcchat(struct npc_data *nd)
  269. {
  270. struct chat_data *cd;
  271. nullpo_retr(0, nd);
  272. nullpo_retr(0, cd=(struct chat_data*)map_id2bl(nd->chat_id));
  273. chat_npckickall(cd);
  274. clif_clearchat(cd,0);
  275. map_delobject(cd->bl.id); // freeまでしてくれる
  276. nd->chat_id=0;
  277. return 0;
  278. }
  279. /*==========================================
  280. * 規定人数以上でイベントが定義されてるなら実行
  281. *------------------------------------------
  282. */
  283. int chat_triggerevent(struct chat_data *cd)
  284. {
  285. nullpo_retr(0, cd);
  286. if(cd->users>=cd->trigger && cd->npc_event[0])
  287. npc_event_do(cd->npc_event);
  288. return 0;
  289. }
  290. /*==========================================
  291. * イベントの有効化
  292. *------------------------------------------
  293. */
  294. int chat_enableevent(struct chat_data *cd)
  295. {
  296. nullpo_retr(0, cd);
  297. cd->trigger&=0x7f;
  298. chat_triggerevent(cd);
  299. return 0;
  300. }
  301. /*==========================================
  302. * イベントの無効化
  303. *------------------------------------------
  304. */
  305. int chat_disableevent(struct chat_data *cd)
  306. {
  307. nullpo_retr(0, cd);
  308. cd->trigger|=0x80;
  309. return 0;
  310. }
  311. /*==========================================
  312. * チャットルームから全員蹴り出す
  313. *------------------------------------------
  314. */
  315. int chat_npckickall(struct chat_data *cd)
  316. {
  317. nullpo_retr(0, cd);
  318. while(cd->users>0){
  319. chat_leavechat(cd->usersd[cd->users-1]);
  320. }
  321. return 0;
  322. }