charcommand.c 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790
  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 <stdlib.h>
  5. #include <string.h>
  6. #include <ctype.h>
  7. #include <math.h>
  8. #include "../common/socket.h"
  9. #include "../common/timer.h"
  10. #include "../common/nullpo.h"
  11. #include "log.h"
  12. #include "clif.h"
  13. #include "chrif.h"
  14. #include "intif.h"
  15. #include "itemdb.h"
  16. #include "map.h"
  17. #include "pc.h"
  18. #include "status.h"
  19. #include "skill.h"
  20. #include "mob.h"
  21. #include "pet.h"
  22. #include "battle.h"
  23. #include "charcommand.h"
  24. #include "atcommand.h"
  25. #include "showmsg.h"
  26. static char command_symbol = '#';
  27. extern char *msg_table[1000]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others)
  28. #define CCMD_FUNC(x) int charcommand_ ## x (const int fd, struct map_session_data* sd, const char* command, const char* message)
  29. CCMD_FUNC(jobchange);
  30. CCMD_FUNC(petrename);
  31. CCMD_FUNC(petfriendly);
  32. CCMD_FUNC(stats);
  33. CCMD_FUNC(option);
  34. CCMD_FUNC(save);
  35. CCMD_FUNC(stats_all);
  36. CCMD_FUNC(reset);
  37. CCMD_FUNC(spiritball);
  38. CCMD_FUNC(itemlist);
  39. CCMD_FUNC(effect);
  40. CCMD_FUNC(storagelist);
  41. CCMD_FUNC(item);
  42. CCMD_FUNC(warp);
  43. CCMD_FUNC(zeny);
  44. CCMD_FUNC(fakename);
  45. CCMD_FUNC(baselevel);
  46. CCMD_FUNC(joblevel);
  47. CCMD_FUNC(questskill);
  48. CCMD_FUNC(lostskill);
  49. CCMD_FUNC(skreset);
  50. CCMD_FUNC(streset);
  51. CCMD_FUNC(model);
  52. CCMD_FUNC(stpoint);
  53. CCMD_FUNC(skpoint);
  54. CCMD_FUNC(changesex);
  55. CCMD_FUNC(feelreset);
  56. CCMD_FUNC(help);
  57. /*==========================================
  58. *CharCommandInfo charcommand_info[]構造体の定義
  59. *------------------------------------------
  60. */
  61. // First char of commands is configured in charcommand_athena.conf. Leave # in this list for default value.
  62. // to set default level, read charcommand_athena.conf first please.
  63. static CharCommandInfo charcommand_info[] = {
  64. { CharCommandJobChange, "#job", 60, charcommand_jobchange },
  65. { CharCommandJobChange, "#jobchange", 60, charcommand_jobchange },
  66. { CharCommandPetRename, "#petrename", 50, charcommand_petrename },
  67. { CharCommandPetFriendly, "#petfriendly", 50, charcommand_petfriendly },
  68. { CharCommandStats, "#stats", 40, charcommand_stats },
  69. { CharCommandOption, "#option", 60, charcommand_option },
  70. { CharCommandReset, "#reset", 60, charcommand_reset },
  71. { CharCommandSave, "#save", 60, charcommand_save },
  72. { CharCommandStatsAll, "#statsall", 40, charcommand_stats_all },
  73. { CharCommandSpiritball, "#spiritball", 40, charcommand_spiritball },
  74. { CharCommandItemList, "#itemlist", 40, charcommand_itemlist },
  75. { CharCommandEffect, "#effect", 40, charcommand_effect },
  76. { CharCommandStorageList, "#storagelist", 40, charcommand_storagelist },
  77. { CharCommandItem, "#item", 60, charcommand_item },
  78. { CharCommandWarp, "#warp", 60, charcommand_warp },
  79. { CharCommandWarp, "#rura", 60, charcommand_warp },
  80. { CharCommandWarp, "#rura+", 60, charcommand_warp },
  81. { CharCommandZeny, "#zeny", 60, charcommand_zeny },
  82. { CharCommandFakeName, "#fakename", 20, charcommand_fakename},
  83. //*********************************Recently added commands*********************************************
  84. { CharCommandBaseLevel, "#baselvl", 20, charcommand_baselevel},
  85. { CharCommandBaseLevel, "#blvl", 60, charcommand_baselevel},
  86. { CharCommandBaseLevel, "#baselvlup", 60, charcommand_baselevel},
  87. { CharCommandJobLevel, "#joblvl", 60, charcommand_joblevel},
  88. { CharCommandJobLevel, "#jlvl", 60, charcommand_joblevel},
  89. { CharCommandJobLevel, "#joblvlup", 60, charcommand_joblevel},
  90. { CharCommandQuestSkill, "#questskill", 60, charcommand_questskill },
  91. { CharCommandLostSkill, "#lostskill", 60, charcommand_lostskill },
  92. { CharCommandSkReset, "#skreset", 60, charcommand_skreset },
  93. { CharCommandStReset, "#streset", 60, charcommand_streset },
  94. { CharCommandModel, "#model", 50, charcommand_model },
  95. { CharCommandSKPoint, "#skpoint", 60, charcommand_skpoint },
  96. { CharCommandSTPoint, "#stpoint", 60, charcommand_stpoint },
  97. { CharCommandChangeSex, "#changesex", 60, charcommand_changesex },
  98. { CharCommandFeelReset, "#feelreset", 60, charcommand_feelreset },
  99. { CharCommandHelp, "#help", 20, charcommand_help },
  100. // add new commands before this line
  101. { CharCommand_Unknown, NULL, 1, NULL }
  102. };
  103. int get_charcommand_level(const CharCommandType type) {
  104. int i;
  105. for (i = 0; charcommand_info[i].type != CharCommand_None; i++)
  106. if (charcommand_info[i].type == type)
  107. return charcommand_info[i].level;
  108. return 100; // 100: command can not be used
  109. }
  110. /*==========================================
  111. *is_charcommand @コマンドに存在するかどうか確認する
  112. *------------------------------------------
  113. */
  114. CharCommandType
  115. is_charcommand(const int fd, struct map_session_data* sd, const char* message, int gmlvl) {
  116. const char* str = message;
  117. int s_flag = 0;
  118. CharCommandInfo info;
  119. CharCommandType type;
  120. nullpo_retr(CharCommand_None, sd);
  121. if (!message || !*message)
  122. return CharCommand_None;
  123. memset(&info, 0, sizeof(info));
  124. str += strlen(sd->status.name);
  125. while (*str && (isspace(*str) || (s_flag == 0 && *str == ':'))) {
  126. if (*str == ':')
  127. s_flag = 1;
  128. str++;
  129. }
  130. if (!*str)
  131. return CharCommand_None;
  132. type = charcommand(sd, gmlvl > 0 ? gmlvl : pc_isGM(sd), str, &info);
  133. if (type != CharCommand_None) {
  134. char command[100];
  135. char output[200];
  136. const char* p = str;
  137. memset(command, '\0', sizeof(command));
  138. memset(output, '\0', sizeof(output));
  139. while (*p && !isspace(*p))
  140. p++;
  141. if (p - str >= sizeof(command)) // too long
  142. return CharCommand_Unknown;
  143. strncpy(command, str, p - str);
  144. while (isspace(*p))
  145. p++;
  146. if (type == CharCommand_Unknown || info.proc == NULL) {
  147. snprintf(output, sizeof(output),msg_txt(153), command); // %s is Unknown Command.
  148. clif_displaymessage(fd, output);
  149. } else {
  150. if (info.proc(fd, sd, command, p) != 0) {
  151. // Command can not be executed
  152. snprintf(output, sizeof(output), msg_txt(154), command); // %s failed.
  153. clif_displaymessage(fd, output);
  154. }
  155. }
  156. return info.type;
  157. }
  158. return CharCommand_None;
  159. }
  160. /*==========================================
  161. *
  162. *------------------------------------------
  163. */
  164. CharCommandType charcommand(struct map_session_data* sd, const int level, const char* message, CharCommandInfo* info) {
  165. char* p = (char *)message;
  166. if (!info)
  167. return CharCommand_None;
  168. if (battle_config.atc_gmonly != 0 && !level) // level = pc_isGM(sd)
  169. return CharCommand_None;
  170. if (!p || !*p) {
  171. ShowError("char command message is empty\n");
  172. return CharCommand_None;
  173. }
  174. if (*p == command_symbol) { // check first char.
  175. char command[101];
  176. int i = 0;
  177. memset(info, 0, sizeof(CharCommandInfo));
  178. sscanf(p, "%100s", command);
  179. command[sizeof(command)-1] = '\0';
  180. while (charcommand_info[i].type != CharCommand_Unknown) {
  181. if (strcmpi(command+1, charcommand_info[i].command+1) == 0 && level >= charcommand_info[i].level) {
  182. p[0] = charcommand_info[i].command[0]; // set correct first symbol for after.
  183. break;
  184. }
  185. i++;
  186. }
  187. if (charcommand_info[i].type == CharCommand_Unknown) {
  188. // doesn't return Unknown if player is normal player (display the text, not display: unknown command)
  189. if (level == 0)
  190. return CharCommand_None;
  191. else
  192. return CharCommand_Unknown;
  193. } else if((log_config.gm) && (charcommand_info[i].level >= log_config.gm)) {
  194. log_atcommand(sd, message);
  195. }
  196. memcpy(info, &charcommand_info[i], sizeof charcommand_info[i]);
  197. } else {
  198. return CharCommand_None;
  199. }
  200. return info->type;
  201. }
  202. /*==========================================
  203. *
  204. *------------------------------------------
  205. */
  206. static CharCommandInfo* get_charcommandinfo_byname(const char* name) {
  207. int i;
  208. for (i = 0; charcommand_info[i].type != CharCommand_Unknown; i++)
  209. if (strcmpi(charcommand_info[i].command + 1, name) == 0)
  210. return &charcommand_info[i];
  211. return NULL;
  212. }
  213. /*==========================================
  214. *
  215. *------------------------------------------
  216. */
  217. int charcommand_config_read(const char *cfgName) {
  218. char line[1024], w1[1024], w2[1024];
  219. CharCommandInfo* p;
  220. FILE* fp;
  221. if ((fp = fopen(cfgName, "r")) == NULL) {
  222. ShowError("CharCommands configuration file not found: %s\n", cfgName);
  223. return 1;
  224. }
  225. while (fgets(line, sizeof(line)-1, fp)) {
  226. if (line[0] == '/' && line[1] == '/')
  227. continue;
  228. if (sscanf(line, "%1023[^:]:%1023s", w1, w2) != 2)
  229. continue;
  230. p = get_charcommandinfo_byname(w1);
  231. if (p != NULL) {
  232. p->level = atoi(w2);
  233. if (p->level > 100)
  234. p->level = 100;
  235. else if (p->level < 0)
  236. p->level = 0;
  237. }
  238. if (strcmpi(w1, "import") == 0)
  239. charcommand_config_read(w2);
  240. else if (strcmpi(w1, "command_symbol") == 0 && w2[0] > 31 &&
  241. w2[0] != '/' && // symbol of standard ragnarok GM commands
  242. w2[0] != '%' && // symbol of party chat speaking
  243. w2[0] != '$' && // symbol of guild chat speaking
  244. w2[0] != '@') // symbol of atcommand
  245. command_symbol = w2[0];
  246. }
  247. fclose(fp);
  248. return 0;
  249. }
  250. /*==========================================
  251. * 対象キャラクターを転職させる upper指定で転生や養子も可能
  252. *------------------------------------------
  253. */
  254. int charcommand_jobchange(
  255. const int fd, struct map_session_data* sd,
  256. const char* command, const char* message)
  257. {
  258. char character[100];
  259. struct map_session_data* pl_sd;
  260. int job = 0, upper = -1;
  261. memset(character, '\0', sizeof(character));
  262. if (!message || !*message) {
  263. clif_displaymessage(fd, "Please, enter a job and a player name (usage: #job/#jobchange <job ID> <char name>).");
  264. return -1;
  265. }
  266. if (sscanf(message, "%d %d %99[^\n]", &job, &upper, character) < 3) { //upper指定してある
  267. upper = -1;
  268. if (sscanf(message, "%d %99[^\n]", &job, character) < 2) { //upper指定してない上に何か足りない
  269. clif_displaymessage(fd, "Please, enter a job and a player name (usage: #job/#jobchange <job ID> <char name>).");
  270. return -1;
  271. }
  272. }
  273. if ((pl_sd = map_nick2sd(character)) != NULL) {
  274. int j;
  275. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change job only to lower or same level
  276. if ((job >= 0 && job < MAX_PC_CLASS)) {
  277. for (j=0; j < MAX_INVENTORY; j++) {
  278. if(pl_sd->status.inventory[j].nameid>0 && pl_sd->status.inventory[j].equip!=0)
  279. pc_unequipitem(pl_sd, j, 3);
  280. }
  281. if (pc_jobchange(pl_sd, job, upper) == 0)
  282. clif_displaymessage(fd, msg_table[48]); // Character's job changed.
  283. else {
  284. clif_displaymessage(fd, msg_table[192]); // Impossible to change the character's job.
  285. return -1;
  286. }
  287. } else {
  288. clif_displaymessage(fd, msg_table[49]); // Invalid job ID.
  289. return -1;
  290. }
  291. } else {
  292. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  293. return -1;
  294. }
  295. } else {
  296. clif_displaymessage(fd, msg_table[3]); // Character not found.
  297. return -1;
  298. }
  299. return 0;
  300. }
  301. /*==========================================
  302. *
  303. *------------------------------------------
  304. */
  305. int charcommand_petrename(
  306. const int fd, struct map_session_data* sd,
  307. const char* command, const char* message)
  308. {
  309. char character[NAME_LENGTH];
  310. struct map_session_data *pl_sd;
  311. memset(character, '\0', sizeof(character));
  312. if (!message || !*message || sscanf(message, "%23[^\n]", character) < 1) {
  313. clif_displaymessage(fd, "Please, enter a player name (usage: #petrename <char name>).");
  314. return -1;
  315. }
  316. if ((pl_sd = map_nick2sd(character)) != NULL) {
  317. if (pl_sd->status.pet_id > 0 && pl_sd->pd) {
  318. if (pl_sd->pet.rename_flag != 0) {
  319. pl_sd->pet.rename_flag = 0;
  320. intif_save_petdata(pl_sd->status.account_id, &pl_sd->pet);
  321. clif_send_petstatus(pl_sd);
  322. clif_displaymessage(fd, msg_table[189]); // This player can now rename his/her pet.
  323. } else {
  324. clif_displaymessage(fd, msg_table[190]); // This player can already rename his/her pet.
  325. return -1;
  326. }
  327. } else {
  328. clif_displaymessage(fd, msg_table[191]); // Sorry, but this player has no pet.
  329. return -1;
  330. }
  331. } else {
  332. clif_displaymessage(fd, msg_txt(3)); // Character not found.
  333. return -1;
  334. }
  335. return 0;
  336. }
  337. /*==========================================
  338. *
  339. *------------------------------------------
  340. */
  341. int charcommand_petfriendly(
  342. const int fd, struct map_session_data* sd,
  343. const char* command, const char* message)
  344. {
  345. int friendly = 0;
  346. int t = 0;
  347. char character[NAME_LENGTH];
  348. struct map_session_data *pl_sd;
  349. memset(character, '\0', sizeof(character));
  350. if (!message || !*message || sscanf(message,"%d %23s",&friendly,character) < 2) {
  351. clif_displaymessage(fd, "Please, enter a valid value (usage: "
  352. "#petfriendly <0-1000> <player>).");
  353. return -1;
  354. }
  355. if (((pl_sd = map_nick2sd(character)) != NULL) && pc_isGM(sd)>pc_isGM(pl_sd)) {
  356. if (pl_sd->status.pet_id > 0 && pl_sd->pd) {
  357. if (friendly >= 0 && friendly <= 1000) {
  358. if (friendly != pl_sd->pet.intimate) {
  359. t = pl_sd->pet.intimate;
  360. pl_sd->pet.intimate = friendly;
  361. clif_send_petstatus(pl_sd);
  362. clif_pet_emotion(pl_sd->pd,0);
  363. if (battle_config.pet_status_support) {
  364. if ((pl_sd->pet.intimate > 0 && t <= 0) ||
  365. (pl_sd->pet.intimate <= 0 && t > 0)) {
  366. if (pl_sd->bl.prev != NULL)
  367. status_calc_pc(pl_sd, 0);
  368. else
  369. status_calc_pc(pl_sd, 2);
  370. }
  371. }
  372. clif_displaymessage(pl_sd->fd, msg_table[182]); // Pet friendly value changed!
  373. clif_displaymessage(sd->fd, msg_table[182]); // Pet friendly value changed!
  374. } else {
  375. clif_displaymessage(fd, msg_table[183]); // Pet friendly is already the good value.
  376. return -1;
  377. }
  378. } else {
  379. clif_displaymessage(fd, msg_table[37]); // An invalid number was specified.
  380. return -1;
  381. }
  382. } else {
  383. return -1;
  384. }
  385. } else {
  386. clif_displaymessage(fd, msg_txt(3)); // Character not found.
  387. return -1;
  388. }
  389. return 0;
  390. }
  391. /*==========================================
  392. *
  393. *------------------------------------------
  394. */
  395. int charcommand_stats(
  396. const int fd, struct map_session_data* sd,
  397. const char* command, const char* message)
  398. {
  399. char character[NAME_LENGTH];
  400. char job_jobname[100];
  401. char output[200];
  402. struct map_session_data *pl_sd;
  403. int i;
  404. memset(character, '\0', sizeof(character));
  405. memset(job_jobname, '\0', sizeof(job_jobname));
  406. memset(output, '\0', sizeof(output));
  407. if (!message || !*message || sscanf(message, "%23[^\n]", character) < 1) {
  408. clif_displaymessage(fd, "Please, enter a player name (usage: #stats <char name>).");
  409. return -1;
  410. }
  411. if ((pl_sd = map_nick2sd(character)) != NULL) {
  412. struct {
  413. const char* format;
  414. int value;
  415. } output_table[] = {
  416. { "Base Level - %d", pl_sd->status.base_level },
  417. { job_jobname, pl_sd->status.job_level },
  418. { "Hp - %d", pl_sd->status.hp },
  419. { "MaxHp - %d", pl_sd->status.max_hp },
  420. { "Sp - %d", pl_sd->status.sp },
  421. { "MaxSp - %d", pl_sd->status.max_sp },
  422. { "Str - %3d", pl_sd->status.str },
  423. { "Agi - %3d", pl_sd->status.agi },
  424. { "Vit - %3d", pl_sd->status.vit },
  425. { "Int - %3d", pl_sd->status.int_ },
  426. { "Dex - %3d", pl_sd->status.dex },
  427. { "Luk - %3d", pl_sd->status.luk },
  428. { "Zeny - %d", pl_sd->status.zeny },
  429. { NULL, 0 }
  430. };
  431. sprintf(job_jobname, "Job - %s %s", job_name(pl_sd->status.class_), "(level %d)");
  432. sprintf(output, msg_table[53], pl_sd->status.name); // '%s' stats:
  433. clif_displaymessage(fd, output);
  434. for (i = 0; output_table[i].format != NULL; i++) {
  435. sprintf(output, output_table[i].format, output_table[i].value);
  436. clif_displaymessage(fd, output);
  437. }
  438. } else {
  439. clif_displaymessage(fd, msg_table[3]); // Character not found.
  440. return -1;
  441. }
  442. return 0;
  443. }
  444. /*==========================================
  445. * Character Reset
  446. *------------------------------------------
  447. */
  448. int charcommand_reset(
  449. const int fd, struct map_session_data* sd,
  450. const char* command, const char* message)
  451. {
  452. char character[NAME_LENGTH];
  453. char output[200];
  454. struct map_session_data *pl_sd;
  455. memset(character, '\0', sizeof(character));
  456. memset(output, '\0', sizeof(output));
  457. if (!message || !*message || sscanf(message, "%23[^\n]", character) < 1) {
  458. clif_displaymessage(fd, "Please, enter a player name (usage: #reset <charname>).");
  459. return -1;
  460. }
  461. if ((pl_sd = map_nick2sd(character)) != NULL) {
  462. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can reset a character only for lower or same GM level
  463. pc_resetstate(pl_sd);
  464. pc_resetskill(pl_sd,1);
  465. sprintf(output, msg_table[208], character); // '%s' skill and stats points reseted!
  466. clif_displaymessage(fd, output);
  467. } else {
  468. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  469. return -1;
  470. }
  471. } else {
  472. clif_displaymessage(fd, msg_table[3]); // Character not found.
  473. return -1;
  474. }
  475. return 0;
  476. }
  477. /*==========================================
  478. *
  479. *------------------------------------------
  480. */
  481. int charcommand_option(
  482. const int fd, struct map_session_data* sd,
  483. const char* command, const char* message)
  484. {
  485. char character[NAME_LENGTH];
  486. int opt1 = 0, opt2 = 0, opt3 = 0;
  487. struct map_session_data* pl_sd;
  488. memset(character, '\0', sizeof(character));
  489. if (!message || !*message ||
  490. sscanf(message, "%d %d %d %23[^\n]", &opt1, &opt2, &opt3, character) < 4 ||
  491. opt1 < 0 || opt2 < 0 || opt3 < 0) {
  492. clif_displaymessage(fd, "Please, enter valid options and a player name (usage: #option <param1> <param2> <param3> <charname>).");
  493. return -1;
  494. }
  495. if ((pl_sd = map_nick2sd(character)) != NULL) {
  496. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change option only to lower or same level
  497. pl_sd->sc.opt1 = opt1;
  498. pl_sd->sc.opt2 = opt2;
  499. pc_setoption(pl_sd, opt3);
  500. clif_displaymessage(fd, msg_table[58]); // Character's options changed.
  501. } else {
  502. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  503. return -1;
  504. }
  505. } else {
  506. clif_displaymessage(fd, msg_table[3]); // Character not found.
  507. return -1;
  508. }
  509. return 0;
  510. }
  511. /*==========================================
  512. *
  513. *------------------------------------------
  514. */
  515. int charcommand_save(
  516. const int fd, struct map_session_data* sd,
  517. const char* command, const char* message)
  518. {
  519. char map_name[MAP_NAME_LENGTH];
  520. char character[NAME_LENGTH];
  521. struct map_session_data* pl_sd;
  522. int x = 0, y = 0;
  523. int m;
  524. memset(map_name, '\0', sizeof(map_name));
  525. memset(character, '\0', sizeof(character));
  526. if (!message || !*message || sscanf(message, "%15s %d %d %23[^\n]", map_name, &x, &y, character) < 4 || x < 0 || y < 0) {
  527. clif_displaymessage(fd, "Please, enter a valid save point and a player name (usage: #save <map> <x> <y> <charname>).");
  528. return -1;
  529. }
  530. if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < MAP_NAME_LENGTH-4) // 16 - 4 (.gat)
  531. strcat(map_name, ".gat");
  532. if ((pl_sd = map_nick2sd(character)) != NULL) {
  533. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change save point only to lower or same gm level
  534. m = map_mapname2mapid(map_name);
  535. if (m < 0) {
  536. clif_displaymessage(fd, msg_table[1]); // Map not found.
  537. return -1;
  538. } else {
  539. if (map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
  540. clif_displaymessage(fd, "You are not authorised to set this map as a save map.");
  541. return -1;
  542. }
  543. pc_setsavepoint(pl_sd, map[m].index, x, y);
  544. clif_displaymessage(fd, msg_table[57]); // Character's respawn point changed.
  545. }
  546. } else {
  547. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  548. return -1;
  549. }
  550. } else {
  551. clif_displaymessage(fd, msg_table[3]); // Character not found.
  552. return -1;
  553. }
  554. return 0;
  555. }
  556. /*==========================================
  557. *
  558. *------------------------------------------
  559. */
  560. //** Character Stats All by fritz
  561. int charcommand_stats_all(const int fd, struct map_session_data* sd, const char* command, const char* message)
  562. {
  563. char output[1024], gmlevel[1024];
  564. int i;
  565. int count, users;
  566. struct map_session_data *pl_sd, **pl_allsd;
  567. memset(output, '\0', sizeof(output));
  568. memset(gmlevel, '\0', sizeof(gmlevel));
  569. count = 0;
  570. pl_allsd = map_getallusers(&users);
  571. for(i = 0; i < users; i++) {
  572. if ((pl_sd = pl_allsd[i]))
  573. {
  574. if (pc_isGM(pl_sd) > 0)
  575. sprintf(gmlevel, "| GM Lvl: %d", pc_isGM(pl_sd));
  576. else
  577. sprintf(gmlevel, " ");
  578. sprintf(output, "Name: %s | BLvl: %d | Job: %s (Lvl: %d) | HP: %d/%d | SP: %d/%d", pl_sd->status.name, pl_sd->status.base_level, job_name(pl_sd->status.class_), pl_sd->status.job_level, pl_sd->status.hp, pl_sd->status.max_hp, pl_sd->status.sp, pl_sd->status.max_sp);
  579. clif_displaymessage(fd, output);
  580. sprintf(output, "STR: %d | AGI: %d | VIT: %d | INT: %d | DEX: %d | LUK: %d | Zeny: %d %s", pl_sd->status.str, pl_sd->status.agi, pl_sd->status.vit, pl_sd->status.int_, pl_sd->status.dex, pl_sd->status.luk, pl_sd->status.zeny, gmlevel);
  581. clif_displaymessage(fd, output);
  582. clif_displaymessage(fd, "--------");
  583. count++;
  584. }
  585. }
  586. if (count == 0)
  587. clif_displaymessage(fd, msg_table[28]); // No player found.
  588. else if (count == 1)
  589. clif_displaymessage(fd, msg_table[29]); // 1 player found.
  590. else {
  591. sprintf(output, msg_table[30], count); // %d players found.
  592. clif_displaymessage(fd, output);
  593. }
  594. return 0;
  595. }
  596. /*==========================================
  597. * CharSpiritBall Function by PalasX
  598. *------------------------------------------
  599. */
  600. int charcommand_spiritball(const int fd, struct map_session_data* sd,const char* command, const char* message)
  601. {
  602. struct map_session_data *pl_sd;
  603. char character[NAME_LENGTH];
  604. int spirit = 0;
  605. memset(character, '\0', sizeof(character));
  606. if(!message || !*message || sscanf(message, "%d %23[^\n]", &spirit, character) < 2 || spirit < 0 || spirit > 1000) {
  607. clif_displaymessage(fd, "Usage: @spiritball <number: 0-1000>) <CHARACTER_NAME>.");
  608. return -1;
  609. }
  610. if((pl_sd = map_nick2sd(character)) != NULL) {
  611. if (spirit >= 0 && spirit <= 0x7FFF) {
  612. if (pl_sd->spiritball != spirit || spirit > 999) {
  613. if (pl_sd->spiritball > 0)
  614. pc_delspiritball(pl_sd, pl_sd->spiritball, 1);
  615. pl_sd->spiritball = spirit;
  616. clif_spiritball(pl_sd);
  617. // no message, player can look the difference
  618. if (spirit > 1000)
  619. clif_displaymessage(fd, msg_table[204]); // WARNING: more than 1000 spiritballs can CRASH your server and/or client!
  620. } else {
  621. clif_displaymessage(fd, msg_table[205]); // You already have this number of spiritballs.
  622. return -1;
  623. }
  624. } else {
  625. clif_displaymessage(fd, msg_table[37]); // An invalid number was specified.
  626. return -1;
  627. }
  628. } else {
  629. clif_displaymessage(fd, msg_table[3]); // Character not found.
  630. return -1;
  631. }
  632. return 0;
  633. }
  634. /*==========================================
  635. * #itemlist <character>: Displays the list of a player's items.
  636. *------------------------------------------
  637. */
  638. int
  639. charcommand_itemlist(
  640. const int fd, struct map_session_data* sd,
  641. const char* command, const char* message)
  642. {
  643. struct map_session_data *pl_sd;
  644. struct item_data *item_data, *item_temp;
  645. int i, j, equip, count, counter, counter2;
  646. char character[NAME_LENGTH], output[200], equipstr[100], outputtmp[200];
  647. nullpo_retr(-1, sd);
  648. memset(character, '\0', sizeof(character));
  649. memset(output, '\0', sizeof(output));
  650. memset(equipstr, '\0', sizeof(equipstr));
  651. memset(outputtmp, '\0', sizeof(outputtmp));
  652. if (!message || !*message || sscanf(message, "%23[^\n]", character) < 1) {
  653. clif_displaymessage(fd, "Please, enter a player name (usage: #itemlist <char name>).");
  654. return -1;
  655. }
  656. if ((pl_sd = map_nick2sd(character)) != NULL) {
  657. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can look items only lower or same level
  658. counter = 0;
  659. count = 0;
  660. for (i = 0; i < MAX_INVENTORY; i++) {
  661. if (pl_sd->status.inventory[i].nameid > 0 && (item_data = itemdb_search(pl_sd->status.inventory[i].nameid)) != NULL) {
  662. counter = counter + pl_sd->status.inventory[i].amount;
  663. count++;
  664. if (count == 1) {
  665. sprintf(output, "------ Items list of '%s' ------", pl_sd->status.name);
  666. clif_displaymessage(fd, output);
  667. }
  668. if ((equip = pl_sd->status.inventory[i].equip)) {
  669. strcpy(equipstr, "| equiped: ");
  670. if (equip & 4)
  671. strcat(equipstr, "robe/gargment, ");
  672. if (equip & 8)
  673. strcat(equipstr, "left accessory, ");
  674. if (equip & 16)
  675. strcat(equipstr, "body/armor, ");
  676. if ((equip & 34) == 2)
  677. strcat(equipstr, "right hand, ");
  678. if ((equip & 34) == 32)
  679. strcat(equipstr, "left hand, ");
  680. if ((equip & 34) == 34)
  681. strcat(equipstr, "both hands, ");
  682. if (equip & 64)
  683. strcat(equipstr, "feet, ");
  684. if (equip & 128)
  685. strcat(equipstr, "right accessory, ");
  686. if ((equip & 769) == 1)
  687. strcat(equipstr, "lower head, ");
  688. if ((equip & 769) == 256)
  689. strcat(equipstr, "top head, ");
  690. if ((equip & 769) == 257)
  691. strcat(equipstr, "lower/top head, ");
  692. if ((equip & 769) == 512)
  693. strcat(equipstr, "mid head, ");
  694. if ((equip & 769) == 512)
  695. strcat(equipstr, "lower/mid head, ");
  696. if ((equip & 769) == 769)
  697. strcat(equipstr, "lower/mid/top head, ");
  698. // remove final ', '
  699. equipstr[strlen(equipstr) - 2] = '\0';
  700. } else
  701. memset(equipstr, '\0', sizeof(equipstr));
  702. if (sd->status.inventory[i].refine)
  703. sprintf(output, "%d %s %+d (%s %+d, id: %d) %s", pl_sd->status.inventory[i].amount, item_data->name, pl_sd->status.inventory[i].refine, item_data->jname, pl_sd->status.inventory[i].refine, pl_sd->status.inventory[i].nameid, equipstr);
  704. else
  705. sprintf(output, "%d %s (%s, id: %d) %s", pl_sd->status.inventory[i].amount, item_data->name, item_data->jname, pl_sd->status.inventory[i].nameid, equipstr);
  706. clif_displaymessage(fd, output);
  707. memset(output, '\0', sizeof(output));
  708. counter2 = 0;
  709. for (j = 0; j < item_data->slot; j++) {
  710. if (pl_sd->status.inventory[i].card[j]) {
  711. if ((item_temp = itemdb_search(pl_sd->status.inventory[i].card[j])) != NULL) {
  712. if (output[0] == '\0')
  713. sprintf(outputtmp, " -> (card(s): #%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
  714. else
  715. sprintf(outputtmp, "#%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
  716. strcat(output, outputtmp);
  717. }
  718. }
  719. }
  720. if (output[0] != '\0') {
  721. output[strlen(output) - 2] = ')';
  722. output[strlen(output) - 1] = '\0';
  723. clif_displaymessage(fd, output);
  724. }
  725. }
  726. }
  727. if (count == 0)
  728. clif_displaymessage(fd, "No item found on this player.");
  729. else {
  730. sprintf(output, "%d item(s) found in %d kind(s) of items.", counter, count);
  731. clif_displaymessage(fd, output);
  732. }
  733. } else {
  734. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  735. return -1;
  736. }
  737. } else {
  738. clif_displaymessage(fd, msg_table[3]); // Character not found.
  739. return -1;
  740. }
  741. return 0;
  742. }
  743. /*==========================================
  744. * #effect by [MouseJstr]
  745. *
  746. * Create a effect localized on another character
  747. *------------------------------------------
  748. */
  749. int
  750. charcommand_effect(const int fd, struct map_session_data* sd,
  751. const char* command, const char* message)
  752. {
  753. struct map_session_data *pl_sd = NULL;
  754. char target[255];
  755. int type = 0;
  756. nullpo_retr(-1, sd);
  757. if (!message || !*message || sscanf(message, "%d %s", &type, target) != 2) {
  758. clif_displaymessage(fd, "usage: #effect <type+> <target>.");
  759. return -1;
  760. }
  761. if((pl_sd=map_nick2sd((char *) target)) == NULL)
  762. return -1;
  763. clif_specialeffect(&pl_sd->bl, type, 0);
  764. clif_displaymessage(fd, msg_table[229]); // Your effect has changed.
  765. return 0;
  766. }
  767. /*==========================================
  768. * #storagelist <character>: Displays the items list of a player's storage.
  769. *------------------------------------------
  770. */
  771. int
  772. charcommand_storagelist(
  773. const int fd, struct map_session_data* sd,
  774. const char* command, const char* message)
  775. {
  776. struct storage *stor;
  777. struct map_session_data *pl_sd;
  778. struct item_data *item_data, *item_temp;
  779. int i, j, count, counter, counter2;
  780. char character[NAME_LENGTH], output[200], outputtmp[200];
  781. nullpo_retr(-1, sd);
  782. memset(character, '\0', sizeof(character));
  783. memset(output, '\0', sizeof(output));
  784. memset(outputtmp, '\0', sizeof(outputtmp));
  785. if (!message || !*message || sscanf(message, "%23[^\n]", character) < 1) {
  786. clif_displaymessage(fd, "Please, enter a player name (usage: #itemlist <char name>).");
  787. return -1;
  788. }
  789. if ((pl_sd = map_nick2sd(character)) != NULL) {
  790. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can look items only lower or same level
  791. if((stor = account2storage2(pl_sd->status.account_id)) != NULL) {
  792. counter = 0;
  793. count = 0;
  794. for (i = 0; i < MAX_STORAGE; i++) {
  795. if (stor->storage_[i].nameid > 0 && (item_data = itemdb_search(stor->storage_[i].nameid)) != NULL) {
  796. counter = counter + stor->storage_[i].amount;
  797. count++;
  798. if (count == 1) {
  799. sprintf(output, "------ Storage items list of '%s' ------", pl_sd->status.name);
  800. clif_displaymessage(fd, output);
  801. }
  802. if (stor->storage_[i].refine)
  803. sprintf(output, "%d %s %+d (%s %+d, id: %d)", stor->storage_[i].amount, item_data->name, stor->storage_[i].refine, item_data->jname, stor->storage_[i].refine, stor->storage_[i].nameid);
  804. else
  805. sprintf(output, "%d %s (%s, id: %d)", stor->storage_[i].amount, item_data->name, item_data->jname, stor->storage_[i].nameid);
  806. clif_displaymessage(fd, output);
  807. memset(output, '\0', sizeof(output));
  808. counter2 = 0;
  809. for (j = 0; j < item_data->slot; j++) {
  810. if (stor->storage_[i].card[j]) {
  811. if ((item_temp = itemdb_search(stor->storage_[i].card[j])) != NULL) {
  812. if (output[0] == '\0')
  813. sprintf(outputtmp, " -> (card(s): #%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
  814. else
  815. sprintf(outputtmp, "#%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
  816. strcat(output, outputtmp);
  817. }
  818. }
  819. }
  820. if (output[0] != '\0') {
  821. output[strlen(output) - 2] = ')';
  822. output[strlen(output) - 1] = '\0';
  823. clif_displaymessage(fd, output);
  824. }
  825. }
  826. }
  827. if (count == 0)
  828. clif_displaymessage(fd, "No item found in the storage of this player.");
  829. else {
  830. sprintf(output, "%d item(s) found in %d kind(s) of items.", counter, count);
  831. clif_displaymessage(fd, output);
  832. }
  833. } else {
  834. clif_displaymessage(fd, "This player has no storage.");
  835. return 0;
  836. }
  837. } else {
  838. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  839. return -1;
  840. }
  841. } else {
  842. clif_displaymessage(fd, msg_table[3]); // Character not found.
  843. return -1;
  844. }
  845. return 0;
  846. }
  847. static void
  848. charcommand_giveitem_sub(struct map_session_data *sd,struct item_data *item_data,int number)
  849. {
  850. int flag = 0;
  851. int loop = 1, get_count = number,i;
  852. struct item item_tmp;
  853. if(sd && item_data){
  854. if (item_data->type == 4 || item_data->type == 5 ||
  855. item_data->type == 7 || item_data->type == 8) {
  856. loop = number;
  857. get_count = 1;
  858. }
  859. for (i = 0; i < loop; i++) {
  860. memset(&item_tmp, 0, sizeof(item_tmp));
  861. item_tmp.nameid = item_data->nameid;
  862. item_tmp.identify = 1;
  863. if ((flag = pc_additem((struct map_session_data*)sd,
  864. &item_tmp, get_count)))
  865. clif_additem((struct map_session_data*)sd, 0, 0, flag);
  866. }
  867. //Logs (A)dmins items [Lupus]
  868. if(log_config.pick > 0 ) {
  869. log_pick(sd, "A", 0, item_tmp.nameid, number, &item_tmp);
  870. }
  871. //Logs
  872. }
  873. }
  874. /*==========================================
  875. * #item command (usage: #item <name/id_of_item> <quantity> <player>)
  876. * by MC Cameri
  877. *------------------------------------------
  878. */
  879. int charcommand_item(
  880. const int fd, struct map_session_data* sd,
  881. const char* command, const char* message)
  882. {
  883. char item_name[100];
  884. char character[NAME_LENGTH];
  885. struct map_session_data *pl_sd;
  886. int number = 0, item_id, flag;
  887. struct item item_tmp;
  888. struct item_data *item_data;
  889. int get_count, i, pet_id;
  890. char tmp_cmdoutput[1024];
  891. nullpo_retr(-1, sd);
  892. memset(item_name, '\0', sizeof(item_name));
  893. if (!message || !*message || sscanf(message, "%99s %d %23[^\n]", item_name, &number, character) < 3) {
  894. clif_displaymessage(fd, "Please, enter an item name/id (usage: #item <item name or ID> <quantity> <char name>).");
  895. return -1;
  896. }
  897. if (number <= 0)
  898. number = 1;
  899. item_id = 0;
  900. if ((item_data = itemdb_searchname(item_name)) != NULL ||
  901. (item_data = itemdb_exists(atoi(item_name))) != NULL)
  902. item_id = item_data->nameid;
  903. if (item_id >= 500) {
  904. get_count = number;
  905. // check pet egg
  906. pet_id = search_petDB_index(item_id, PET_EGG);
  907. if (item_data->type == 4 || item_data->type == 5 ||
  908. item_data->type == 7 || item_data->type == 8) {
  909. get_count = 1;
  910. }
  911. if ((pl_sd = map_nick2sd(character)) != NULL) {
  912. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can look items only lower or same level
  913. for (i = 0; i < number; i += get_count) {
  914. // if pet egg
  915. if (pet_id >= 0) {
  916. pl_sd->catch_target_class = pet_db[pet_id].class_;
  917. intif_create_pet(pl_sd->status.account_id, pl_sd->status.char_id,
  918. (short)pet_db[pet_id].class_, (short)mob_db(pet_db[pet_id].class_)->lv,
  919. (short)pet_db[pet_id].EggID, 0, (short)pet_db[pet_id].intimate,
  920. 100, 0, 1, pet_db[pet_id].jname);
  921. // if not pet egg
  922. } else {
  923. memset(&item_tmp, 0, sizeof(item_tmp));
  924. item_tmp.nameid = item_id;
  925. item_tmp.identify = 1;
  926. if ((flag = pc_additem(pl_sd, &item_tmp, get_count)))
  927. clif_additem(pl_sd, 0, 0, flag);
  928. }
  929. }
  930. //Logs (A)dmins items [Lupus]
  931. if(log_config.pick > 0 ) {
  932. log_pick(sd, "A", 0, item_tmp.nameid, number, &item_tmp);
  933. }
  934. //Logs
  935. clif_displaymessage(fd, msg_table[18]); // Item created.
  936. } else {
  937. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  938. return -1;
  939. }
  940. } else if(/* from jA's @giveitem */strcmpi(character,"all")==0 || strcmpi(character,"everyone")==0){
  941. struct map_session_data **pl_allsd;
  942. int users;
  943. pl_allsd = map_getallusers(&users);
  944. for (i = 0; i < users; i++) {
  945. if ((pl_sd = pl_allsd[i])) {
  946. charcommand_giveitem_sub(pl_sd,item_data,number);
  947. snprintf(tmp_cmdoutput, sizeof(tmp_cmdoutput), "You got %s %d.", item_name,number);
  948. clif_displaymessage(pl_sd->fd, tmp_cmdoutput);
  949. }
  950. }
  951. snprintf(tmp_cmdoutput, sizeof(tmp_cmdoutput), "%s received %s %d.","Everyone",item_name,number);
  952. clif_displaymessage(fd, tmp_cmdoutput);
  953. } else {
  954. clif_displaymessage(fd, msg_table[3]); // Character not found.
  955. return -1;
  956. }
  957. } else {
  958. clif_displaymessage(fd, msg_table[19]); // Invalid item ID or name.
  959. return -1;
  960. }
  961. return 0;
  962. }
  963. /*==========================================
  964. * #warp/#rura/#rura+ <mapname> <x> <y> <char name>
  965. *------------------------------------------
  966. */
  967. int charcommand_warp(
  968. const int fd, struct map_session_data* sd,
  969. const char* command, const char* message)
  970. {
  971. char map_name[MAP_NAME_LENGTH];
  972. char character[NAME_LENGTH];
  973. int x = 0, y = 0;
  974. struct map_session_data *pl_sd;
  975. int m;
  976. nullpo_retr(-1, sd);
  977. memset(map_name, '\0', sizeof(map_name));
  978. memset(character, '\0', sizeof(character));
  979. if (!message || !*message || sscanf(message, "%15s %d %d %23[^\n]", map_name, &x, &y, character) < 4) {
  980. clif_displaymessage(fd, "Usage: #warp/#rura/#rura+ <mapname> <x> <y> <char name>");
  981. return -1;
  982. }
  983. if (x <= 0)
  984. x = rand() % 399 + 1;
  985. if (y <= 0)
  986. y = rand() % 399 + 1;
  987. if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < MAP_NAME_LENGTH-4) // 16 - 4 (.gat)
  988. strcat(map_name, ".gat");
  989. if ((pl_sd = map_nick2sd(character)) != NULL) {
  990. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can rura+ only lower or same GM level
  991. if (x > 0 && x < 400 && y > 0 && y < 400) {
  992. m = map_mapname2mapid(map_name);
  993. if (m >= 0 && map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
  994. clif_displaymessage(fd, "You are not authorised to warp someone to this map.");
  995. return -1;
  996. }
  997. if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
  998. clif_displaymessage(fd, "You are not authorised to warp this player from its actual map.");
  999. return -1;
  1000. }
  1001. if (pc_setpos(pl_sd, map[m].index, x, y, 3) == 0) {
  1002. clif_displaymessage(pl_sd->fd, msg_table[0]); // Warped.
  1003. clif_displaymessage(fd, msg_table[15]); // Player warped (message sends to player too).
  1004. } else {
  1005. clif_displaymessage(fd, msg_table[1]); // Map not found.
  1006. return -1;
  1007. }
  1008. } else {
  1009. clif_displaymessage(fd, msg_table[2]); // Coordinates out of range.
  1010. return -1;
  1011. }
  1012. } else {
  1013. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  1014. return -1;
  1015. }
  1016. } else {
  1017. clif_displaymessage(fd, msg_table[3]); // Character not found.
  1018. return -1;
  1019. }
  1020. return 0;
  1021. }
  1022. /*==========================================
  1023. * #zeny <charname>
  1024. *------------------------------------------
  1025. */
  1026. int charcommand_zeny(
  1027. const int fd, struct map_session_data* sd,
  1028. const char* command, const char* message)
  1029. {
  1030. struct map_session_data *pl_sd;
  1031. char character[NAME_LENGTH];
  1032. int zeny = 0, new_zeny;
  1033. nullpo_retr(-1, sd);
  1034. memset(character, '\0', sizeof(character));
  1035. if (!message || !*message || sscanf(message, "%d %23[^\n]", &zeny, character) < 2 || zeny == 0) {
  1036. clif_displaymessage(fd, "Please, enter a number and a player name (usage: #zeny <zeny> <name>).");
  1037. return -1;
  1038. }
  1039. if ((pl_sd = map_nick2sd(character)) != NULL) {
  1040. new_zeny = pl_sd->status.zeny + zeny;
  1041. if (zeny > 0 && (zeny > MAX_ZENY || new_zeny > MAX_ZENY)) // fix positiv overflow
  1042. new_zeny = MAX_ZENY;
  1043. else if (zeny < 0 && (zeny < -MAX_ZENY || new_zeny < 0)) // fix negativ overflow
  1044. new_zeny = 0;
  1045. if (new_zeny != pl_sd->status.zeny) {
  1046. pl_sd->status.zeny = new_zeny;
  1047. clif_updatestatus(pl_sd, SP_ZENY);
  1048. clif_displaymessage(fd, msg_table[211]); // Character's number of zenys changed!
  1049. } else {
  1050. if (zeny < 0)
  1051. clif_displaymessage(fd, msg_table[41]); // Impossible to decrease the number/value.
  1052. else
  1053. clif_displaymessage(fd, msg_table[149]); // Impossible to increase the number/value.
  1054. return -1;
  1055. }
  1056. } else {
  1057. clif_displaymessage(fd, msg_table[3]); // Character not found.
  1058. return -1;
  1059. }
  1060. return 0;
  1061. }
  1062. /*==========================================
  1063. * #fakename <char name> <fake name>
  1064. *------------------------------------------
  1065. */
  1066. int charcommand_fakename(
  1067. const int fd, struct map_session_data* sd,
  1068. const char* command, const char* message)
  1069. {
  1070. struct map_session_data *pl_sd;
  1071. char name[NAME_LENGTH];
  1072. char char_name[NAME_LENGTH];
  1073. nullpo_retr(-1, sd);
  1074. name[0] = '\0'; //If you don't pass a second word, name is left as garbage, most definitely not a blank name! [Skotlex]
  1075. if (!message || !*message || sscanf(message, "%23s %23[^\n]", char_name, name) < 1) {
  1076. clif_displaymessage(sd->fd,"Usage: #fakename <char name> <fake name>.");
  1077. clif_displaymessage(sd->fd,"Or: #fakename <char name> to disable.");
  1078. return 0;
  1079. }
  1080. if(!(pl_sd = map_nick2sd(char_name))) {
  1081. clif_displaymessage(sd->fd,"Character not found.");
  1082. return -1;
  1083. }
  1084. if(strlen(name) < 1 || !name) {
  1085. if(strlen(pl_sd->fakename) > 1) {
  1086. pl_sd->fakename[0]='\0';
  1087. pc_setpos(pl_sd, pl_sd->mapindex, pl_sd->bl.x, sd->bl.y, 3);
  1088. clif_displaymessage(sd->fd,"Returned to real name.");
  1089. } else {
  1090. clif_displaymessage(sd->fd,"Character does not has a fake name.");
  1091. }
  1092. return 0;
  1093. }
  1094. if(strlen(name) < 2) {
  1095. clif_displaymessage(sd->fd,"Fake name must be at least two characters.");
  1096. return 0;
  1097. }
  1098. memcpy(pl_sd->fakename,name, NAME_LENGTH-1);
  1099. pc_setpos(pl_sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, 3);
  1100. clif_displaymessage(sd->fd,"Fake name enabled.");
  1101. return 0;
  1102. }
  1103. /*==========================================
  1104. * #baselvl <#> <nickname>
  1105. * Transferred by: Kevin
  1106. *------------------------------------------
  1107. */
  1108. int charcommand_baselevel(
  1109. const int fd, struct map_session_data* sd,
  1110. const char* command, const char* message)
  1111. {
  1112. struct map_session_data *pl_sd;
  1113. char player[NAME_LENGTH];
  1114. int level = 0, i;
  1115. nullpo_retr(-1, sd);
  1116. if (!message || !*message || sscanf(message, "%d %23[^\n]", &level, player) < 2 || level == 0) {
  1117. clif_displaymessage(fd, "Please, enter a level adjustement and a player name (usage: #baselvl <#> <nickname>).");
  1118. return -1;
  1119. }
  1120. if ((pl_sd = map_nick2sd(player)) != NULL) {
  1121. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change base level only lower or same gm level
  1122. if (level > 0) {
  1123. if (pl_sd->status.base_level == pc_maxbaselv(sd)) { // check for max level by Valaris
  1124. clif_displaymessage(fd, msg_table[91]); // Character's base level can't go any higher.
  1125. return 0;
  1126. } // End Addition
  1127. if ((unsigned int)level > pc_maxbaselv(pl_sd) ||
  1128. pl_sd->status.base_level > pc_maxbaselv(pl_sd) -level)
  1129. level = pc_maxbaselv(pl_sd) - pl_sd->status.base_level;
  1130. for (i = 1; i <= level; i++)
  1131. pl_sd->status.status_point += (pl_sd->status.base_level + i + 14) / 5;
  1132. pl_sd->status.base_level += (unsigned int)level;
  1133. clif_updatestatus(pl_sd, SP_BASELEVEL);
  1134. clif_updatestatus(pl_sd, SP_NEXTBASEEXP);
  1135. clif_updatestatus(pl_sd, SP_STATUSPOINT);
  1136. status_calc_pc(pl_sd, 0);
  1137. pc_heal(pl_sd, pl_sd->status.max_hp, pl_sd->status.max_sp);
  1138. clif_misceffect(&pl_sd->bl, 0);
  1139. clif_displaymessage(fd, msg_table[65]); // Character's base level raised.
  1140. } else {
  1141. if (pl_sd->status.base_level == 1) {
  1142. clif_displaymessage(fd, msg_table[193]); // Character's base level can't go any lower.
  1143. return -1;
  1144. }
  1145. level *= -1;
  1146. if ((unsigned int)level >= pl_sd->status.base_level)
  1147. level = pl_sd->status.base_level -1;
  1148. if (pl_sd->status.status_point > 0) {
  1149. for (i = 0; i > -level; i--)
  1150. pl_sd->status.status_point -= (pl_sd->status.base_level +i + 14) / 5;
  1151. if (pl_sd->status.status_point < 0)
  1152. pl_sd->status.status_point = 0;
  1153. clif_updatestatus(pl_sd, SP_STATUSPOINT);
  1154. } // to add: remove status points from stats
  1155. pl_sd->status.base_level -= (unsigned int)level;
  1156. clif_updatestatus(pl_sd, SP_BASELEVEL);
  1157. clif_updatestatus(pl_sd, SP_NEXTBASEEXP);
  1158. status_calc_pc(pl_sd, 0);
  1159. clif_displaymessage(fd, msg_table[66]); // Character's base level lowered.
  1160. }
  1161. } else {
  1162. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  1163. return -1;
  1164. }
  1165. } else {
  1166. clif_displaymessage(fd, msg_table[3]); // Character not found.
  1167. return -1;
  1168. }
  1169. return 0; //正常終了
  1170. }
  1171. /*==========================================
  1172. * #jlvl <#> <nickname>
  1173. * Transferred by: Kevin
  1174. *------------------------------------------
  1175. */
  1176. int charcommand_joblevel(
  1177. const int fd, struct map_session_data* sd,
  1178. const char* command, const char* message)
  1179. {
  1180. struct map_session_data *pl_sd;
  1181. char player[NAME_LENGTH];
  1182. int level = 0;
  1183. //転生や養子の場合の元の職業を算出する
  1184. nullpo_retr(-1, sd);
  1185. if (!message || !*message || sscanf(message, "%d %23[^\n]", &level, player) < 2 || level == 0) {
  1186. clif_displaymessage(fd, "Please, enter a level adjustement and a player name (usage: #joblvl <#> <nickname>).");
  1187. return -1;
  1188. }
  1189. if ((pl_sd = map_nick2sd(player)) != NULL) {
  1190. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change job level only lower or same gm level
  1191. if (level > 0) {
  1192. if (pl_sd->status.job_level == pc_maxjoblv(pl_sd)) {
  1193. clif_displaymessage(fd, msg_table[67]); // Character's job level can't go any higher.
  1194. return -1;
  1195. }
  1196. if ((unsigned int)level > pc_maxjoblv(pl_sd) ||
  1197. pl_sd->status.job_level > pc_maxjoblv(pl_sd) -level)
  1198. level = pc_maxjoblv(pl_sd) - pl_sd->status.job_level;
  1199. pl_sd->status.job_level += (unsigned int)level;
  1200. clif_updatestatus(pl_sd, SP_JOBLEVEL);
  1201. clif_updatestatus(pl_sd, SP_NEXTJOBEXP);
  1202. pl_sd->status.skill_point += level;
  1203. clif_updatestatus(pl_sd, SP_SKILLPOINT);
  1204. status_calc_pc(pl_sd, 0);
  1205. clif_misceffect(&pl_sd->bl, 1);
  1206. clif_displaymessage(fd, msg_table[68]); // character's job level raised.
  1207. } else {
  1208. if (pl_sd->status.job_level == 1) {
  1209. clif_displaymessage(fd, msg_table[194]); // Character's job level can't go any lower.
  1210. return -1;
  1211. }
  1212. level*=-1;
  1213. if ((unsigned int)level >= pl_sd->status.job_level)
  1214. level = pl_sd->status.job_level-1;
  1215. pl_sd->status.job_level -= (unsigned int)level;
  1216. clif_updatestatus(pl_sd, SP_JOBLEVEL);
  1217. clif_updatestatus(pl_sd, SP_NEXTJOBEXP);
  1218. if (pl_sd->status.skill_point < level)
  1219. pc_resetskill(pl_sd, 0); //Need more skill points to substract
  1220. pl_sd->status.skill_point -= level;
  1221. if (pl_sd->status.skill_point < 0)
  1222. pl_sd->status.skill_point = 0;
  1223. clif_updatestatus(pl_sd, SP_SKILLPOINT);
  1224. status_calc_pc(pl_sd, 0);
  1225. clif_displaymessage(fd, msg_table[69]); // Character's job level lowered.
  1226. }
  1227. } else {
  1228. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  1229. return -1;
  1230. }
  1231. } else {
  1232. clif_displaymessage(fd, msg_table[3]); // Character not found.
  1233. return -1;
  1234. }
  1235. return 0;
  1236. }
  1237. /*==========================================
  1238. * #questskill <skill_#> <nickname>
  1239. * Transferred by: Kevin
  1240. *------------------------------------------
  1241. */
  1242. int charcommand_questskill(
  1243. const int fd, struct map_session_data* sd,
  1244. const char* command, const char* message)
  1245. {
  1246. struct map_session_data *pl_sd;
  1247. char player[NAME_LENGTH];
  1248. int skill_id = 0;
  1249. nullpo_retr(-1, sd);
  1250. if (!message || !*message || sscanf(message, "%d %23[^\n]", &skill_id, player) < 2 || skill_id < 0) {
  1251. clif_displaymessage(fd, "Please, enter a quest skill number and a player name (usage: #questskill <#:0+> <nickname>).");
  1252. return -1;
  1253. }
  1254. if (skill_id >= 0 && skill_id < MAX_SKILL_DB) {
  1255. if (skill_get_inf2(skill_id) & INF2_QUEST_SKILL) {
  1256. if ((pl_sd = map_nick2sd(player)) != NULL) {
  1257. if (pc_checkskill(pl_sd, skill_id) == 0) {
  1258. pc_skill(pl_sd, skill_id, 1, 0);
  1259. clif_displaymessage(fd, msg_table[199]); // This player has learned the skill.
  1260. } else {
  1261. clif_displaymessage(fd, msg_table[200]); // This player already has this quest skill.
  1262. return -1;
  1263. }
  1264. } else {
  1265. clif_displaymessage(fd, msg_table[3]); // Character not found.
  1266. return -1;
  1267. }
  1268. } else {
  1269. clif_displaymessage(fd, msg_table[197]); // This skill number doesn't exist or isn't a quest skill.
  1270. return -1;
  1271. }
  1272. } else {
  1273. clif_displaymessage(fd, msg_table[198]); // This skill number doesn't exist.
  1274. return -1;
  1275. }
  1276. return 0;
  1277. }
  1278. /*==========================================
  1279. * #lostskill <skill_#> <nickname>
  1280. * Transferred by: Kevin
  1281. *------------------------------------------
  1282. */
  1283. int charcommand_lostskill(
  1284. const int fd, struct map_session_data* sd,
  1285. const char* command, const char* message)
  1286. {
  1287. struct map_session_data *pl_sd;
  1288. char player[NAME_LENGTH];
  1289. int skill_id = 0;
  1290. nullpo_retr(-1, sd);
  1291. if (!message || !*message || sscanf(message, "%d %23[^\n]", &skill_id, player) < 2 || skill_id < 0) {
  1292. clif_displaymessage(fd, "Please, enter a quest skill number and a player name (usage: @charlostskill <#:0+> <char_name>).");
  1293. return -1;
  1294. }
  1295. if (skill_id >= 0 && skill_id < MAX_SKILL) {
  1296. if (skill_get_inf2(skill_id) & INF2_QUEST_SKILL) {
  1297. if ((pl_sd = map_nick2sd(player)) != NULL) {
  1298. if (pc_checkskill(pl_sd, skill_id) > 0) {
  1299. pl_sd->status.skill[skill_id].lv = 0;
  1300. pl_sd->status.skill[skill_id].flag = 0;
  1301. clif_skillinfoblock(pl_sd);
  1302. clif_displaymessage(fd, msg_table[202]); // This player has forgotten the skill.
  1303. } else {
  1304. clif_displaymessage(fd, msg_table[203]); // This player doesn't have this quest skill.
  1305. return -1;
  1306. }
  1307. } else {
  1308. clif_displaymessage(fd, msg_table[3]); // Character not found.
  1309. return -1;
  1310. }
  1311. } else {
  1312. clif_displaymessage(fd, msg_table[197]); // This skill number doesn't exist or isn't a quest skill.
  1313. return -1;
  1314. }
  1315. } else {
  1316. clif_displaymessage(fd, msg_table[198]); // This skill number doesn't exist.
  1317. return -1;
  1318. }
  1319. return 0;
  1320. }
  1321. /*==========================================
  1322. * Character Skill Reset
  1323. *------------------------------------------
  1324. */
  1325. int charcommand_skreset(
  1326. const int fd, struct map_session_data* sd,
  1327. const char* command, const char* message)
  1328. {
  1329. struct map_session_data *pl_sd;
  1330. char player[NAME_LENGTH];
  1331. char tmp_cmdoutput[1024];
  1332. nullpo_retr(-1, sd);
  1333. if (!message || !*message || sscanf(message, "%23[^\n]", player) < 1) {
  1334. clif_displaymessage(fd, "Please, enter a player name (usage: @charskreset <charname>).");
  1335. return -1;
  1336. }
  1337. if ((pl_sd = map_nick2sd(player)) != NULL) {
  1338. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can reset skill points only lower or same gm level
  1339. pc_resetskill(pl_sd,1);
  1340. sprintf(tmp_cmdoutput, msg_table[206], player); // '%s' skill points reseted!
  1341. clif_displaymessage(fd, tmp_cmdoutput);
  1342. } else {
  1343. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  1344. return -1;
  1345. }
  1346. } else {
  1347. clif_displaymessage(fd, msg_table[3]); // Character not found.
  1348. return -1;
  1349. }
  1350. return 0;
  1351. }
  1352. /*==========================================
  1353. * Character Stat Reset
  1354. *------------------------------------------
  1355. */
  1356. int charcommand_streset(
  1357. const int fd, struct map_session_data* sd,
  1358. const char* command, const char* message)
  1359. {
  1360. struct map_session_data *pl_sd;
  1361. char player[NAME_LENGTH];
  1362. char tmp_cmdoutput[1024];
  1363. nullpo_retr(-1, sd);
  1364. if (!message || !*message || sscanf(message, "%23[^\n]", player) < 1) {
  1365. clif_displaymessage(fd, "Please, enter a player name (usage: @charstreset <charname>).");
  1366. return -1;
  1367. }
  1368. if ((pl_sd = map_nick2sd(player)) != NULL) {
  1369. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can reset stats points only lower or same gm level
  1370. pc_resetstate(pl_sd);
  1371. sprintf(tmp_cmdoutput, msg_table[207], player); // '%s' stats points reseted!
  1372. clif_displaymessage(fd, tmp_cmdoutput);
  1373. } else {
  1374. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  1375. return -1;
  1376. }
  1377. } else {
  1378. clif_displaymessage(fd, msg_table[3]); // Character not found.
  1379. return -1;
  1380. }
  1381. return 0;
  1382. }
  1383. /*==========================================
  1384. * Character Model by chbrules
  1385. *------------------------------------------
  1386. */
  1387. int charcommand_model(
  1388. const int fd, struct map_session_data* sd,
  1389. const char* command, const char* message)
  1390. {
  1391. int hair_style = 0, hair_color = 0, cloth_color = 0;
  1392. struct map_session_data *pl_sd;
  1393. char player[NAME_LENGTH];
  1394. char tmp_cmdoutput[1024];
  1395. nullpo_retr(-1, sd);
  1396. if (!message || !*message || sscanf(message, "%d %d %d %23[^\n]", &hair_style, &hair_color, &cloth_color, player) < 4 || hair_style < 0 || hair_color < 0 || cloth_color < 0) {
  1397. sprintf(tmp_cmdoutput, "Please, enter a valid model and a player name (usage: @charmodel <hair ID: %d-%d> <hair color: %d-%d> <clothes color: %d-%d> <name>).",
  1398. MIN_HAIR_STYLE, MAX_HAIR_STYLE, MIN_HAIR_COLOR, MAX_HAIR_COLOR, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR);
  1399. clif_displaymessage(fd, tmp_cmdoutput);
  1400. return -1;
  1401. }
  1402. if ((pl_sd = map_nick2sd(player)) != NULL) {
  1403. if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE &&
  1404. hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR &&
  1405. cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) {
  1406. /* Removed this check for being too strange. [Skotlex]
  1407. if (cloth_color != 0 &&
  1408. pl_sd->status.sex == 1 &&
  1409. (pl_sd->status.class_ == JOB_ASSASSIN || pl_sd->status.class_ == JOB_ROGUE)) {
  1410. clif_displaymessage(fd, msg_table[35]); // You can't use this command with this class.
  1411. return -1;
  1412. } else {
  1413. */
  1414. pc_changelook(pl_sd, LOOK_HAIR, hair_style);
  1415. pc_changelook(pl_sd, LOOK_HAIR_COLOR, hair_color);
  1416. pc_changelook(pl_sd, LOOK_CLOTHES_COLOR, cloth_color);
  1417. clif_displaymessage(fd, msg_table[36]); // Appearence changed.
  1418. // }
  1419. } else {
  1420. clif_displaymessage(fd, msg_table[37]); // An invalid number was specified.
  1421. return -1;
  1422. }
  1423. } else {
  1424. clif_displaymessage(fd, msg_table[3]); // Character not found.
  1425. return -1;
  1426. }
  1427. return 0;
  1428. }
  1429. /*==========================================
  1430. * Character Skill Point (Rewritten by [Yor])
  1431. *------------------------------------------
  1432. */
  1433. int charcommand_skpoint(
  1434. const int fd, struct map_session_data* sd,
  1435. const char* command, const char* message)
  1436. {
  1437. struct map_session_data *pl_sd;
  1438. char player[NAME_LENGTH];
  1439. int new_skill_point;
  1440. int point = 0;
  1441. nullpo_retr(-1, sd);
  1442. if (!message || !*message || sscanf(message, "%d %23[^\n]", &point, player) < 2 || point == 0) {
  1443. clif_displaymessage(fd, "Please, enter a number and a player name (usage: @charskpoint <amount> <name>).");
  1444. return -1;
  1445. }
  1446. if ((pl_sd = map_nick2sd(player)) != NULL) {
  1447. new_skill_point = (int)pl_sd->status.skill_point + point;
  1448. if (point > 0 && (point > 0x7FFF || new_skill_point > 0x7FFF)) // fix positiv overflow
  1449. new_skill_point = 0x7FFF;
  1450. else if (point < 0 && (point < -0x7FFF || new_skill_point < 0)) // fix negativ overflow
  1451. new_skill_point = 0;
  1452. if (new_skill_point != (int)pl_sd->status.skill_point) {
  1453. pl_sd->status.skill_point = new_skill_point;
  1454. clif_updatestatus(pl_sd, SP_SKILLPOINT);
  1455. clif_displaymessage(fd, msg_table[209]); // Character's number of skill points changed!
  1456. } else {
  1457. if (point < 0)
  1458. clif_displaymessage(fd, msg_table[41]); // Impossible to decrease the number/value.
  1459. else
  1460. clif_displaymessage(fd, msg_table[149]); // Impossible to increase the number/value.
  1461. return -1;
  1462. }
  1463. } else {
  1464. clif_displaymessage(fd, msg_table[3]); // Character not found.
  1465. return -1;
  1466. }
  1467. return 0;
  1468. }
  1469. /*==========================================
  1470. * Character Status Point (rewritten by [Yor])
  1471. *------------------------------------------
  1472. */
  1473. int charcommand_stpoint(
  1474. const int fd, struct map_session_data* sd,
  1475. const char* command, const char* message)
  1476. {
  1477. struct map_session_data *pl_sd;
  1478. char player[NAME_LENGTH];
  1479. int new_status_point;
  1480. int point = 0;
  1481. nullpo_retr(-1, sd);
  1482. if (!message || !*message || sscanf(message, "%d %23[^\n]", &point, player) < 2 || point == 0) {
  1483. clif_displaymessage(fd, "Please, enter a number and a player name (usage: @charstpoint <amount> <name>).");
  1484. return -1;
  1485. }
  1486. if ((pl_sd = map_nick2sd(player)) != NULL) {
  1487. new_status_point = (int)pl_sd->status.status_point + point;
  1488. if (point > 0 && (point > 0x7FFF || new_status_point > 0x7FFF)) // fix positiv overflow
  1489. new_status_point = 0x7FFF;
  1490. else if (point < 0 && (point < -0x7FFF || new_status_point < 0)) // fix negativ overflow
  1491. new_status_point = 0;
  1492. if (new_status_point != (int)pl_sd->status.status_point) {
  1493. pl_sd->status.status_point = new_status_point;
  1494. clif_updatestatus(pl_sd, SP_STATUSPOINT);
  1495. clif_displaymessage(fd, msg_table[210]); // Character's number of status points changed!
  1496. } else {
  1497. if (point < 0)
  1498. clif_displaymessage(fd, msg_table[41]); // Impossible to decrease the number/value.
  1499. else
  1500. clif_displaymessage(fd, msg_table[149]); // Impossible to increase the number/value.
  1501. return -1;
  1502. }
  1503. } else {
  1504. clif_displaymessage(fd, msg_table[3]); // Character not found.
  1505. return -1;
  1506. }
  1507. return 0;
  1508. }
  1509. /*==========================================
  1510. * charchangesex command (usage: charchangesex <player_name>)
  1511. *------------------------------------------
  1512. */
  1513. int charcommand_changesex(
  1514. const int fd, struct map_session_data* sd,
  1515. const char* command, const char* message)
  1516. {
  1517. char player[NAME_LENGTH];
  1518. nullpo_retr(-1, sd);
  1519. if (!message || !*message || sscanf(message, "%23[^\n]", player) < 1) {
  1520. clif_displaymessage(fd, "Please, enter a player name (usage: @charchangesex <name>).");
  1521. return -1;
  1522. }
  1523. // check player name
  1524. if (strlen(player) < 4) {
  1525. clif_displaymessage(fd, msg_table[86]); // Sorry, but a player name have at least 4 characters.
  1526. return -1;
  1527. } else if (strlen(player) > 23) {
  1528. clif_displaymessage(fd, msg_table[87]); // Sorry, but a player name have 23 characters maximum.
  1529. return -1;
  1530. } else {
  1531. chrif_char_ask_name(sd->status.account_id, player, 5, 0, 0, 0, 0, 0, 0); // type: 5 - changesex
  1532. clif_displaymessage(fd, msg_table[88]); // Character name sends to char-server to ask it.
  1533. }
  1534. return 0;
  1535. }
  1536. /*==========================================
  1537. * Feel (SG save map) Reset
  1538. *------------------------------------------
  1539. */
  1540. int charcommand_feelreset(
  1541. const int fd, struct map_session_data* sd,
  1542. const char* command, const char* message)
  1543. {
  1544. char character[NAME_LENGTH];
  1545. char output[200];
  1546. struct map_session_data *pl_sd;
  1547. memset(character, '\0', sizeof(character));
  1548. memset(output, '\0', sizeof(output));
  1549. if (!message || !*message || sscanf(message, "%23[^\n]", character) < 1) {
  1550. clif_displaymessage(fd, "Please, enter a player name (usage: #feelreset <charname>).");
  1551. return -1;
  1552. }
  1553. if ((pl_sd = map_nick2sd(character)) != NULL) {
  1554. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can reset a character only for lower or same GM level
  1555. pc_resetfeel(pl_sd);
  1556. sprintf(output, msg_table[267], character); // '%s' designated maps reseted!
  1557. clif_displaymessage(fd, output);
  1558. } else {
  1559. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  1560. return -1;
  1561. }
  1562. } else {
  1563. clif_displaymessage(fd, msg_table[3]); // Character not found.
  1564. return -1;
  1565. }
  1566. return 0;
  1567. }
  1568. /*==========================================
  1569. * #help - Char commands [Kayla]
  1570. *------------------------------------------
  1571. */
  1572. int charcommand_help(
  1573. const int fd, struct map_session_data* sd,
  1574. const char* command, const char* message)
  1575. {
  1576. char buf[2048], w1[2048], w2[2048];
  1577. int i, gm_level;
  1578. FILE* fp;
  1579. nullpo_retr(-1, sd);
  1580. memset(buf, '\0', sizeof(buf));
  1581. if ((fp = fopen(charhelp_txt, "r")) != NULL) {
  1582. clif_displaymessage(fd, msg_table[26]); /* Help commands: */
  1583. gm_level = pc_isGM(sd);
  1584. while(fgets(buf, sizeof(buf) - 1, fp) != NULL) {
  1585. if (buf[0] == '/' && buf[1] == '/')
  1586. continue;
  1587. for (i = 0; buf[i] != '\0'; i++) {
  1588. if (buf[i] == '\r' || buf[i] == '\n') {
  1589. buf[i] = '\0';
  1590. break;
  1591. }
  1592. }
  1593. if (sscanf(buf, "%2047[^:]:%2047[^\n]", w1, w2) < 2)
  1594. clif_displaymessage(fd, buf);
  1595. else if (gm_level >= atoi(w1))
  1596. clif_displaymessage(fd, w2);
  1597. }
  1598. fclose(fp);
  1599. } else {
  1600. clif_displaymessage(fd, msg_table[27]); /* File help.txt not found. */
  1601. return -1;
  1602. }
  1603. return 0;
  1604. }