charcommand.c 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <math.h>
  6. #include "../common/socket.h"
  7. #include "../common/timer.h"
  8. #include "../common/nullpo.h"
  9. #include "log.h"
  10. #include "clif.h"
  11. #include "chrif.h"
  12. #include "intif.h"
  13. #include "itemdb.h"
  14. #include "map.h"
  15. #include "pc.h"
  16. #include "skill.h"
  17. #include "mob.h"
  18. #include "pet.h"
  19. #include "battle.h"
  20. #include "party.h"
  21. #include "guild.h"
  22. #include "charcommand.h"
  23. #include "atcommand.h"
  24. #include "script.h"
  25. #include "npc.h"
  26. #include "trade.h"
  27. #include "core.h"
  28. static char command_symbol = '#';
  29. extern char msg_table[1000][256]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others)
  30. #define CCMD_FUNC(x) int charcommand_ ## x (const int fd, struct map_session_data* sd, const char* command, const char* message)
  31. CCMD_FUNC(jobchange);
  32. CCMD_FUNC(petrename);
  33. CCMD_FUNC(petfriendly);
  34. CCMD_FUNC(stats);
  35. CCMD_FUNC(option);
  36. CCMD_FUNC(save);
  37. CCMD_FUNC(stats_all);
  38. CCMD_FUNC(reset);
  39. CCMD_FUNC(spiritball);
  40. CCMD_FUNC(itemlist);
  41. CCMD_FUNC(effect);
  42. CCMD_FUNC(storagelist);
  43. CCMD_FUNC(item);
  44. CCMD_FUNC(warp);
  45. CCMD_FUNC(zeny);
  46. #ifdef TXT_ONLY
  47. /* TXT_ONLY */
  48. /* TXT_ONLY */
  49. #else
  50. /* SQL-only */
  51. /* SQL Only */
  52. #endif
  53. /*==========================================
  54. *CharCommandInfo charcommand_info[]構造体の定義
  55. *------------------------------------------
  56. */
  57. // First char of commands is configured in charcommand_athena.conf. Leave @ in this list for default value.
  58. // to set default level, read charcommand_athena.conf first please.
  59. static CharCommandInfo charcommand_info[] = {
  60. { CharCommandJobChange, "#job", 60, charcommand_jobchange },
  61. { CharCommandJobChange, "#jobchange", 60, charcommand_jobchange },
  62. { CharCommandPetRename, "#petrename", 50, charcommand_petrename },
  63. { CharCommandPetFriendly, "#petfriendly", 50, charcommand_petfriendly },
  64. { CharCommandStats, "#stats", 40, charcommand_stats },
  65. { CharCommandOption, "#option", 60, charcommand_option },
  66. { CharCommandReset, "#reset", 60, charcommand_reset },
  67. { CharCommandSave, "#save", 60, charcommand_save },
  68. { CharCommandStatsAll, "#statsall", 40, charcommand_stats_all },
  69. { CharCommandSpiritball, "#spiritball", 40, charcommand_spiritball },
  70. { CharCommandItemList, "#itemlist", 40, charcommand_itemlist },
  71. { CharCommandEffect, "#effect", 40, charcommand_effect },
  72. { CharCommandStorageList, "#storagelist", 40, charcommand_storagelist },
  73. { CharCommandItem, "#item", 60, charcommand_item },
  74. { CharCommandWarp, "#warp", 60, charcommand_warp },
  75. { CharCommandWarp, "#rura", 60, charcommand_warp },
  76. { CharCommandWarp, "#rura+", 60, charcommand_warp },
  77. { CharCommandZeny, "#zeny", 60, charcommand_zeny },
  78. #ifdef TXT_ONLY
  79. /* TXT_ONLY */
  80. /* TXT_ONLY */
  81. #else
  82. /* SQL-only */
  83. /* SQL Only */
  84. #endif
  85. // add new commands before this line
  86. { CharCommand_Unknown, NULL, 1, NULL }
  87. };
  88. int get_charcommand_level(const CharCommandType type) {
  89. int i;
  90. for (i = 0; charcommand_info[i].type != CharCommand_None; i++)
  91. if (charcommand_info[i].type == type)
  92. return charcommand_info[i].level;
  93. return 100; // 100: command can not be used
  94. }
  95. /*==========================================
  96. *is_charcommand @コマンドに存在するかどうか確認する
  97. *------------------------------------------
  98. */
  99. CharCommandType
  100. is_charcommand(const int fd, struct map_session_data* sd, const char* message, int gmlvl) {
  101. const char* str = message;
  102. int s_flag = 0;
  103. CharCommandInfo info;
  104. CharCommandType type;
  105. nullpo_retr(CharCommand_None, sd);
  106. if (!message || !*message)
  107. return CharCommand_None;
  108. memset(&info, 0, sizeof(info));
  109. str += strlen(sd->status.name);
  110. while (*str && (isspace(*str) || (s_flag == 0 && *str == ':'))) {
  111. if (*str == ':')
  112. s_flag = 1;
  113. str++;
  114. }
  115. if (!*str)
  116. return CharCommand_None;
  117. type = charcommand(gmlvl > 0 ? gmlvl : pc_isGM(sd), str, &info);
  118. if (type != CharCommand_None) {
  119. char command[100];
  120. char output[200];
  121. const char* p = str;
  122. memset(command, '\0', sizeof(command));
  123. memset(output, '\0', sizeof(output));
  124. while (*p && !isspace(*p))
  125. p++;
  126. if (p - str >= sizeof(command)) // too long
  127. return CharCommand_Unknown;
  128. strncpy(command, str, p - str);
  129. while (isspace(*p))
  130. p++;
  131. if (type == CharCommand_Unknown || info.proc == NULL) {
  132. snprintf(output, sizeof(output),msg_txt(153), command); // %s is Unknown Command.
  133. clif_displaymessage(fd, output);
  134. } else {
  135. if (info.proc(fd, sd, command, p) != 0) {
  136. // Command can not be executed
  137. snprintf(output, sizeof(output), msg_txt(154), command); // %s failed.
  138. clif_displaymessage(fd, output);
  139. }
  140. }
  141. return info.type;
  142. }
  143. return CharCommand_None;
  144. }
  145. /*==========================================
  146. *
  147. *------------------------------------------
  148. */
  149. CharCommandType charcommand(const int level, const char* message, struct CharCommandInfo* info) {
  150. char* p = (char *)message;
  151. if (!info)
  152. return CharCommand_None;
  153. if (battle_config.atc_gmonly != 0 && !level) // level = pc_isGM(sd)
  154. return CharCommand_None;
  155. if (!p || !*p) {
  156. fprintf(stderr, "char command message is empty\n");
  157. return CharCommand_None;
  158. }
  159. if (*p == command_symbol) { // check first char.
  160. char command[101];
  161. int i = 0;
  162. memset(info, 0, sizeof(CharCommandInfo));
  163. sscanf(p, "%100s", command);
  164. command[sizeof(command)-1] = '\0';
  165. while (charcommand_info[i].type != CharCommand_Unknown) {
  166. if (strcmpi(command+1, charcommand_info[i].command+1) == 0 && level >= charcommand_info[i].level) {
  167. p[0] = charcommand_info[i].command[0]; // set correct first symbol for after.
  168. break;
  169. }
  170. i++;
  171. }
  172. if (charcommand_info[i].type == CharCommand_Unknown) {
  173. // doesn't return Unknown if player is normal player (display the text, not display: unknown command)
  174. if (level == 0)
  175. return CharCommand_None;
  176. else
  177. return CharCommand_Unknown;
  178. }
  179. memcpy(info, &charcommand_info[i], sizeof charcommand_info[i]);
  180. } else {
  181. return CharCommand_None;
  182. }
  183. return info->type;
  184. }
  185. /*==========================================
  186. *
  187. *------------------------------------------
  188. */
  189. static CharCommandInfo* get_charcommandinfo_byname(const char* name) {
  190. int i;
  191. for (i = 0; charcommand_info[i].type != CharCommand_Unknown; i++)
  192. if (strcmpi(charcommand_info[i].command + 1, name) == 0)
  193. return &charcommand_info[i];
  194. return NULL;
  195. }
  196. /*==========================================
  197. *
  198. *------------------------------------------
  199. */
  200. int charcommand_config_read(const char *cfgName) {
  201. char line[1024], w1[1024], w2[1024];
  202. CharCommandInfo* p;
  203. FILE* fp;
  204. if ((fp = fopen(cfgName, "r")) == NULL) {
  205. printf("CharCommands configuration file not found: %s\n", cfgName);
  206. return 1;
  207. }
  208. while (fgets(line, sizeof(line)-1, fp)) {
  209. if (line[0] == '/' && line[1] == '/')
  210. continue;
  211. if (sscanf(line, "%1023[^:]:%1023s", w1, w2) != 2)
  212. continue;
  213. p = get_charcommandinfo_byname(w1);
  214. if (p != NULL) {
  215. p->level = atoi(w2);
  216. if (p->level > 100)
  217. p->level = 100;
  218. else if (p->level < 0)
  219. p->level = 0;
  220. }
  221. if (strcmpi(w1, "import") == 0)
  222. charcommand_config_read(w2);
  223. else if (strcmpi(w1, "command_symbol") == 0 && w2[0] > 31 &&
  224. w2[0] != '/' && // symbol of standard ragnarok GM commands
  225. w2[0] != '%' // symbol of party chat speaking
  226. )
  227. command_symbol = w2[0];
  228. }
  229. fclose(fp);
  230. return 0;
  231. }
  232. /*==========================================
  233. * 対象キャラクターを転職させる upper指定で転生や養子も可能
  234. *------------------------------------------
  235. */
  236. int charcommand_jobchange(
  237. const int fd, struct map_session_data* sd,
  238. const char* command, const char* message)
  239. {
  240. char character[100];
  241. struct map_session_data* pl_sd;
  242. int job = 0, upper = -1;
  243. memset(character, '\0', sizeof(character));
  244. if (!message || !*message) {
  245. clif_displaymessage(fd, "Please, enter a job and a player name (usage: #job/#jobchange <job ID> <char name>).");
  246. return -1;
  247. }
  248. if (sscanf(message, "%d %d %99[^\n]", &job, &upper, character) < 3) { //upper指定してある
  249. upper = -1;
  250. if (sscanf(message, "%d %99[^\n]", &job, character) < 2) { //upper指定してない上に何か足りない
  251. clif_displaymessage(fd, "Please, enter a job and a player name (usage: #job/#jobchange <job ID> <char name>).");
  252. return -1;
  253. }
  254. }
  255. if ((pl_sd = map_nick2sd(character)) != NULL) {
  256. int j;
  257. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change job only to lower or same level
  258. if ((job >= 0 && job < MAX_PC_CLASS)) {
  259. // fix pecopeco display
  260. if ((job != 13 && job != 21 && job != 4014 && job != 4022)) {
  261. if (pc_isriding(sd)) {
  262. if (pl_sd->status.class == 13)
  263. pl_sd->status.class = pl_sd->view_class = 7;
  264. if (pl_sd->status.class == 21)
  265. pl_sd->status.class = pl_sd->view_class = 14;
  266. if (pl_sd->status.class == 4014)
  267. pl_sd->status.class = pl_sd->view_class = 4008;
  268. if (pl_sd->status.class == 4022)
  269. pl_sd->status.class = pl_sd->view_class = 4015;
  270. pl_sd->status.option &= ~0x0020;
  271. clif_changeoption(&pl_sd->bl);
  272. pc_calcstatus(pl_sd, 0);
  273. }
  274. } else {
  275. if (!pc_isriding(sd)) {
  276. if (job == 13)
  277. job = 7;
  278. if (job == 21)
  279. job = 14;
  280. if (job == 4014)
  281. job = 4008;
  282. if (job == 4022)
  283. job = 4015;
  284. }
  285. }
  286. for (j=0; j < MAX_INVENTORY; j++) {
  287. if(pl_sd->status.inventory[j].nameid>0 && pl_sd->status.inventory[j].equip!=0)
  288. pc_unequipitem(pl_sd, j, 3);
  289. }
  290. if (pc_jobchange(pl_sd, job, upper) == 0)
  291. clif_displaymessage(fd, msg_table[48]); // Character's job changed.
  292. else {
  293. clif_displaymessage(fd, msg_table[192]); // Impossible to change the character's job.
  294. return -1;
  295. }
  296. } else {
  297. clif_displaymessage(fd, msg_table[49]); // Invalid job ID.
  298. return -1;
  299. }
  300. } else {
  301. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  302. return -1;
  303. }
  304. } else {
  305. clif_displaymessage(fd, msg_table[3]); // Character not found.
  306. return -1;
  307. }
  308. return 0;
  309. }
  310. /*==========================================
  311. *
  312. *------------------------------------------
  313. */
  314. int charcommand_petrename(
  315. const int fd, struct map_session_data* sd,
  316. const char* command, const char* message)
  317. {
  318. char character[100];
  319. struct map_session_data *pl_sd;
  320. memset(character, '\0', sizeof(character));
  321. if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
  322. clif_displaymessage(fd, "Please, enter a player name (usage: #petrename <char name>).");
  323. return -1;
  324. }
  325. if ((pl_sd = map_nick2sd(character)) != NULL) {
  326. if (pl_sd->status.pet_id > 0 && pl_sd->pd) {
  327. if (pl_sd->pet.rename_flag != 0) {
  328. pl_sd->pet.rename_flag = 0;
  329. intif_save_petdata(pl_sd->status.account_id, &pl_sd->pet);
  330. clif_send_petstatus(pl_sd);
  331. clif_displaymessage(fd, msg_table[189]); // This player can now rename his/her pet.
  332. } else {
  333. clif_displaymessage(fd, msg_table[190]); // This player can already rename his/her pet.
  334. return -1;
  335. }
  336. } else {
  337. clif_displaymessage(fd, msg_table[191]); // Sorry, but this player has no pet.
  338. return -1;
  339. }
  340. } else {
  341. clif_displaymessage(fd, msg_txt(3)); // Character not found.
  342. return -1;
  343. }
  344. return 0;
  345. }
  346. /*==========================================
  347. *
  348. *------------------------------------------
  349. */
  350. int charcommand_petfriendly(
  351. const int fd, struct map_session_data* sd,
  352. const char* command, const char* message)
  353. {
  354. int friendly = 0;
  355. int t = 0;
  356. char character[100];
  357. struct map_session_data *pl_sd;
  358. memset(character, '\0', sizeof(character));
  359. if (!message || !*message || sscanf(message,"%d %s",&friendly,character) < 2) {
  360. clif_displaymessage(fd, "Please, enter a valid value (usage: "
  361. "#petfriendly <0-1000> <player>).");
  362. return -1;
  363. }
  364. if (((pl_sd = map_nick2sd(character)) != NULL) && pc_isGM(sd)>pc_isGM(pl_sd)) {
  365. if (pl_sd->status.pet_id > 0 && pl_sd->pd) {
  366. if (friendly >= 0 && friendly <= 1000) {
  367. if (friendly != pl_sd->pet.intimate) {
  368. t = pl_sd->pet.intimate;
  369. pl_sd->pet.intimate = friendly;
  370. clif_send_petstatus(pl_sd);
  371. clif_pet_emotion(pl_sd->pd,0);
  372. if (battle_config.pet_status_support) {
  373. if ((pl_sd->pet.intimate > 0 && t <= 0) ||
  374. (pl_sd->pet.intimate <= 0 && t > 0)) {
  375. if (pl_sd->bl.prev != NULL)
  376. pc_calcstatus(pl_sd, 0);
  377. else
  378. pc_calcstatus(pl_sd, 2);
  379. }
  380. }
  381. clif_displaymessage(pl_sd->fd, msg_table[182]); // Pet friendly value changed!
  382. clif_displaymessage(sd->fd, msg_table[182]); // Pet friendly value changed!
  383. } else {
  384. clif_displaymessage(fd, msg_table[183]); // Pet friendly is already the good value.
  385. return -1;
  386. }
  387. } else {
  388. clif_displaymessage(fd, msg_table[37]); // An invalid number was specified.
  389. return -1;
  390. }
  391. } else {
  392. return -1;
  393. }
  394. } else {
  395. clif_displaymessage(fd, msg_txt(3)); // Character not found.
  396. return -1;
  397. }
  398. return 0;
  399. }
  400. /*==========================================
  401. *
  402. *------------------------------------------
  403. */
  404. int charcommand_stats(
  405. const int fd, struct map_session_data* sd,
  406. const char* command, const char* message)
  407. {
  408. char character[100];
  409. char job_jobname[100];
  410. char output[200];
  411. struct map_session_data *pl_sd;
  412. int i;
  413. memset(character, '\0', sizeof(character));
  414. memset(job_jobname, '\0', sizeof(job_jobname));
  415. memset(output, '\0', sizeof(output));
  416. if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
  417. clif_displaymessage(fd, "Please, enter a player name (usage: #stats <char name>).");
  418. return -1;
  419. }
  420. if ((pl_sd = map_nick2sd(character)) != NULL) {
  421. struct {
  422. const char* format;
  423. int value;
  424. } output_table[] = {
  425. { "Base Level - %d", pl_sd->status.base_level },
  426. { job_jobname, pl_sd->status.job_level },
  427. { "Hp - %d", pl_sd->status.hp },
  428. { "MaxHp - %d", pl_sd->status.max_hp },
  429. { "Sp - %d", pl_sd->status.sp },
  430. { "MaxSp - %d", pl_sd->status.max_sp },
  431. { "Str - %3d", pl_sd->status.str },
  432. { "Agi - %3d", pl_sd->status.agi },
  433. { "Vit - %3d", pl_sd->status.vit },
  434. { "Int - %3d", pl_sd->status.int_ },
  435. { "Dex - %3d", pl_sd->status.dex },
  436. { "Luk - %3d", pl_sd->status.luk },
  437. { "Zeny - %d", pl_sd->status.zeny },
  438. { NULL, 0 }
  439. };
  440. sprintf(job_jobname, "Job - %s %s", job_name(pl_sd->status.class), "(level %d)");
  441. sprintf(output, msg_table[53], pl_sd->status.name); // '%s' stats:
  442. clif_displaymessage(fd, output);
  443. for (i = 0; output_table[i].format != NULL; i++) {
  444. sprintf(output, output_table[i].format, output_table[i].value);
  445. clif_displaymessage(fd, output);
  446. }
  447. } else {
  448. clif_displaymessage(fd, msg_table[3]); // Character not found.
  449. return -1;
  450. }
  451. return 0;
  452. }
  453. /*==========================================
  454. * Character Reset
  455. *------------------------------------------
  456. */
  457. int charcommand_reset(
  458. const int fd, struct map_session_data* sd,
  459. const char* command, const char* message)
  460. {
  461. char character[100];
  462. char output[200];
  463. struct map_session_data *pl_sd;
  464. memset(character, '\0', sizeof(character));
  465. memset(output, '\0', sizeof(output));
  466. if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
  467. clif_displaymessage(fd, "Please, enter a player name (usage: #reset <charname>).");
  468. return -1;
  469. }
  470. if ((pl_sd = map_nick2sd(character)) != NULL) {
  471. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can reset a character only for lower or same GM level
  472. pc_resetstate(pl_sd);
  473. pc_resetskill(pl_sd);
  474. sprintf(output, msg_table[208], character); // '%s' skill and stats points reseted!
  475. clif_displaymessage(fd, output);
  476. } else {
  477. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  478. return -1;
  479. }
  480. } else {
  481. clif_displaymessage(fd, msg_table[3]); // Character not found.
  482. return -1;
  483. }
  484. return 0;
  485. }
  486. /*==========================================
  487. *
  488. *------------------------------------------
  489. */
  490. int charcommand_option(
  491. const int fd, struct map_session_data* sd,
  492. const char* command, const char* message)
  493. {
  494. char character[100];
  495. int opt1 = 0, opt2 = 0, opt3 = 0;
  496. struct map_session_data* pl_sd;
  497. memset(character, '\0', sizeof(character));
  498. if (!message || !*message ||
  499. sscanf(message, "%d %d %d %99[^\n]", &opt1, &opt2, &opt3, character) < 4 ||
  500. opt1 < 0 || opt2 < 0 || opt3 < 0) {
  501. clif_displaymessage(fd, "Please, enter valid options and a player name (usage: #option <param1> <param2> <param3> <charname>).");
  502. return -1;
  503. }
  504. if ((pl_sd = map_nick2sd(character)) != NULL) {
  505. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change option only to lower or same level
  506. pl_sd->opt1 = opt1;
  507. pl_sd->opt2 = opt2;
  508. pl_sd->status.option = opt3;
  509. // fix pecopeco display
  510. if (pl_sd->status.class == 13 || pl_sd->status.class == 21 || pl_sd->status.class == 4014 || pl_sd->status.class == 4022) {
  511. if (!pc_isriding(pl_sd)) { // pl_sd have the new value...
  512. if (pl_sd->status.class == 13)
  513. pl_sd->status.class = pl_sd->view_class = 7;
  514. else if (pl_sd->status.class == 21)
  515. pl_sd->status.class = pl_sd->view_class = 14;
  516. else if (pl_sd->status.class == 4014)
  517. pl_sd->status.class = pl_sd->view_class = 4008;
  518. else if (pl_sd->status.class == 4022)
  519. pl_sd->status.class = pl_sd->view_class = 4015;
  520. }
  521. } else {
  522. if (pc_isriding(pl_sd)) { // pl_sd have the new value...
  523. if (pl_sd->disguise > 0) { // temporary prevention of crash caused by peco + disguise, will look into a better solution [Valaris] (code added by [Yor])
  524. pl_sd->status.option &= ~0x0020;
  525. } else {
  526. if (pl_sd->status.class == 7)
  527. pl_sd->status.class = pl_sd->view_class = 13;
  528. else if (pl_sd->status.class == 14)
  529. pl_sd->status.class = pl_sd->view_class = 21;
  530. else if (pl_sd->status.class == 4008)
  531. pl_sd->status.class = pl_sd->view_class = 4014;
  532. else if (pl_sd->status.class == 4015)
  533. pl_sd->status.class = pl_sd->view_class = 4022;
  534. else
  535. pl_sd->status.option &= ~0x0020;
  536. }
  537. }
  538. }
  539. clif_changeoption(&pl_sd->bl);
  540. pc_calcstatus(pl_sd, 0);
  541. clif_displaymessage(fd, msg_table[58]); // Character's options changed.
  542. } else {
  543. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  544. return -1;
  545. }
  546. } else {
  547. clif_displaymessage(fd, msg_table[3]); // Character not found.
  548. return -1;
  549. }
  550. return 0;
  551. }
  552. /*==========================================
  553. *
  554. *------------------------------------------
  555. */
  556. int charcommand_save(
  557. const int fd, struct map_session_data* sd,
  558. const char* command, const char* message)
  559. {
  560. char map_name[100];
  561. char character[100];
  562. struct map_session_data* pl_sd;
  563. int x = 0, y = 0;
  564. int m;
  565. memset(map_name, '\0', sizeof(map_name));
  566. memset(character, '\0', sizeof(character));
  567. if (!message || !*message || sscanf(message, "%99s %d %d %99[^\n]", map_name, &x, &y, character) < 4 || x < 0 || y < 0) {
  568. clif_displaymessage(fd, "Please, enter a valid save point and a player name (usage: #save <map> <x> <y> <charname>).");
  569. return -1;
  570. }
  571. if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat)
  572. strcat(map_name, ".gat");
  573. if ((pl_sd = map_nick2sd(character)) != NULL) {
  574. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can change save point only to lower or same gm level
  575. m = map_mapname2mapid(map_name);
  576. if (m < 0) {
  577. clif_displaymessage(fd, msg_table[1]); // Map not found.
  578. return -1;
  579. } else {
  580. if (m >= 0 && map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
  581. clif_displaymessage(fd, "You are not authorised to set this map as a save map.");
  582. return -1;
  583. }
  584. pc_setsavepoint(pl_sd, map_name, x, y);
  585. clif_displaymessage(fd, msg_table[57]); // Character's respawn point changed.
  586. }
  587. } else {
  588. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  589. return -1;
  590. }
  591. } else {
  592. clif_displaymessage(fd, msg_table[3]); // Character not found.
  593. return -1;
  594. }
  595. return 0;
  596. }
  597. /*==========================================
  598. *
  599. *------------------------------------------
  600. */
  601. //** Character Stats All by fritz
  602. int charcommand_stats_all(const int fd, struct map_session_data* sd, const char* command, const char* message)
  603. {
  604. char output[1024], gmlevel[1024];
  605. int i;
  606. int count;
  607. struct map_session_data *pl_sd;
  608. memset(output, '\0', sizeof(output));
  609. memset(gmlevel, '\0', sizeof(gmlevel));
  610. count = 0;
  611. for(i = 0; i < fd_max; i++) {
  612. if (session[i] && (pl_sd = session[i]->session_data) && pl_sd->state.auth) {
  613. if (pc_isGM(pl_sd) > 0)
  614. sprintf(gmlevel, "| GM Lvl: %d", pc_isGM(pl_sd));
  615. else
  616. sprintf(gmlevel, " ");
  617. 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);
  618. clif_displaymessage(fd, output);
  619. 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);
  620. clif_displaymessage(fd, output);
  621. clif_displaymessage(fd, "--------");
  622. count++;
  623. }
  624. }
  625. if (count == 0)
  626. clif_displaymessage(fd, msg_table[28]); // No player found.
  627. else if (count == 1)
  628. clif_displaymessage(fd, msg_table[29]); // 1 player found.
  629. else {
  630. sprintf(output, msg_table[30], count); // %d players found.
  631. clif_displaymessage(fd, output);
  632. }
  633. return 0;
  634. }
  635. /*==========================================
  636. * CharSpiritBall Function by PalasX
  637. *------------------------------------------
  638. */
  639. int charcommand_spiritball(const int fd, struct map_session_data* sd,const char* command, const char* message)
  640. {
  641. struct map_session_data *pl_sd;
  642. char character[100];
  643. int spirit = 0;
  644. memset(character, '\0', sizeof(character));
  645. if(!message || !*message || sscanf(message, "%d %99[^\n]", &spirit, character) < 2 || spirit < 0 || spirit > 1000) {
  646. clif_displaymessage(fd, "Usage: @spiritball <number: 0-1000>) <CHARACTER_NAME>.");
  647. return -1;
  648. }
  649. if((pl_sd = map_nick2sd(character)) != NULL) {
  650. if (spirit >= 0 && spirit <= 0x7FFF) {
  651. if (pl_sd->spiritball != spirit || spirit > 999) {
  652. if (pl_sd->spiritball > 0)
  653. pc_delspiritball(pl_sd, pl_sd->spiritball, 1);
  654. pl_sd->spiritball = spirit;
  655. clif_spiritball(pl_sd);
  656. // no message, player can look the difference
  657. if (spirit > 1000)
  658. clif_displaymessage(fd, msg_table[204]); // WARNING: more than 1000 spiritballs can CRASH your server and/or client!
  659. } else {
  660. clif_displaymessage(fd, msg_table[205]); // You already have this number of spiritballs.
  661. return -1;
  662. }
  663. } else {
  664. clif_displaymessage(fd, msg_table[37]); // An invalid number was specified.
  665. return -1;
  666. }
  667. } else {
  668. clif_displaymessage(fd, msg_table[3]); // Character not found.
  669. return -1;
  670. }
  671. return 0;
  672. }
  673. /*==========================================
  674. * #itemlist <character>: Displays the list of a player's items.
  675. *------------------------------------------
  676. */
  677. int
  678. charcommand_itemlist(
  679. const int fd, struct map_session_data* sd,
  680. const char* command, const char* message)
  681. {
  682. struct map_session_data *pl_sd;
  683. struct item_data *item_data, *item_temp;
  684. int i, j, equip, count, counter, counter2;
  685. char character[100], output[200], equipstr[100], outputtmp[200];
  686. nullpo_retr(-1, sd);
  687. memset(character, '\0', sizeof(character));
  688. memset(output, '\0', sizeof(output));
  689. memset(equipstr, '\0', sizeof(equipstr));
  690. memset(outputtmp, '\0', sizeof(outputtmp));
  691. if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
  692. clif_displaymessage(fd, "Please, enter a player name (usage: #itemlist <char name>).");
  693. return -1;
  694. }
  695. if ((pl_sd = map_nick2sd(character)) != NULL) {
  696. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can look items only lower or same level
  697. counter = 0;
  698. count = 0;
  699. for (i = 0; i < MAX_INVENTORY; i++) {
  700. if (pl_sd->status.inventory[i].nameid > 0 && (item_data = itemdb_search(pl_sd->status.inventory[i].nameid)) != NULL) {
  701. counter = counter + pl_sd->status.inventory[i].amount;
  702. count++;
  703. if (count == 1) {
  704. sprintf(output, "------ Items list of '%s' ------", pl_sd->status.name);
  705. clif_displaymessage(fd, output);
  706. }
  707. if ((equip = pl_sd->status.inventory[i].equip)) {
  708. strcpy(equipstr, "| equiped: ");
  709. if (equip & 4)
  710. strcat(equipstr, "robe/gargment, ");
  711. if (equip & 8)
  712. strcat(equipstr, "left accessory, ");
  713. if (equip & 16)
  714. strcat(equipstr, "body/armor, ");
  715. if ((equip & 34) == 2)
  716. strcat(equipstr, "right hand, ");
  717. if ((equip & 34) == 32)
  718. strcat(equipstr, "left hand, ");
  719. if ((equip & 34) == 34)
  720. strcat(equipstr, "both hands, ");
  721. if (equip & 64)
  722. strcat(equipstr, "feet, ");
  723. if (equip & 128)
  724. strcat(equipstr, "right accessory, ");
  725. if ((equip & 769) == 1)
  726. strcat(equipstr, "lower head, ");
  727. if ((equip & 769) == 256)
  728. strcat(equipstr, "top head, ");
  729. if ((equip & 769) == 257)
  730. strcat(equipstr, "lower/top head, ");
  731. if ((equip & 769) == 512)
  732. strcat(equipstr, "mid head, ");
  733. if ((equip & 769) == 512)
  734. strcat(equipstr, "lower/mid head, ");
  735. if ((equip & 769) == 769)
  736. strcat(equipstr, "lower/mid/top head, ");
  737. // remove final ', '
  738. equipstr[strlen(equipstr) - 2] = '\0';
  739. } else
  740. memset(equipstr, '\0', sizeof(equipstr));
  741. if (sd->status.inventory[i].refine)
  742. 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);
  743. else
  744. 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);
  745. clif_displaymessage(fd, output);
  746. memset(output, '\0', sizeof(output));
  747. counter2 = 0;
  748. for (j = 0; j < item_data->slot; j++) {
  749. if (pl_sd->status.inventory[i].card[j]) {
  750. if ((item_temp = itemdb_search(pl_sd->status.inventory[i].card[j])) != NULL) {
  751. if (output[0] == '\0')
  752. sprintf(outputtmp, " -> (card(s): #%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
  753. else
  754. sprintf(outputtmp, "#%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
  755. strcat(output, outputtmp);
  756. }
  757. }
  758. }
  759. if (output[0] != '\0') {
  760. output[strlen(output) - 2] = ')';
  761. output[strlen(output) - 1] = '\0';
  762. clif_displaymessage(fd, output);
  763. }
  764. }
  765. }
  766. if (count == 0)
  767. clif_displaymessage(fd, "No item found on this player.");
  768. else {
  769. sprintf(output, "%d item(s) found in %d kind(s) of items.", counter, count);
  770. clif_displaymessage(fd, output);
  771. }
  772. } else {
  773. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  774. return -1;
  775. }
  776. } else {
  777. clif_displaymessage(fd, msg_table[3]); // Character not found.
  778. return -1;
  779. }
  780. return 0;
  781. }
  782. /*==========================================
  783. * #effect by [MouseJstr]
  784. *
  785. * Create a effect localized on another character
  786. *------------------------------------------
  787. */
  788. int
  789. charcommand_effect(const int fd, struct map_session_data* sd,
  790. const char* command, const char* message)
  791. {
  792. struct map_session_data *pl_sd = NULL;
  793. char target[255];
  794. int type = 0;
  795. nullpo_retr(-1, sd);
  796. if (!message || !*message || sscanf(message, "%d %s", &type, target) != 2) {
  797. clif_displaymessage(fd, "usage: #effect <type+> <target>.");
  798. return -1;
  799. }
  800. if((pl_sd=map_nick2sd((char *) target)) == NULL)
  801. return -1;
  802. clif_specialeffect(&pl_sd->bl, type, 0);
  803. clif_displaymessage(fd, msg_table[229]); // Your effect has changed.
  804. return 0;
  805. }
  806. /*==========================================
  807. * #storagelist <character>: Displays the items list of a player's storage.
  808. *------------------------------------------
  809. */
  810. int
  811. charcommand_storagelist(
  812. const int fd, struct map_session_data* sd,
  813. const char* command, const char* message)
  814. {
  815. struct storage *stor;
  816. struct map_session_data *pl_sd;
  817. struct item_data *item_data, *item_temp;
  818. int i, j, count, counter, counter2;
  819. char character[100], output[200], outputtmp[200];
  820. nullpo_retr(-1, sd);
  821. memset(character, '\0', sizeof(character));
  822. memset(output, '\0', sizeof(output));
  823. memset(outputtmp, '\0', sizeof(outputtmp));
  824. if (!message || !*message || sscanf(message, "%99[^\n]", character) < 1) {
  825. clif_displaymessage(fd, "Please, enter a player name (usage: #itemlist <char name>).");
  826. return -1;
  827. }
  828. if ((pl_sd = map_nick2sd(character)) != NULL) {
  829. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can look items only lower or same level
  830. if((stor = account2storage2(pl_sd->status.account_id)) != NULL) {
  831. counter = 0;
  832. count = 0;
  833. for (i = 0; i < MAX_STORAGE; i++) {
  834. if (stor->storage[i].nameid > 0 && (item_data = itemdb_search(stor->storage[i].nameid)) != NULL) {
  835. counter = counter + stor->storage[i].amount;
  836. count++;
  837. if (count == 1) {
  838. sprintf(output, "------ Storage items list of '%s' ------", pl_sd->status.name);
  839. clif_displaymessage(fd, output);
  840. }
  841. if (stor->storage[i].refine)
  842. 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);
  843. else
  844. sprintf(output, "%d %s (%s, id: %d)", stor->storage[i].amount, item_data->name, item_data->jname, stor->storage[i].nameid);
  845. clif_displaymessage(fd, output);
  846. memset(output, '\0', sizeof(output));
  847. counter2 = 0;
  848. for (j = 0; j < item_data->slot; j++) {
  849. if (stor->storage[i].card[j]) {
  850. if ((item_temp = itemdb_search(stor->storage[i].card[j])) != NULL) {
  851. if (output[0] == '\0')
  852. sprintf(outputtmp, " -> (card(s): #%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
  853. else
  854. sprintf(outputtmp, "#%d %s (%s), ", ++counter2, item_temp->name, item_temp->jname);
  855. strcat(output, outputtmp);
  856. }
  857. }
  858. }
  859. if (output[0] != '\0') {
  860. output[strlen(output) - 2] = ')';
  861. output[strlen(output) - 1] = '\0';
  862. clif_displaymessage(fd, output);
  863. }
  864. }
  865. }
  866. if (count == 0)
  867. clif_displaymessage(fd, "No item found in the storage of this player.");
  868. else {
  869. sprintf(output, "%d item(s) found in %d kind(s) of items.", counter, count);
  870. clif_displaymessage(fd, output);
  871. }
  872. } else {
  873. clif_displaymessage(fd, "This player has no storage.");
  874. return 0;
  875. }
  876. } else {
  877. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  878. return -1;
  879. }
  880. } else {
  881. clif_displaymessage(fd, msg_table[3]); // Character not found.
  882. return -1;
  883. }
  884. return 0;
  885. }
  886. static void
  887. charcommand_giveitem_sub(struct map_session_data *sd,struct item_data *item_data,int number)
  888. {
  889. int flag = 0;
  890. int loop = 1, get_count = number,i;
  891. struct item item_tmp;
  892. if(sd && item_data){
  893. if (item_data->type == 4 || item_data->type == 5 ||
  894. item_data->type == 7 || item_data->type == 8) {
  895. loop = number;
  896. get_count = 1;
  897. }
  898. for (i = 0; i < loop; i++) {
  899. memset(&item_tmp, 0, sizeof(item_tmp));
  900. item_tmp.nameid = item_data->nameid;
  901. item_tmp.identify = 1;
  902. if ((flag = pc_additem((struct map_session_data*)sd,
  903. &item_tmp, get_count)))
  904. clif_additem((struct map_session_data*)sd, 0, 0, flag);
  905. }
  906. }
  907. }
  908. /*==========================================
  909. * #item command (usage: #item <name/id_of_item> <quantity> <player>)
  910. * by MC Cameri
  911. *------------------------------------------
  912. */
  913. int charcommand_item(
  914. const int fd, struct map_session_data* sd,
  915. const char* command, const char* message)
  916. {
  917. char item_name[100];
  918. char character[100];
  919. struct map_session_data *pl_sd;
  920. int number = 0, item_id, flag;
  921. struct item item_tmp;
  922. struct item_data *item_data;
  923. int get_count, i, pet_id;
  924. nullpo_retr(-1, sd);
  925. memset(item_name, '\0', sizeof(item_name));
  926. if (!message || !*message || sscanf(message, "%99s %d %99[^\n]", item_name, &number, character) < 3) {
  927. clif_displaymessage(fd, "Please, enter an item name/id (usage: #item <item name or ID> <quantity> <char name>).");
  928. return -1;
  929. }
  930. if (number <= 0)
  931. number = 1;
  932. item_id = 0;
  933. if ((item_data = itemdb_searchname(item_name)) != NULL ||
  934. (item_data = itemdb_exists(atoi(item_name))) != NULL)
  935. item_id = item_data->nameid;
  936. if (item_id >= 500) {
  937. get_count = number;
  938. // check pet egg
  939. pet_id = search_petDB_index(item_id, PET_EGG);
  940. if (item_data->type == 4 || item_data->type == 5 ||
  941. item_data->type == 7 || item_data->type == 8) {
  942. get_count = 1;
  943. }
  944. if ((pl_sd = map_nick2sd(character)) != NULL) {
  945. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can look items only lower or same level
  946. for (i = 0; i < number; i += get_count) {
  947. // if pet egg
  948. if (pet_id >= 0) {
  949. sd->catch_target_class = pet_db[pet_id].class;
  950. intif_create_pet(sd->status.account_id, sd->status.char_id,
  951. pet_db[pet_id].class, mob_db[pet_db[pet_id].class].lv,
  952. pet_db[pet_id].EggID, 0, pet_db[pet_id].intimate,
  953. 100, 0, 1, pet_db[pet_id].jname);
  954. // if not pet egg
  955. } else {
  956. memset(&item_tmp, 0, sizeof(item_tmp));
  957. item_tmp.nameid = item_id;
  958. item_tmp.identify = 1;
  959. if ((flag = pc_additem((struct map_session_data*)sd, &item_tmp, get_count)))
  960. clif_additem((struct map_session_data*)sd, 0, 0, flag);
  961. }
  962. }
  963. clif_displaymessage(fd, msg_table[18]); // Item created.
  964. } else {
  965. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  966. return -1;
  967. }
  968. } else if(strncasecmp(character,"all")==0 || strncasecmp(character,"everyone")==0){ // 名前がALLなら、接続者全員へ
  969. for (i = 0; i < fd_max; i++) {
  970. if (session[i] && (pl_sd = session[i]->session_data)){
  971. atcommand_giveitem_sub(pl_sd,item_data,number);
  972. snprintf(output, sizeof output, "You got %s %d.", item_name,number);
  973. clif_displaymessage(pl_sd->fd, output);
  974. }
  975. }
  976. snprintf(output, sizeof output, "%s received %s %d.","Everyone",item_name,number);
  977. clif_displaymessage(fd, output);
  978. } else {
  979. clif_displaymessage(fd, msg_table[3]); // Character not found.
  980. return -1;
  981. }
  982. } else {
  983. clif_displaymessage(fd, msg_table[19]); // Invalid item ID or name.
  984. return -1;
  985. }
  986. return 0;
  987. }
  988. /*==========================================
  989. * #warp/#rura/#rura+ <mapname> <x> <y> <char name>
  990. *------------------------------------------
  991. */
  992. int charcommand_warp(
  993. const int fd, struct map_session_data* sd,
  994. const char* command, const char* message)
  995. {
  996. char map_name[100];
  997. char character[100];
  998. int x = 0, y = 0;
  999. struct map_session_data *pl_sd;
  1000. int m;
  1001. nullpo_retr(-1, sd);
  1002. memset(map_name, '\0', sizeof(map_name));
  1003. memset(character, '\0', sizeof(character));
  1004. if (!message || !*message || sscanf(message, "%99s %d %d %99[^\n]", map_name, &x, &y, character) < 4) {
  1005. clif_displaymessage(fd, "Usage: #warp/#rura/#rura+ <mapname> <x> <y> <char name>");
  1006. return -1;
  1007. }
  1008. if (x <= 0)
  1009. x = rand() % 399 + 1;
  1010. if (y <= 0)
  1011. y = rand() % 399 + 1;
  1012. if (strstr(map_name, ".gat") == NULL && strstr(map_name, ".afm") == NULL && strlen(map_name) < 13) // 16 - 4 (.gat)
  1013. strcat(map_name, ".gat");
  1014. if ((pl_sd = map_nick2sd(character)) != NULL) {
  1015. if (pc_isGM(sd) >= pc_isGM(pl_sd)) { // you can rura+ only lower or same GM level
  1016. if (x > 0 && x < 400 && y > 0 && y < 400) {
  1017. m = map_mapname2mapid(map_name);
  1018. if (m >= 0 && map[m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
  1019. clif_displaymessage(fd, "You are not authorised to warp someone to this map.");
  1020. return -1;
  1021. }
  1022. if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd)) {
  1023. clif_displaymessage(fd, "You are not authorised to warp this player from its actual map.");
  1024. return -1;
  1025. }
  1026. if (pc_setpos(pl_sd, map_name, x, y, 3) == 0) {
  1027. clif_displaymessage(pl_sd->fd, msg_table[0]); // Warped.
  1028. clif_displaymessage(fd, msg_table[15]); // Player warped (message sends to player too).
  1029. } else {
  1030. clif_displaymessage(fd, msg_table[1]); // Map not found.
  1031. return -1;
  1032. }
  1033. } else {
  1034. clif_displaymessage(fd, msg_table[2]); // Coordinates out of range.
  1035. return -1;
  1036. }
  1037. } else {
  1038. clif_displaymessage(fd, msg_table[81]); // Your GM level don't authorise you to do this action on this player.
  1039. return -1;
  1040. }
  1041. } else {
  1042. clif_displaymessage(fd, msg_table[3]); // Character not found.
  1043. return -1;
  1044. }
  1045. return 0;
  1046. }
  1047. /*==========================================
  1048. * #zeny <charname>
  1049. *------------------------------------------
  1050. */
  1051. int charcommand_zeny(
  1052. const int fd, struct map_session_data* sd,
  1053. const char* command, const char* message)
  1054. {
  1055. struct map_session_data *pl_sd;
  1056. char character[100];
  1057. int zeny = 0, new_zeny;
  1058. nullpo_retr(-1, sd);
  1059. memset(character, '\0', sizeof(character));
  1060. if (!message || !*message || sscanf(message, "%d %99[^\n]", &zeny, character) < 2 || zeny == 0) {
  1061. clif_displaymessage(fd, "Please, enter a number and a player name (usage: #zeny <zeny> <name>).");
  1062. return -1;
  1063. }
  1064. if ((pl_sd = map_nick2sd(character)) != NULL) {
  1065. new_zeny = pl_sd->status.zeny + zeny;
  1066. if (zeny > 0 && (zeny > MAX_ZENY || new_zeny > MAX_ZENY)) // fix positiv overflow
  1067. new_zeny = MAX_ZENY;
  1068. else if (zeny < 0 && (zeny < -MAX_ZENY || new_zeny < 0)) // fix negativ overflow
  1069. new_zeny = 0;
  1070. if (new_zeny != pl_sd->status.zeny) {
  1071. pl_sd->status.zeny = new_zeny;
  1072. clif_updatestatus(pl_sd, SP_ZENY);
  1073. clif_displaymessage(fd, msg_table[211]); // Character's number of zenys changed!
  1074. } else {
  1075. if (zeny < 0)
  1076. clif_displaymessage(fd, msg_table[41]); // Impossible to decrease the number/value.
  1077. else
  1078. clif_displaymessage(fd, msg_table[149]); // Impossible to increase the number/value.
  1079. return -1;
  1080. }
  1081. } else {
  1082. clif_displaymessage(fd, msg_table[3]); // Character not found.
  1083. return -1;
  1084. }
  1085. return 0;
  1086. }