From 8f36123ac4f0dad6a9c2428b0b01a3ffd81017a4 Mon Sep 17 00:00:00 2001 From: ultramage Date: Mon, 29 Oct 2007 09:16:39 +0000 Subject: Command code cleaning (refer to topic:169759) * separated the execution part of command code into interface part and internal part to better see which checks are done and when (fixes problem where 'nocommand' mapflag blocked server npcs) * moved the internal commands list (array) to the end of the file, this let me discard that long block of ACMD_FUNC() declarations * removed enum AtCommandType from command headers and commands array; its purpose was perhaps to identify aliased commands, but apparently it was never finished because the rest of the code doesn't use it (also doing aliases like this is not a very good idea) * internally, commands are now referenced to using their function name * removed the @/# symbols from the command lists; all lookup functions will now properly deal with strings with- and without a command symbol (commands interface still requires the symbol tho', so TODO for later) * removed several unneeded commands (*id2 code, dmalloc debug commands) * reverted atcommand config from alphabetically-sorted to how it was before (with additional fixes; see /conf changelog) * added missing code for #dropall / #storeall * added a warning when trying to set gm level of an undefined command The structure of the commands table has changed, please adjust docs/guides to match the new format (sorry for the inconvenience). git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@11607 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 22 + conf/Changelog.txt | 8 + conf/atcommand_athena.conf | 764 ++++++++++---------- conf/charcommand_athena.conf | 19 +- src/map/atcommand.c | 1569 +++++++++++++++--------------------------- src/map/atcommand.h | 299 +------- src/map/charcommand.c | 732 ++++++++++---------- src/map/charcommand.h | 101 +-- src/map/clif.c | 85 +-- src/map/map.c | 2 +- src/map/pc.c | 2 +- src/map/script.c | 94 +-- 12 files changed, 1464 insertions(+), 2233 deletions(-) diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 8bae71d38..bc418daf2 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -3,6 +3,28 @@ Date Added AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. +2007/10/29 + * command code cleaning (refer to topic:169759) [ultramage] + - separated the execution part of command code into interface part + and internal part to better see which checks are done and when + (fixes problem where 'nocommand' mapflag blocked server npcs) + - moved the internal commands list (array) to the end of the file, + this let me discard that long block of ACMD_FUNC() declarations + - removed enum AtCommandType from command headers and commands array; + its purpose was perhaps to identify aliased commands, but apparently + it was never finished because the rest of the code doesn't use it + (also doing aliases like this is not a very good idea) + - internally, commands are now referenced to using their function name + - removed the @/# symbols from the command lists; all lookup functions + will now properly deal with strings with- and without a command symbol + (commands interface still requires the symbol tho', so TODO for later) + - removed several unneeded commands (*id2 code, dmalloc debug commands) + - reverted atcommand config from alphabetically-sorted to how it was + before (with additional fixes; see /conf changelog) + - added missing code for #dropall / #storeall + - added a warning when trying to set gm level of an undefined command + * The structure of the commands table has changed, please adjust + docs/guides to match the new format (sorry for the inconvenience) 2007/10/28 * Minor adjustment to take into account the end of line. * Fixed the line count in the new error message of npc_parse_function. diff --git a/conf/Changelog.txt b/conf/Changelog.txt index 16f89f004..b9da37380 100644 --- a/conf/Changelog.txt +++ b/conf/Changelog.txt @@ -1,5 +1,13 @@ Date Added +2007/10/29 + * Removed petid command (not needed because commands understand names) + * Removed *id2 commands (messy, useless and redundant) + * Added missing @misceffect, @feelreset and #dropall/#storeall setting + * AGAIN added conf entries for @whozeny, @kamic, @tonpc, @identify, + @adopt, @trade, @changelook, @send, @displayskill + * Reverted atcommand conf (alphabetically-sorted = failure) [ultramage] + 2007/10/26 * Removed the config setting firewall_hits_on_undead setting. The code handles this now using the delay defined in skill_unit_db. [Skotlex] diff --git a/conf/atcommand_athena.conf b/conf/atcommand_athena.conf index 06fec590e..92ecf2bf5 100644 --- a/conf/atcommand_athena.conf +++ b/conf/atcommand_athena.conf @@ -1,41 +1,41 @@ -// Athena atcommand Configuration file. -// Translated by Peter Kieser - -// Set here the symbol that you want to use for your commands -// Only 1 character is get (default is character_savecharacter_save'@'). You can set any character, -// except control-character (0x00-0x1f), '%' (party chat speaking) and '/' (standard ragnarok GM commands) -// With default character, all commands begin by a '@': @revive +//-------------------------------------------------------------- +// eAthena atcommand configuration file. +// Originally translated by Peter Kieser +//-------------------------------------------------------------- + +// The symbol that will be used to recognize commands. +// You can set any one character except control-characters (0x00-0x1f), +// '%', '$' (party/guild chat speaking) and '/' (standard client commands). +// The symbol must also be different from from the GM charcommand symbol. command_symbol: @ +// The following settings in this file use the format ": level". +// They define the minimum GM level required to execute the associated command. +// Adjust values as you like. Note that to activate commands for normal players, +// (GM level 0), you also need to change the 'atcommand_gm_only' option to 'no'. +// To completely disable a command, set its required GM level to 100. -// Sets the level of the users that can use the GM commands. -// : level -// When battle_athena.conf has atcommand_gm_only set to no, -// normal players (gm level 0) can use GM commands if you set 0 to the command level. -// Max GM level is 99. If you want forbid a command to all people, set it with level 100. - -// Default values are set to define different GM levels like follow: -// 0: normal player -// -> no special advantage (only @time to know time and if at_command_gm_only is disabled) +// Default levels were chosen so that they form the following hierarchy: +// 0: Normal player +// -> no commands accessible // 1: Super player -// -> some (very) little advantages: storage, petrename, etc... +// -> some minor advantage: storage, petrename, etc... // 10: Super player+ -// -> same of Super player with !go (very super player) +// -> more powerful commands, like mobsearch and changegm // 20: Mediator -// -> it's a GM that only need to know people, and move to their to speak with them (they can access to any command about wisps) +// -> GM commands for finding players and moving to them (also kicking them) // 40: Sub-GM -// -> This GM can help a GM, and can not create item or zeny or modify a character (can have some information commands) +// -> GM commands for basic tasks, no significant impact on other players // 50: Sub-GM+ -// -> This GM can change some non-important things on a character +// -> GM commands to spawn mobs and create guilds // 60: GM -// -> can do almost anything (excep administration, and mass commands) -// GM is the first level where we can modify a character with important value, create items or create zenys +// -> almost all commands available (except administration and mass commands) // 80: GM Chief // -> can do anything, except administration commands // 99: Administrator // -> can do anything! // 100: Disabled -// -> Commands that aren't used. Note: You must use command level 100 to disable command. Commenting doesn't enough. +// -> commands that will not be available to anyone //-------------------------- @@ -45,222 +45,168 @@ command_symbol: @ //------------------------- // 1: Super player commands -// Enables/disables autolooting from killed mobs. -autoloot: 1 - -// Allows you continue vending offline. -autotrade: 1 -at: 1 - -// Away messsage -away: 1 -aw: 1 +// Displays a list of @ commands available to the player. +commands: 1 -// Change Guild Master of your Guild -changegm: 1 +// Displays the server rates. +rates: 1 -// Change the leader of your party. -changeleader: 1 +// Show server uptime +uptime: 1 -//Displays a list of @ commands available to the player. -commands: 1 +// Shows/Hides the "there is a delay after a skill" message. +showdelay: 1 -// Duel organizing commands -duel: 1 -invite: 1 -accept: 1 -reject: 1 -leave: 1 +// Displays current levels and % progress. +exp: 1 // To change your (own) email (characters protection) // note: this command doesn't check email itself, but check structure of the email (xxx@xxx) // if you want be sure of each e-mail disable this option (value: 100) email: 1 -//Displays current levels and % progress. -exp: 1 - -//Homunculus commands for players -homtalk: 1 -hominfo: 1 +// Show Monster info (rates, stats, drops, MVP stuff) +mobinfo: 1 +monsterinfo: 1 +mi: 1 // Show Item info (type, price, etc) iteminfo: 1 ii: 1 -// Displays remaining jail time -jailtime: 1 - -// Main chat -main: 1 - -// Displays the text as a normal message with the format "*name message*" -// instead of "name : message" (Like the /me command in IRC) -me: 1 - -// Saves a warp point. -memo: 1 +// Show who drops an item (mobs with highest drop rate) +whodrops: 1 -// Show Monster info (rates, stats, drops, MVP stuff) -mobinfo: 1 -monsterinfo: 1 -mi: 1 +// Syncs the player's position on the client with the one stored on the server. +refresh: 1 -// Autorejecting Deals/Invites -noask: 1 +// Give server time. (6 same commands) +time: 1 +date: 1 +serverdate: 1 +servertime: 1 -//Create a party -party: 1 +// Displays SVN version of the server. +version: 1 -// Change the party item share rules. -partyoption: 1 +// Suicide your character. +die: 1 // Enables you to rename your pet. petrename: 1 -// Command what the player's pet will say. -pettalk: 1 - -//Displays the server rates. -rates: 1 - -// Syncs the position of the player on the client with the one stored in the server. -refresh: 1 - -// Sends a request to all connected GMs (via the gm whisper system) -request: 1 +// Organize a new party, with you as the party leader. +party: 1 -//Shows/Hides the "there is a delay after a skill" message. -showdelay: 1 +// Brings up your personal storage wherever you are. +storage: 1 -//Displays/Hides Experience gained -showexp: 1 +// Opens your mailbox. +mail: 1 -//Displays/Hides Zeny gained -showzeny: 1 +// Locate someone on a map, returns your coordinates if the person isn't on. +where: 1 -// Give server time. (6 same commands) -time: 1 -date: 1 -server_date: 1 -serverdate: 1 -server_time: 1 -servertime: 1 +// Duel organizing commands +duel: 1 +invite: 1 +accept: 1 +reject: 1 +leave: 1 -// Show server uptime -uptime: 1 +// Away messsage +away: 1 +aw: 1 -// Displays SVN version of the server. -version: 1 +// Main chat +main: 1 -// Show who drops an item (mobs with highest drop rate) -whodrops: 1 +// Autorejecting Deals/Invites +noask: 1 -//--------------------------------------------------------------- -// 0: Mail System - SQL Only commands +// Displays remaining jail time +jailtime: 1 -// Opens mail Window. -mail: 1 +// Homunculus commands for players +hominfo: 1 +homstats: 1 //--------------------------- // 10: Super player+ commands -// Suicide your character. -die: 10 +// Displays/Hides Experience gained +showexp: 10 -// Spawns you to set points in major cities. +// Displays/Hides Zeny gained +showzeny: 10 + +// Warps you to predefined locations in major cities. go: 10 -// Brings up your guild storage wherever you are. -gstorage: 10 +// Enables/disables autolooting from killed mobs. +autoloot: 10 -// Create a guild -guild: 10 +// Allows you continue vending offline. +autotrade: 10 +at: 10 -// Brings up your personal storage wherever you are. -storage: 10 +// Change Guild Master of your Guild +changegm: 10 -// Locate someone on a map, returns your coordinates if the person isn't on. -where: 10 +// Change the leader of your party. +changeleader: 10 -// Locates and displays the position of a certain mob on the current map. -mobsearch: 10 +// Change the party exp- and item share rules. +partyoption: 10 -// Changes your apperance. -model: 10 +// Command what the player's pet will say. +pettalk: 10 + +// Command what the player's homunculus will say. +homtalk: 10 +// Locates and displays the position of a certain mob on the current map. +mobsearch: 10 // Locates and displays the position of a certain mob on your mini-map showmobs: 10 - // Prints out in which maps a monster normally spawns at (does not count script-invoked mobs) whereis: 10 -// Changes your size. -size: 10 +// Resets a Star Gladiator's marked maps +feelreset: 10 //---------------------- // 20: Mediator commands -// Change your appearence to other players to a mob. -disguise: 20 - -// Changes GM clothes color (2 same commands) -dye: 20 -ccolor: 20 - -// Do some visual effect on your character -effect: 20 - -// Changes your name to your choice temporarly. -fakename: 20 - -// follow a player (including warping to them) -follow: 20 - -// Displays the motd file to all players -gmotd: 20 - -// Displays helpfile in Athena base directory (2 same commands). +// Displays helpfile in eAthena base directory (2 same commands). help: 20 h: 20 help2: 20 h2: 20 -// Changes GM hair color (2 same commands) -haircolor: 20 -hcolor: 20 - -// Changes GM hair style (2 same commands) -hairstyle: 20 -hstyle: 20 - // Warp yourself to a person (3 same commands + /shift). jumpto: 20 goto: 20 warpto: 20 -// Warp yourself to a person by PID (similar to above, cept you us the PID) -jumptoid2: 20 -gotoid2: 20 -warptoid2: 20 - -// allow other players to hit you out of pvp -killable: 20 +// Displays the motd file to all players +gmotd: 20 -// To get a peco to (un)ride -mountpeco: 20 +// Follow a player (including warping to them) +follow: 20 -// Can command what other npcs (by name) can say. -npctalk: 20 +// Sends a request to all connected GMs (via the gm whisper system) +request: 20 -// Sets the speed you can walk/attack at. Default is 150. -speed: 20 +// Disconnects a user from the server (1 command + right click menu for GM "(name) force to quit"). +kick: 20 -//Restore your normal appearance. -undisguise: 20 +// Changes your appearance. +model: 20 -// Displays distribution of players on the server per map (% on each map which has players) -users: 20 +// To get a peco to (un)ride (2 same commands). +mountpeco: 20 +mount: 20 // Returns list of logged in characters with their position (2 same commands). who: 20 @@ -286,50 +232,58 @@ whomap3: 20 // @who+@who2+who3 whogm: 20 -//-------------------- -// 40: Sub-GM commands +// Displays a sorted list of the ammount of zeny each conected player has at hand. +whozeny: 20 +// Change your appearence to other players to a mob. +disguise: 20 -// Resurects yourself. -alive: 40 +// Restore your normal appearance. +undisguise: 20 + +// Displays the text as a normal message with the format "*name message*" +// instead of "name : message" (Like the /me command in IRC) +me: 20 + +// Changes your name to your choice temporarily. +fakename: 20 + +// Changes your size. +size: 20 -// Levels your character to specified level (adds to your level) (3 same commands). -blvl: 40 -blevel: 40 -baselvl: 40 -baselevel: 40 +// Can command what other npcs (by name) can say. +npctalk: 20 + +//-------------------- +// 40: Sub-GM commands // Broadcast to the whole server. Using (1 command + /nb, /b). broadcast: 40 -// Changes the sex of yourself -changesex: 40 +// Broadcast to the map you are on (1 command + /lb, /nlb). +localbroadcast: 40 -// Deletes floor items in your range of sight -cleanmap: 40 +// Broadcast (with or without name) +kami: 40 +// Same as kami but with blue color +kamib: 40 +// Same as kami but you can choose the color (uses different packet) +kamic: 40 -// drop all your items -dropall: 40 +// Enables GvG on a map (2 same commands). +gvgon: 40 +gpvpon: 40 -//Hatches an egg -hatch: 60 +// Turns GvG (Guild vs. Guild) off on a map (2 same commands). +gvgoff: 40 +gpvpoff: 40 -// Heals yourself to full HP/SP. +// Modifies your HP/SP. heal: 40 -// GM Hide (enables you to be invisible to characters, and most monsters) (1 command + /hide). +// GM Hide (total invisibility to characters and monsters) (1 command + /hide). hide: 40 -//Homunculus commands for gms -homlvup: 40 -homevolution: 40 -makehomun: 40 -homfriendly: 40 -homhungry: 40 - -// Deletes all your items. -itemreset: 40 - // Changes your job to one you specify (2 same commands). job: 40 jobchange: 40 @@ -337,53 +291,15 @@ jobchange: 40 // Enables you to to jump randomly on a map (that you are already on). jump: 40 -// Broadcast (with or without name). -kami: 40 -kamib: 40 - -// Disconnects a user from the server (1 command + right click menu for GM "(name) force to quit"). -kick: 40 - -// Disconnects a user from the server using their PID. -kickid2: 40 - -// Kill all monsters in map (without drops) -killmonster2: 40 - // Warps you to your last save point (2 same commands). load: 40 return: 40 -// Broadcast to the map you are on (1 command + /lb, /nlb). -localbroadcast: 40 - -// To send specified character in jails -jail: 40 - -// To discharge a prisoner (2 same commands) -unjail: 40 -discharge: 40 - -// Timed jailing -jailfor: 40 - -// Raises your job level (3 same commands). -jlvl: 40 -jlevel: 40 -joblvl: 40 -joblevel: 40 - -// Creates yourself a pet egg, have to use Pet ID. -makeegg: 60 +// Warps you to a specific npc +tonpc: 40 -// Warp yourself to a certain map, at (x,y) coordinates (2 same commands). /mm or /mapmove -mapmove: 40 -rura: 40 -warp: 40 - -// Marriage skills -marry: 40 -divorce: 40 +// Saves a warp point. +memo: 40 // Set your character display options. (Visual effects of your character) option: 40 @@ -394,67 +310,106 @@ petfriendly: 40 // Sets hunger level of your pet. pethungry: 40 +// Turns PvP (Person vs. Person) off on a map. +pvpoff: 40 + +// Enables PvP on a map. +pvpon: 40 + // Permanently adds/removes a quest skill questskill: 40 lostskill: 40 +// Sets the speed you can walk/attack at. Default is 150. +speed: 40 + +// Summons spirit spheres around you. +spiritball: 40 + +// Warp yourself to a certain map, at (x,y) coordinates (2 same commands). +mapmove: 40 // (also /mm or /mapmove) +rura: 40 +warp: 40 + +// Changes GM clothes color (2 same commands) +dye: 40 +ccolor: 40 + +// Changes GM hair style (2 same commands) +hairstyle: 40 +hstyle: 40 + +// Changes GM hair color (2 same commands) +haircolor: 40 +hcolor: 40 + +// Deletes all your items. +itemreset: 40 + // Does a skill/stat reset. reset: 40 +// Displays distribution of players on the server per map (% on each map which has players) +users: 40 + +// Deletes floor items in your range of sight +cleanmap: 40 + +// Kill all monsters in map (without drops) +killmonster2: 40 + // Sets your spawn point (aka save point). save: 40 -// look up a skill by name -skillid: 40 +// Do some visual effect on your character +effect: 40 -// What skills are required to get this skill -skilltree: 40 +// Do some visual effect on your character (misceffect) +misceffect: 40 -// Play a Sound! -sound: 40 +// GM's magnifier +identify: 40 -// Enables spirit sphere balls. -spiritball: 40 +// Drop all your items +dropall: 40 -// Change Status of your character -str: 40 -agi: 40 -vit: 40 -int: 40 -dex: 40 -luk: 40 +// Store all your items +storeall: 40 -// Gets all skills (4 same commands) -allskill: 40 -allskills: 40 -skillall: 40 -skillsall: 40 +// Allow other players to hit you out of PvP +killable: 40 -// sets GM stats to maximum (4 same commands) -statall: 40 -statsall: 40 -allstats: 40 -allstat: 40 +// Look up a skill by name +skillid: 40 -// Gives you job points. -stpoint: 40 +// Use a skill by id +useskill: 40 -// Gives you skill points of desired amount. -skpoint: 40 +// What skills are required to get this skill +skilltree: 40 -// store all your items -storeall: 40 +// Marriage commands +marry: 40 +divorce: 40 -// use a skill by id -useskill: 40 +// Adopt a novice into a family +adopt: 40 + +// Play a Sound! +sound: 40 //--------------------- // 50: Sub-GM+ commands -// Spawns a monster, and a certain amount (3 same commands + /monster). -spawn: 50 +// Creates a new guild, with you as the guildmaster. +guild: 50 + +// Brings up your guild storage wherever you are. +gstorage: 50 + +// Spawns a monster, and a certain amount (2 same commands + /monster). monster: 50 -summon: 50 +spawn: 50 // Spawns a smaller sized version of a monster. monstersmall: 50 @@ -462,6 +417,9 @@ monstersmall: 50 // Spawns a larger sized version of a monster. monsterbig: 50 +// Spawns mobs that treat you as their master (they disappear after some time) +summon: 50 + // It will spawn a supportive clone of the given player. clone: 50 @@ -475,40 +433,43 @@ evilclone: 50 //---------------- // 60: GM commands -// Create a static warp portal that lasts until the next reboot -addwarp: 60 - -// To block definitively a player (only administrator can unblock the account) (2 same commands) -block: 60 -charblock: 60 +// Starts Guild Wars +agitstart: 60 -// To unblock a player (2 same commands) -unblock: 60 -charunblock: 60 +// Ends Guild Wars +agitend: 60 -// To ban a player for a limited time (only administrator can unban the account) (4 same commands) -ban: 60 -banish: 60 -charban: 60 -charbanish: 60 +// Resurects yourself. +alive: 60 + +// Levels your character to specified level (adds to your level) (7 same commands). +blvl: 60 +lvup: 60 +blevel: 60 +baselvl: 60 +baselvup: 60 +baselevel: 60 +baselvlup: 60 + +// Raises your job level (6 same commands). +jlvl: 60 +jlevel: 60 +joblvl: 60 +joblvup: 60 +joblevel: 60 +joblvlup: 60 -// To unban a player (4 same commands) -unban: 60 -unbanish: 60 -charunban: 60 -charunbanish: 60 +// Changes the sex of yourself +changesex: 60 // Levels your guild to specified level (2 same commands). +glvl: 60 +glevel: 60 +guildlvl: 60 guildlvup: 60 +guildlevel: 60 guildlvlup: 60 -// Warps all online character of a guild to you. (at least one member of that guild must be on.) -guildrecall: 60 - -// Allows you to spy on any Guilds Guild chat. (at least one member of that guild must be on.) -// NOTE: map server needs to be configured to enable spying to use this command (enable_spy: yes) -guildspy: 60 - // Find an itemID based on item name idsearch: 60 @@ -521,85 +482,142 @@ item2: 60 // Kill another character without hitting them. kill: 60 -// Same as above, cept uses PID. -killid2: 60 - // Kill all monsters in map (with drops) killmonster: 60 -// Enable hitting a player even when not in pvp -killer: 60 +// Creates yourself a pet egg. +makeegg: 60 -// Mute a player (prevents talking, usage of skills and commands) -mute: 80 +// Hatches an egg +hatch: 60 -// Warps all online character of a party to you. (at least one party member must be online.) -partyrecall: 60 +// Instantly kills player whose name is entered and deals insane damage to everything around +nuke: 60 -//Allows you to spy on any party's party chat. (at least one party member must be online.) -// NOTE: map server needs to be configured to enable spying to use this command (enable_spy: yes) -partyspy: 60 +// Enable hitting a player even when not in PvP +killer: 60 // Creates weapon of desired element. produce: 60 -// Turns PVP (Person v. Person) off on a map. -pvpoff: 60 - -// Enables PVP on a map. -pvpon: 60 - // Warps a character to you (1 command + /recall). recall: 60 -// Warps a character to you using their PID. -recallid2: 60 - // Refines all weapons in your items list. refine: 60 // Will repair all broken items in inventory. repairall: 60 -// Revives a character using their PID. -reviveid2: 60 +// Change Status of your character +str: 60 +agi: 60 +vit: 60 +int: 60 +dex: 60 +luk: 60 -// Unmute a player -unmute: 60 +// Gets all skills (4 same commands) +allskill: 60 +allskills: 60 +skillall: 60 +skillsall: 60 + +// Sets GM stats to maximum (4 same commands) +statall: 60 +statsall: 60 +allstats: 60 +allstat: 60 + +// Gives you job points. +stpoint: 60 + +// Gives you skill points of desired amount. +skpoint: 60 + +// Warps all online character of a guild to you. (at least one member of that guild must be on.) +guildrecall: 60 + +// Warps all online character of a party to you. (at least one party member must be online.) +partyrecall: 60 + +// Allows you to spy on any Guilds Guild chat. (at least one member of that guild must be on.) +// NOTE: map server needs to be configured to enable spying to use this command (enable_spy: yes) +guildspy: 60 + +// Allows you to spy on any party's party chat. (at least one party member must be online.) +// NOTE: map server needs to be configured to enable spying to use this command (enable_spy: yes) +partyspy: 60 // Gives you money (zeny) of desired amount. zeny: 60 -//---------------------- -// 80: GM Chief commands +// To block definitively a player (2 same commands) +block: 60 +charblock: 60 -// Starts Guild Wars -agitstart: 60 +// To unblock a player (2 same commands) +unblock: 60 +charunblock: 60 -// Ends Guild Wars -agitend: 60 +// To ban a player for a limited time (4 same commands) +ban: 60 +banish: 60 +charban: 60 +charbanish: 60 + +// To unban a player (4 same commands) +unban: 60 +unbanish: 60 +charunban: 60 +charunbanish: 60 + +// To send specified character in jails +jail: 60 + +// To discharge a prisoner (2 same commands) +unjail: 60 +discharge: 60 + +// Timed jailing +jailfor: 60 + +// Create a static warp portal that lasts until the next reboot +addwarp: 60 + +// Open a trade window with any player +trade: 60 + +// Changes the player's appearance (headgear) +changelook: 60 + +// Homunculus commands for GMs +hlvl: 60 +hlevel: 60 +homlvl: 60 +homlvup: 60 +homlevel: 60 +homevolve: 60 +homevolution: 60 +makehomun: 60 +homfriendly: 60 +homhungry: 60 + +// Re-calculates stats, as if the homun was sent back to level 1 and re-leveled +homshuffle: 60 + +//---------------------- +// 80: GM Chief commands // Set the map you are on to day. day: 80 -// [Un]Disguise All Players (admin command) -disguiseall: 99 -undisguiseall: 99 - // Kills everyone on the server. doom: 80 // Kills everyone on the map you are on. doommap: 80 -// Enables GVG on a map (2 same commands). -gvgon: 40 -gpvpon: 40 - -// Turns GVG (Guild v. Guild) off on a map (2 same commands). -gvgoff: 40 -gpvpoff: 40 - // Set the map you are currently on to night. night: 80 @@ -633,19 +651,14 @@ skillon: 80 // turn skills off for a map skilloff: 80 -//--------------------------- -// 99: Administrator commands - -// Changes the required GM level of an @ command -// (effect lasts until restart or command reload) -adjcmdlvl: 99 +// Mute a player (prevents talking, usage of skills and commands) +mute: 80 -// Changes the GM level of another character -// (lasts until reboot, or gm list reload) -adjgmlvl: 99 +// Unmute a player +unmute: 80 -// Give information about terrain/area (debug function) -gat: 99 +//--------------------------- +// 99: Administrator commands // Disconnect all users from the server kickall: 99 @@ -653,6 +666,12 @@ kickall: 99 // Closes Map-Server mapexit: 99 +// Used for testing packet sends from the client (debug function) +send: 99 + +// Give information about terrain/area (debug function) +gat: 99 + // Displays a status change without really applying it (debug function) displaystatus: 99 @@ -665,10 +684,6 @@ mapinfo: 99 // Set Map Flags (WIP) mapflag: 99 -// Mutes every player on screen (admin command) -mutearea: 99 -stfu: 99 - // Re-load item database (admin command) reloaditemdb: 99 @@ -684,7 +699,10 @@ reloadscript: 99 // Re-load GM level (admin command) reloadgmdb: 99 -// Refresh online status of players - SQL Only +// Change a battle_config flag without rebooting server +setbattleflag: 99 + +// Refresh only status of players - SQL Only refreshonline: 99 // Re-load gm command config (admin command) @@ -704,11 +722,21 @@ reloadpcdb: 99 // Re-load the Message of the Day (admin command) reloadmotd: 99 -// Used for testing packet sends from the client (debug function) -send: 99 +// Changes the GM level of another character +// (lasts until reboot, or gm list reload) +adjgmlvl: 99 -// change a battle_config flag without rebooting server -setbattleflag: 99 +// Changes the required GM level of an @ command +// (effect lasts until restart or command reload) +adjcmdlvl: 99 + +// [Un]Disguise All Players (admin command) +disguiseall: 99 +undisguiseall: 99 + +// Mutes every player on screen (admin command) +mutearea: 99 +stfu: 99 // Makes you immune to attacks (monsters/players/skills cannot target/hit you, admin command) monsterignore: 99 @@ -737,8 +765,6 @@ clearweather: 99 //--------------------------------------------------------------- // 100: Disabled commands gm: 100 -nuke: 100 - //--------------------- // OTHER: not a command diff --git a/conf/charcommand_athena.conf b/conf/charcommand_athena.conf index acd89779a..20e0c2427 100644 --- a/conf/charcommand_athena.conf +++ b/conf/charcommand_athena.conf @@ -1,10 +1,12 @@ -// Athena charcommand Configuration file. -// Translated by Peter Kieser +//-------------------------------------------------------------- +// eAthena charcommand configuration file. +// Originally translated by Peter Kieser +//-------------------------------------------------------------- // The symbol that will be used to recognize commands. -// You can set any one character, except control-characters (0x00-0x1f), +// You can set any one character except control-characters (0x00-0x1f), // '%', '$' (party/guild chat speaking) and '/' (standard client commands). -// The symbol must be different from from the standard GM command symbol. +// The symbol must also be different from from the GM atcommand symbol. command_symbol: # @@ -21,6 +23,9 @@ command_symbol: # //---------------------- // 20: Mediator commands +// Displays helpfile in eAthena base directory +help: 20 + //-------------------- // 40: Sub-GM commands @@ -120,6 +125,12 @@ delitem: 60 disguise: 60 undisguise: 60 +// Drop a players possessions on the ground +dropall: 60 + +// Put a players possessions in storage +storeall: 60 + // Resets another character's designated maps feelreset: 60 diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 8a23c9d05..a93bddb3d 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -13,11 +13,12 @@ #include "../common/utils.h" #include "atcommand.h" -#include "log.h" +#include "battle.h" #include "clif.h" #include "chrif.h" #include "intif.h" #include "itemdb.h" +#include "log.h" #include "map.h" #include "pc.h" #include "status.h" @@ -25,12 +26,10 @@ #include "mob.h" #include "npc.h" #include "pet.h" -#include "mercenary.h" //[orn] -#include "battle.h" +#include "mercenary.h" #include "party.h" #include "guild.h" #include "script.h" -#include "npc.h" #include "trade.h" #include "unit.h" @@ -43,539 +42,25 @@ #include #include -char atcommand_symbol = '@'; // first char of the commands (by [Yor]) - -char *msg_table[MAX_MSG]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) +// extern variables +char atcommand_symbol = '@'; // first char of the commands +char* msg_table[MAX_MSG]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) +// local declarations #define ACMD_FUNC(x) int atcommand_ ## x (const int fd, struct map_session_data* sd, const char* command, const char* message) -ACMD_FUNC(broadcast); -ACMD_FUNC(localbroadcast); -ACMD_FUNC(rura); -ACMD_FUNC(where); -ACMD_FUNC(jumpto); -ACMD_FUNC(jump); -ACMD_FUNC(who); -ACMD_FUNC(who2); -ACMD_FUNC(who3); -ACMD_FUNC(whomap); -ACMD_FUNC(whomap2); -ACMD_FUNC(whomap3); -ACMD_FUNC(whogm); // by Yor -ACMD_FUNC(whozeny); // [Valaris] -ACMD_FUNC(save); -ACMD_FUNC(load); -ACMD_FUNC(speed); -ACMD_FUNC(storage); -ACMD_FUNC(guildstorage); -ACMD_FUNC(option); -ACMD_FUNC(hide); -ACMD_FUNC(jobchange); -ACMD_FUNC(die); -ACMD_FUNC(kill); -ACMD_FUNC(alive); -ACMD_FUNC(kami); -ACMD_FUNC(heal); -ACMD_FUNC(item); -ACMD_FUNC(item2); -ACMD_FUNC(itemreset); -ACMD_FUNC(baselevelup); -ACMD_FUNC(joblevelup); -ACMD_FUNC(help); -ACMD_FUNC(help2); -ACMD_FUNC(gm); -ACMD_FUNC(pvpoff); -ACMD_FUNC(pvpon); -ACMD_FUNC(gvgoff); -ACMD_FUNC(gvgon); -ACMD_FUNC(model); -ACMD_FUNC(go); -ACMD_FUNC(monster); -ACMD_FUNC(monstersmall); -ACMD_FUNC(monsterbig); -ACMD_FUNC(spawn); -ACMD_FUNC(killmonster); -ACMD_FUNC(killmonster2); -ACMD_FUNC(refine); -ACMD_FUNC(produce); -ACMD_FUNC(memo); -ACMD_FUNC(gat); -ACMD_FUNC(displaystatus); -ACMD_FUNC(statuspoint); -ACMD_FUNC(skillpoint); -ACMD_FUNC(zeny); -ACMD_FUNC(param); -ACMD_FUNC(guildlevelup); -ACMD_FUNC(makeegg); -ACMD_FUNC(hatch); -ACMD_FUNC(petfriendly); -ACMD_FUNC(pethungry); -ACMD_FUNC(petrename); -ACMD_FUNC(recall); -ACMD_FUNC(recallall); -ACMD_FUNC(night); -ACMD_FUNC(day); -ACMD_FUNC(doom); -ACMD_FUNC(doommap); -ACMD_FUNC(raise); -ACMD_FUNC(raisemap); -ACMD_FUNC(kick); -ACMD_FUNC(kickall); -ACMD_FUNC(allskill); -ACMD_FUNC(questskill); -ACMD_FUNC(lostskill); -ACMD_FUNC(spiritball); -ACMD_FUNC(party); -ACMD_FUNC(guild); -ACMD_FUNC(agitstart); -ACMD_FUNC(agitend); -ACMD_FUNC(reloaditemdb); -ACMD_FUNC(reloadmobdb); -ACMD_FUNC(reloadskilldb); -ACMD_FUNC(reloadscript); -ACMD_FUNC(reloadgmdb); // by Yor -ACMD_FUNC(reloadatcommand); -ACMD_FUNC(reloadbattleconf); -ACMD_FUNC(reloadstatusdb); -ACMD_FUNC(reloadpcdb); -ACMD_FUNC(reloadmotd); // [Valaris] -ACMD_FUNC(mapexit); -ACMD_FUNC(idsearch); -ACMD_FUNC(mapinfo); -ACMD_FUNC(dye); //** by fritz -ACMD_FUNC(hair_style); //** by fritz -ACMD_FUNC(hair_color); //** by fritz -ACMD_FUNC(stat_all); //** by fritz -ACMD_FUNC(char_block); // by Yor -ACMD_FUNC(char_ban); // by Yor -ACMD_FUNC(char_unblock); // by Yor -ACMD_FUNC(char_unban); // by Yor -ACMD_FUNC(mount_peco); // by Valaris -ACMD_FUNC(guildspy); // [Syrus22] -ACMD_FUNC(partyspy); // [Syrus22] -ACMD_FUNC(repairall); // [Valaris] -ACMD_FUNC(guildrecall); // by Yor -ACMD_FUNC(partyrecall); // by Yor -ACMD_FUNC(nuke); // [Valaris] -ACMD_FUNC(shownpc); -ACMD_FUNC(hidenpc); -ACMD_FUNC(loadnpc); -ACMD_FUNC(unloadnpc); -ACMD_FUNC(servertime); // by Yor -ACMD_FUNC(jail); // by Yor -ACMD_FUNC(unjail); // by Yor -ACMD_FUNC(jailfor); // Alias Meruru -ACMD_FUNC(jailtime); // Coltaro -ACMD_FUNC(disguise); // [Valaris] -ACMD_FUNC(undisguise); // by Yor -ACMD_FUNC(email); // by Yor -ACMD_FUNC(effect);//by Apple -ACMD_FUNC(addwarp); // by MouseJstr -ACMD_FUNC(follow); // by MouseJstr -ACMD_FUNC(skillon); // by MouseJstr -ACMD_FUNC(skilloff); // by MouseJstr -ACMD_FUNC(killer); // by MouseJstr -ACMD_FUNC(npcmove); // by MouseJstr -ACMD_FUNC(killable); // by MouseJstr -ACMD_FUNC(dropall); // by MouseJstr -ACMD_FUNC(storeall); // by MouseJstr -ACMD_FUNC(skillid); // by MouseJstr -ACMD_FUNC(useskill); // by MouseJstr -ACMD_FUNC(displayskill); //[Skotlex] -ACMD_FUNC(summon); -ACMD_FUNC(rain); -ACMD_FUNC(snow); -ACMD_FUNC(sakura); -ACMD_FUNC(clouds); -ACMD_FUNC(clouds2); // [Valaris] -ACMD_FUNC(fog); -ACMD_FUNC(fireworks); -ACMD_FUNC(leaves); -ACMD_FUNC(adjgmlvl); // by MouseJstr -ACMD_FUNC(adjcmdlvl); // by MouseJstr -ACMD_FUNC(trade); // by MouseJstr -ACMD_FUNC(send); // by davidsiaw -ACMD_FUNC(setbattleflag); // by MouseJstr -ACMD_FUNC(unmute); // [Valaris] -ACMD_FUNC(clearweather); // Dexity -ACMD_FUNC(uptime); // by MC Cameri -ACMD_FUNC(changesex); // by MC Cameri -ACMD_FUNC(mute); // celest -ACMD_FUNC(refresh); // by MC Cameri -ACMD_FUNC(identify); // by MC Cameri -ACMD_FUNC(gmotd); // Added by MC Cameri, created by davidsiaw -ACMD_FUNC(misceffect); // by MC Cameri -ACMD_FUNC(mobsearch); -ACMD_FUNC(cleanmap); -ACMD_FUNC(npctalk); -ACMD_FUNC(pettalk); -ACMD_FUNC(users); -ACMD_FUNC(reset); -ACMD_FUNC(autoloot); // Improved version imported from Freya. -ACMD_FUNC(skilltree); // by MouseJstr -ACMD_FUNC(marry); // by MouseJstr -ACMD_FUNC(divorce); // by MouseJstr -ACMD_FUNC(jumptoid2); // by Dino9021 -ACMD_FUNC(recallid2); // by Dino9021 -ACMD_FUNC(kickid2); // by Dino9021 -ACMD_FUNC(reviveid2); // by Dino9021 -ACMD_FUNC(killid2); // by Dino9021 -ACMD_FUNC(sound); -ACMD_FUNC(undisguiseall); -ACMD_FUNC(disguiseall); -ACMD_FUNC(changelook); -ACMD_FUNC(mobinfo); //by Lupus -ACMD_FUNC(exp); // by Skotlex -ACMD_FUNC(adopt); // by Veider -ACMD_FUNC(version); // by Ancyker -ACMD_FUNC(mutearea); // by MouseJstr -ACMD_FUNC(rates); // by MouseJstr -ACMD_FUNC(iteminfo); // Lupus -ACMD_FUNC(whodrops); //Skotlex -ACMD_FUNC(whereis); //Skotlex -ACMD_FUNC(mapflag); // Lupus -ACMD_FUNC(me); //added by massdriller, code by lordalfa -ACMD_FUNC(monsterignore); // [Valaris] -ACMD_FUNC(fakename); //[Valaris] -ACMD_FUNC(size); //[Valaris] -ACMD_FUNC(showexp); //moved from charcommand [Kevin] -ACMD_FUNC(showzeny); -ACMD_FUNC(showdelay); //moved from charcommand [Kevin] -ACMD_FUNC(autotrade);// durf -ACMD_FUNC(changeleader);// [Skotlex] -ACMD_FUNC(partyoption);// [Skotlex] -ACMD_FUNC(changegm);// durf -// Duel [LuzZza] -ACMD_FUNC(invite); -ACMD_FUNC(duel); -ACMD_FUNC(leave); -ACMD_FUNC(accept); -ACMD_FUNC(reject); -ACMD_FUNC(away); // LuzZza -ACMD_FUNC(main); // LuzZza -ACMD_FUNC(clone); // [Valaris] -ACMD_FUNC(tonpc); // LuzZza -ACMD_FUNC(commands); // [Skotlex] -ACMD_FUNC(noask); //LuzZza -ACMD_FUNC(request); //[Skotlex] -ACMD_FUNC(homlevel); //[orn] -ACMD_FUNC(homevolution); //[orn] -ACMD_FUNC(makehomun); //[orn] -ACMD_FUNC(homfriendly); //[orn] -ACMD_FUNC(homhungry); //[orn] -ACMD_FUNC(homtalk); //[orn] -ACMD_FUNC(hominfo); //[Toms] -ACMD_FUNC(homstats); //[Skotlex] -ACMD_FUNC(homshuffle); //[Skotlex] -ACMD_FUNC(showmobs); //KarLaeda -ACMD_FUNC(feelreset); //[HiddenDragon] -#ifndef TXT_ONLY -ACMD_FUNC(mail); // [MAIL SYSTEM] -ACMD_FUNC(refreshonline); // [Valaris] -#endif -#ifdef DMALLOC -ACMD_FUNC(dmstart); // by MouseJstr -ACMD_FUNC(dmtick); // by MouseJstr -#endif -/*========================================== - *AtCommandInfo atcommand_info[] structure definition - *------------------------------------------*/ - -// First char of commands is configured in atcommand_athena.conf. Leave @ in this list for default value. -// to set default level, read atcommand_athena.conf first please. -static AtCommandInfo atcommand_info[] = { - { AtCommand_Rura, "@rura", 40, atcommand_rura }, - { AtCommand_Warp, "@warp", 40, atcommand_rura }, - { AtCommand_MapMove, "@mapmove", 40, atcommand_rura }, // /mm command - { AtCommand_Where, "@where", 1, atcommand_where }, - { AtCommand_JumpTo, "@jumpto", 20, atcommand_jumpto }, // + /shift - { AtCommand_JumpTo, "@warpto", 20, atcommand_jumpto }, - { AtCommand_JumpTo, "@goto", 20, atcommand_jumpto }, - { AtCommand_Jump, "@jump", 40, atcommand_jump }, - { AtCommand_Who, "@who", 20, atcommand_who }, - { AtCommand_Who, "@whois", 20, atcommand_who }, - { AtCommand_Who2, "@who2", 20, atcommand_who2 }, - { AtCommand_Who3, "@who3", 20, atcommand_who3 }, - { AtCommand_WhoMap, "@whomap", 20, atcommand_whomap }, - { AtCommand_WhoMap2, "@whomap2", 20, atcommand_whomap2 }, - { AtCommand_WhoMap3, "@whomap3", 20, atcommand_whomap3 }, - { AtCommand_WhoGM, "@whogm", 20, atcommand_whogm }, // by Yor - { AtCommand_Save, "@save", 40, atcommand_save }, - { AtCommand_Load, "@return", 40, atcommand_load }, - { AtCommand_Load, "@load", 40, atcommand_load }, - { AtCommand_Speed, "@speed", 40, atcommand_speed }, - { AtCommand_Storage, "@storage", 1, atcommand_storage }, - { AtCommand_GuildStorage, "@gstorage", 50, atcommand_guildstorage }, - { AtCommand_Option, "@option", 40, atcommand_option }, - { AtCommand_Hide, "@hide", 40, atcommand_hide }, // + /hide - { AtCommand_JobChange, "@jobchange", 40, atcommand_jobchange }, - { AtCommand_JobChange, "@job", 40, atcommand_jobchange }, - { AtCommand_Die, "@die", 1, atcommand_die }, - { AtCommand_Kill, "@kill", 60, atcommand_kill }, - { AtCommand_Alive, "@alive", 60, atcommand_alive }, - { AtCommand_Kami, "@kami", 40, atcommand_kami }, - { AtCommand_KamiB, "@kamib", 40, atcommand_kami }, - { AtCommand_KamiC, "@kamic", 40, atcommand_kami }, //[LuzZza] - { AtCommand_Heal, "@heal", 40, atcommand_heal }, - { AtCommand_Item, "@item", 60, atcommand_item }, - { AtCommand_Item2, "@item2", 60, atcommand_item2 }, - { AtCommand_ItemReset, "@itemreset", 40, atcommand_itemreset }, - { AtCommand_BaseLevelUp, "@baselvl", 60, atcommand_baselevelup }, - { AtCommand_BaseLevelUp, "@baselevel", 60, atcommand_baselevelup }, - { AtCommand_BaseLevelUp, "@blevel", 60, atcommand_baselevelup }, - { AtCommand_BaseLevelUp, "@blvl", 60, atcommand_baselevelup }, - { AtCommand_JobLevelUp, "@jlvl", 60, atcommand_joblevelup }, - { AtCommand_JobLevelUp, "@jlevel", 60, atcommand_joblevelup }, - { AtCommand_JobLevelUp, "@joblvl", 60, atcommand_joblevelup }, - { AtCommand_JobLevelUp, "@joblevel", 60, atcommand_joblevelup }, - { AtCommand_H, "@h", 20, atcommand_help }, - { AtCommand_Help, "@help", 20, atcommand_help }, - { AtCommand_H2, "@h2", 20, atcommand_help2 }, - { AtCommand_Help2, "@help2", 20, atcommand_help2 }, - { AtCommand_GM, "@gm", 100,atcommand_gm }, - { AtCommand_PvPOff, "@pvpoff", 40, atcommand_pvpoff }, - { AtCommand_PvPOn, "@pvpon", 40, atcommand_pvpon }, - { AtCommand_GvGOff, "@gvgoff", 40, atcommand_gvgoff }, - { AtCommand_GvGOff, "@gpvpoff", 40, atcommand_gvgoff }, - { AtCommand_GvGOn, "@gvgon", 40, atcommand_gvgon }, - { AtCommand_GvGOn, "@gpvpon", 40, atcommand_gvgon }, - { AtCommand_Model, "@model", 20, atcommand_model }, - { AtCommand_Go, "@go", 10, atcommand_go }, - { AtCommand_Spawn, "@monster", 50, atcommand_monster }, - { AtCommand_Spawn, "@spawn", 50, atcommand_monster }, - { AtCommand_MonsterSmall, "@monstersmall", 50, atcommand_monstersmall }, - { AtCommand_MonsterBig, "@monsterbig", 50, atcommand_monsterbig }, - { AtCommand_KillMonster, "@killmonster", 60, atcommand_killmonster }, - { AtCommand_KillMonster2, "@killmonster2", 40, atcommand_killmonster2 }, - { AtCommand_Refine, "@refine", 60, atcommand_refine }, - { AtCommand_Produce, "@produce", 60, atcommand_produce }, - { AtCommand_Memo, "@memo", 40, atcommand_memo }, - { AtCommand_GAT, "@gat", 99, atcommand_gat }, - { AtCommand_DisplayStatus, "@displaystatus", 99, atcommand_displaystatus }, - { AtCommand_StatusPoint, "@stpoint", 60, atcommand_statuspoint }, - { AtCommand_SkillPoint, "@skpoint", 60, atcommand_skillpoint }, - { AtCommand_Zeny, "@zeny", 60, atcommand_zeny }, - { AtCommand_Strength, "@str", 60, atcommand_param }, - { AtCommand_Agility, "@agi", 60, atcommand_param }, - { AtCommand_Vitality, "@vit", 60, atcommand_param }, - { AtCommand_Intelligence, "@int", 60, atcommand_param }, - { AtCommand_Dexterity, "@dex", 60, atcommand_param }, - { AtCommand_Luck, "@luk", 60, atcommand_param }, - { AtCommand_GuildLevelUp, "@glvl", 60, atcommand_guildlevelup }, - { AtCommand_GuildLevelUp, "@glevel", 60, atcommand_guildlevelup }, - { AtCommand_GuildLevelUp, "@guildlvl", 60, atcommand_guildlevelup }, - { AtCommand_GuildLevelUp, "@guildlevel", 60, atcommand_guildlevelup }, - { AtCommand_MakeEgg, "@makeegg", 60, atcommand_makeegg }, - { AtCommand_Hatch, "@hatch", 60, atcommand_hatch }, - { AtCommand_PetFriendly, "@petfriendly", 40, atcommand_petfriendly }, - { AtCommand_PetHungry, "@pethungry", 40, atcommand_pethungry }, - { AtCommand_PetRename, "@petrename", 1, atcommand_petrename }, - { AtCommand_Recall, "@recall", 60, atcommand_recall }, // + /recall - { AtCommand_Night, "@night", 80, atcommand_night }, - { AtCommand_Day, "@day", 80, atcommand_day }, - { AtCommand_Doom, "@doom", 80, atcommand_doom }, - { AtCommand_DoomMap, "@doommap", 80, atcommand_doommap }, - { AtCommand_Raise, "@raise", 80, atcommand_raise }, - { AtCommand_RaiseMap, "@raisemap", 80, atcommand_raisemap }, - { AtCommand_Kick, "@kick", 20, atcommand_kick }, // + right click menu for GM "(name) force to quit" - { AtCommand_KickAll, "@kickall", 99, atcommand_kickall }, - { AtCommand_AllSkill, "@allskill", 60, atcommand_allskill }, - { AtCommand_AllSkill, "@allskills", 60, atcommand_allskill }, - { AtCommand_AllSkill, "@skillall", 60, atcommand_allskill }, - { AtCommand_AllSkill, "@skillsall", 60, atcommand_allskill }, - { AtCommand_QuestSkill, "@questskill", 40, atcommand_questskill }, - { AtCommand_LostSkill, "@lostskill", 40, atcommand_lostskill }, - { AtCommand_SpiritBall, "@spiritball", 40, atcommand_spiritball }, - { AtCommand_Party, "@party", 1, atcommand_party }, - { AtCommand_Guild, "@guild", 50, atcommand_guild }, - { AtCommand_AgitStart, "@agitstart", 60, atcommand_agitstart }, - { AtCommand_AgitEnd, "@agitend", 60, atcommand_agitend }, - { AtCommand_MapExit, "@mapexit", 99, atcommand_mapexit }, - { AtCommand_IDSearch, "@idsearch", 60, atcommand_idsearch }, - { AtCommand_Broadcast, "@broadcast", 40, atcommand_broadcast }, // /b and /nb command - { AtCommand_LocalBroadcast, "@localbroadcast", 40, atcommand_localbroadcast }, // /lb and /nlb command - { AtCommand_RecallAll, "@recallall", 80, atcommand_recallall }, - { AtCommand_ReloadItemDB, "@reloaditemdb", 99, atcommand_reloaditemdb }, // admin command - { AtCommand_ReloadMobDB, "@reloadmobdb", 99, atcommand_reloadmobdb }, // admin command - { AtCommand_ReloadSkillDB, "@reloadskilldb", 99, atcommand_reloadskilldb }, // admin command - { AtCommand_ReloadScript, "@reloadscript", 99, atcommand_reloadscript }, // admin command - { AtCommand_ReloadGMDB, "@reloadgmdb", 99, atcommand_reloadgmdb }, // admin command - { AtCommand_ReloadAtcommand, "@reloadatcommand", 99, atcommand_reloadatcommand }, - { AtCommand_ReloadBattleConf, "@reloadbattleconf",99, atcommand_reloadbattleconf }, - { AtCommand_ReloadStatusDB, "@reloadstatusdb", 99, atcommand_reloadstatusdb }, - { AtCommand_ReloadPcDB, "@reloadpcdb", 99, atcommand_reloadpcdb }, - { AtCommand_ReloadMOTD, "@reloadmotd", 99, atcommand_reloadmotd }, // [Valaris] - { AtCommand_MapInfo, "@mapinfo", 99, atcommand_mapinfo }, - { AtCommand_Dye, "@dye", 40, atcommand_dye }, // by fritz - { AtCommand_Dye, "@ccolor", 40, atcommand_dye }, // by fritz - { AtCommand_Hstyle, "@hairstyle", 40, atcommand_hair_style }, // by fritz - { AtCommand_Hstyle, "@hstyle", 40, atcommand_hair_style }, // by fritz - { AtCommand_Hcolor, "@haircolor", 40, atcommand_hair_color }, // by fritz - { AtCommand_Hcolor, "@hcolor", 40, atcommand_hair_color }, // by fritz - { AtCommand_StatAll, "@statall", 60, atcommand_stat_all }, // by fritz - { AtCommand_StatAll, "@statsall", 60, atcommand_stat_all }, - { AtCommand_StatAll, "@allstats", 60, atcommand_stat_all }, // by fritz - { AtCommand_StatAll, "@allstat", 60, atcommand_stat_all }, // by fritz - { AtCommand_CharBlock, "@block", 60, atcommand_char_block }, // by Yor - { AtCommand_CharBlock, "@charblock", 60, atcommand_char_block }, // by Yor - { AtCommand_CharBan, "@ban", 60, atcommand_char_ban }, // by Yor - { AtCommand_CharBan, "@banish", 60, atcommand_char_ban }, // by Yor - { AtCommand_CharBan, "@charban", 60, atcommand_char_ban }, // by Yor - { AtCommand_CharBan, "@charbanish", 60, atcommand_char_ban }, // by Yor - { AtCommand_CharUnBlock, "@unblock", 60, atcommand_char_unblock }, // by Yor - { AtCommand_CharUnBlock, "@charunblock", 60, atcommand_char_unblock }, // by Yor - { AtCommand_CharUnBan, "@unban", 60, atcommand_char_unban }, // by Yor - { AtCommand_CharUnBan, "@unbanish", 60, atcommand_char_unban }, // by Yor - { AtCommand_CharUnBan, "@charunban", 60, atcommand_char_unban }, // by Yor - { AtCommand_CharUnBan, "@charunbanish", 60, atcommand_char_unban }, // by Yor - { AtCommand_MountPeco, "@mount", 20, atcommand_mount_peco }, // by Valaris - { AtCommand_MountPeco, "@mountpeco", 20, atcommand_mount_peco }, // by Valaris - { AtCommand_GuildSpy, "@guildspy", 60, atcommand_guildspy }, // [Syrus22] - { AtCommand_PartySpy, "@partyspy", 60, atcommand_partyspy }, // [Syrus22] - { AtCommand_RepairAll, "@repairall", 60, atcommand_repairall }, // [Valaris] - { AtCommand_GuildRecall, "@guildrecall", 60, atcommand_guildrecall }, // by Yor - { AtCommand_PartyRecall, "@partyrecall", 60, atcommand_partyrecall }, // by Yor - { AtCommand_Nuke, "@nuke", 60, atcommand_nuke }, // [Valaris] - { AtCommand_Shownpc, "@shownpc", 80, atcommand_shownpc }, // [] - { AtCommand_Hidenpc, "@hidenpc", 80, atcommand_hidenpc }, // [] - { AtCommand_Loadnpc, "@loadnpc", 80, atcommand_loadnpc }, // [] - { AtCommand_Unloadnpc, "@unloadnpc", 80, atcommand_unloadnpc }, // [] - { AtCommand_ServerTime, "@time", 1, atcommand_servertime }, // by Yor - { AtCommand_ServerTime, "@date", 1, atcommand_servertime }, // by Yor - { AtCommand_ServerTime, "@serverdate", 1, atcommand_servertime }, // by Yor - { AtCommand_ServerTime, "@servertime", 1, atcommand_servertime }, // by Yor - { AtCommand_Jail, "@jail", 60, atcommand_jail }, // by Yor - { AtCommand_UnJail, "@unjail", 60, atcommand_unjail }, // by Yor - { AtCommand_UnJail, "@discharge", 60, atcommand_unjail }, // by Yor - { AtCommand_JailFor, "@jailfor", 60, atcommand_jailfor }, //Meruru - { AtCommand_JailTime, "@jailtime", 1, atcommand_jailtime }, //Change this to 0 in atcommand_conf.txt if you want it accessible to players (you most likely will ;)) - { AtCommand_Disguise, "@disguise", 20, atcommand_disguise }, // [Valaris] - { AtCommand_UnDisguise, "@undisguise", 20, atcommand_undisguise }, // by Yor - { AtCommand_EMail, "@email", 1, atcommand_email }, // by Yor - { AtCommand_Effect, "@effect", 40, atcommand_effect }, // by Apple - { AtCommand_Follow, "@follow", 20, atcommand_follow }, // by MouseJstr - { AtCommand_AddWarp, "@addwarp", 60, atcommand_addwarp }, // by MouseJstr - { AtCommand_SkillOn, "@skillon", 80, atcommand_skillon }, // by MouseJstr - { AtCommand_SkillOff, "@skilloff", 80, atcommand_skilloff }, // by MouseJstr - { AtCommand_Killer, "@killer", 60, atcommand_killer }, // by MouseJstr - { AtCommand_NpcMove, "@npcmove", 80, atcommand_npcmove }, // by MouseJstr - { AtCommand_Killable, "@killable", 40, atcommand_killable }, // by MouseJstr - { AtCommand_Dropall, "@dropall", 40, atcommand_dropall }, // MouseJstr - { AtCommand_Storeall, "@storeall", 40, atcommand_storeall }, // MouseJstr - { AtCommand_Skillid, "@skillid", 40, atcommand_skillid }, // MouseJstr - { AtCommand_Useskill, "@useskill", 40, atcommand_useskill }, // MouseJstr - { AtCommand_DisplaySkill, "@displayskill", 99, atcommand_displayskill }, // Skotlex - { AtCommand_Snow, "@snow", 99, atcommand_snow }, - { AtCommand_Sakura, "@sakura", 99, atcommand_sakura }, - { AtCommand_Clouds, "@clouds", 99, atcommand_clouds }, - { AtCommand_Clouds2, "@clouds2", 99, atcommand_clouds2 }, - { AtCommand_Fog, "@fog", 99, atcommand_fog }, - { AtCommand_Fireworks, "@fireworks", 99, atcommand_fireworks }, - { AtCommand_Leaves, "@leaves", 99, atcommand_leaves }, - { AtCommand_Summon, "@summon", 60, atcommand_summon }, - { AtCommand_AdjGmLvl, "@adjgmlvl", 99, atcommand_adjgmlvl }, - { AtCommand_AdjCmdLvl, "@adjcmdlvl", 99, atcommand_adjcmdlvl }, - { AtCommand_Trade, "@trade", 60, atcommand_trade }, - { AtCommand_Send, "@send", 99, atcommand_send }, - { AtCommand_SetBattleFlag, "@setbattleflag", 99, atcommand_setbattleflag }, - { AtCommand_UnMute, "@unmute", 80, atcommand_unmute }, // [Valaris] - { AtCommand_Clearweather, "@clearweather", 99, atcommand_clearweather }, // Dexity - { AtCommand_UpTime, "@uptime", 1, atcommand_uptime }, // by MC Cameri - { AtCommand_ChangeSex, "@changesex", 60, atcommand_changesex }, // by MC Cameri <- do we still need this? [Foruken] <- why not? [Skotlex] - { AtCommand_Mute, "@mute", 80, atcommand_mute }, // [celest] - { AtCommand_WhoZeny, "@whozeny", 20, atcommand_whozeny }, // [Valaris] - { AtCommand_Refresh, "@refresh", 1, atcommand_refresh }, // by MC Cameri - { AtCommand_Identify, "@identify", 40, atcommand_identify }, // by MC Cameri - { AtCommand_Gmotd, "@gmotd", 20, atcommand_gmotd }, // Added by MC Cameri, created by davidsiaw - { AtCommand_MiscEffect, "@misceffect", 50, atcommand_misceffect }, // by MC Cameri - { AtCommand_MobSearch, "@mobsearch", 10, atcommand_mobsearch }, - { AtCommand_CleanMap, "@cleanmap", 40, atcommand_cleanmap }, - { AtCommand_NpcTalk, "@npctalk", 20, atcommand_npctalk }, - { AtCommand_PetTalk, "@pettalk", 10, atcommand_pettalk }, - { AtCommand_Users, "@users", 40, atcommand_users }, - { AtCommand_ResetState, "@reset", 40, atcommand_reset }, - { AtCommand_SkillTree, "@skilltree", 40, atcommand_skilltree }, // [MouseJstr] - { AtCommand_Marry, "@marry", 40, atcommand_marry }, // [MouseJstr] - { AtCommand_Divorce, "@divorce", 40, atcommand_divorce }, // [MouseJstr] - { AtCommand_JumpToId2, "@jumptoid2", 20, atcommand_jumptoid2 }, // [Dino9021] - { AtCommand_JumpToId2, "@warptoid2", 20, atcommand_jumptoid2 }, // [Dino9021] - { AtCommand_JumpToId2, "@gotoid2", 20, atcommand_jumptoid2 }, // [Dino9021] - { AtCommand_RecallId2, "@recallid2", 60, atcommand_recallid2 }, // [Dino9021] - { AtCommand_KickId2, "@kickid2", 99, atcommand_kickid2 }, // [Dino9021] - { AtCommand_ReviveId2, "@reviveid2", 60, atcommand_reviveid2 }, // [Dino9021] - { AtCommand_KillId2, "@killid2", 60, atcommand_killid2 }, // [Dino9021] - { AtCommand_Sound, "@sound", 40, atcommand_sound }, - { AtCommand_UndisguiseAll, "@undisguiseall", 99, atcommand_undisguiseall }, - { AtCommand_DisguiseAll, "@disguiseall", 99, atcommand_disguiseall }, - { AtCommand_ChangeLook, "@changelook", 60, atcommand_changelook }, - { AtCommand_AutoLoot, "@autoloot", 10, atcommand_autoloot }, // Upa-Kun - { AtCommand_MobInfo, "@mobinfo", 1, atcommand_mobinfo }, // [Lupus] - { AtCommand_MobInfo, "@monsterinfo", 1, atcommand_mobinfo }, // [Lupus] - { AtCommand_MobInfo, "@mi", 1, atcommand_mobinfo }, // [Lupus] - { AtCommand_Exp, "@exp", 1, atcommand_exp }, // [Skotlex] - { AtCommand_Adopt, "@adopt", 40, atcommand_adopt }, // [Veider] - { AtCommand_Version, "@version", 1, atcommand_version }, - { AtCommand_MuteArea, "@mutearea", 99, atcommand_mutearea }, // MouseJstr - { AtCommand_MuteArea, "@stfu", 99, atcommand_mutearea }, // MouseJstr - { AtCommand_Rates, "@rates", 1, atcommand_rates }, // MouseJstr - { AtCommand_ItemInfo, "@iteminfo", 1, atcommand_iteminfo }, // [Lupus] - { AtCommand_ItemInfo, "@ii", 1, atcommand_iteminfo }, // [Lupus] - { AtCommand_WhoDrops, "@whodrops", 1, atcommand_whodrops }, // [Skotlex] - { AtCommand_WhereIs, "@whereis", 10, atcommand_whereis }, // [Skotlex] - { AtCommand_MapFlag, "@mapflag", 99, atcommand_mapflag }, // [Lupus] - { AtCommand_Me, "@me", 20, atcommand_me }, //added by massdriller, code by lordalfa - { AtCommand_MonsterIgnore, "@monsterignore", 99, atcommand_monsterignore }, // [Valaris] - { AtCommand_MonsterIgnore, "@battleignore", 99, atcommand_monsterignore }, - { AtCommand_FakeName, "@fakename", 20, atcommand_fakename }, // [Valaris] - { AtCommand_Size, "@size", 20, atcommand_size }, - { AtCommand_ShowExp, "@showexp", 10, atcommand_showexp}, - { AtCommand_ShowZeny, "@showzeny", 10, atcommand_showzeny}, - { AtCommand_ShowDelay, "@showdelay", 1, atcommand_showdelay}, - { AtCommand_AutoTrade, "@autotrade", 10, atcommand_autotrade }, // durf - { AtCommand_AutoTrade, "@at", 10, atcommand_autotrade }, - { AtCommand_ChangeGM, "@changegm", 10, atcommand_changegm }, // durf - { AtCommand_ChangeLeader, "@changeleader", 10, atcommand_changeleader }, // durf - { AtCommand_PartyOption, "@partyoption", 10, atcommand_partyoption}, // durf - { AtCommand_Invite, "@invite", 1, atcommand_invite }, // By LuzZza - { AtCommand_Duel, "@duel", 1, atcommand_duel }, // By LuzZza - { AtCommand_Leave, "@leave", 1, atcommand_leave }, // By LuzZza - { AtCommand_Accept, "@accept", 1, atcommand_accept }, // By LuzZza - { AtCommand_Reject, "@reject", 1, atcommand_reject }, // By LuzZza - { AtCommand_Away, "@away", 1, atcommand_away }, // [LuzZza] - { AtCommand_Away, "@aw", 1, atcommand_away }, // [LuzZza] - { AtCommand_Main, "@main", 1, atcommand_main }, // [LuzZza] - { AtCommand_Clone, "@clone", 50, atcommand_clone }, - { AtCommand_Clone, "@slaveclone", 50, atcommand_clone }, - { AtCommand_Clone, "@evilclone", 50, atcommand_clone }, // [Valaris] - { AtCommand_ToNPC, "@tonpc", 40, atcommand_tonpc }, // LuzZza - { AtCommand_Commands, "@commands", 1, atcommand_commands }, // [Skotlex] - { AtCommand_NoAsk, "@noask", 1, atcommand_noask }, // [LuzZza] - { AtCommand_Request, "@request", 20, atcommand_request }, // [Skotlex] - { AtCommand_HomLevel, "@hlvl", 60, atcommand_homlevel }, - { AtCommand_HomLevel, "@hlevel", 60, atcommand_homlevel }, - { AtCommand_HomLevel, "@homlvl", 60, atcommand_homlevel }, - { AtCommand_HomLevel, "@homlevel", 60, atcommand_homlevel }, - { AtCommand_HomEvolution, "@homevolution", 60, atcommand_homevolution }, - { AtCommand_MakeHomun, "@makehomun", 60, atcommand_makehomun }, - { AtCommand_HomFriendly, "@homfriendly", 60, atcommand_homfriendly }, - { AtCommand_HomHungry, "@homhungry", 60, atcommand_homhungry }, - { AtCommand_HomTalk, "@homtalk", 10, atcommand_homtalk }, - { AtCommand_HomInfo, "@hominfo", 1, atcommand_hominfo }, - { AtCommand_HomStats, "@homstats", 1, atcommand_homstats }, - { AtCommand_HomShuffle, "@homshuffle", 60, atcommand_homshuffle }, - { AtCommand_ShowMobs, "@showmobs", 10, atcommand_showmobs }, //KarLaeda - { AtCommand_FeelReset, "@feelreset", 10, atcommand_feelreset }, //[HiddenDragon] -#ifndef TXT_ONLY // sql-only commands - { AtCommand_Mail, "@mail", 1, atcommand_mail }, // [Mail System] - { AtCommand_RefreshOnline, "@refreshonline", 99, atcommand_refreshonline }, // [Valaris] -#endif -#ifdef DMALLOC - { AtCommand_DMStart, "@dmstart", 99, atcommand_dmstart }, // [MouseJstr] - { AtCommand_DMTick, "@dmtick", 99, atcommand_dmtick }, // [MouseJstr] -#endif -// add new commands before this line - { AtCommand_Unknown, NULL, 1, NULL } -}; +typedef struct AtCommandInfo +{ + const char* command; + int level; + AtCommandFunc func; +} AtCommandInfo; + +static AtCommandInfo* get_atcommandinfo_byname(const char* name); +static AtCommandInfo* get_atcommandinfo_byfunc(const AtCommandFunc func); + +int atcommand_commands(const int fd, struct map_session_data* sd, const char* command, const char* message); + /*========================================= * Generic variables @@ -627,151 +112,6 @@ static char* player_title_txt(int level) return atcmd_temp; } -/*========================================== - * Retrieve the atcommand's required gm level - *------------------------------------------*/ -int get_atcommand_level(const AtCommandType type) -{ - int i; - - for (i = 0; atcommand_info[i].type != AtCommand_None; i++) - if (atcommand_info[i].type == type) - return atcommand_info[i].level; - - return 100; // 100: command can not be used -} - -AtCommandType is_atcommand_sub(const int fd, struct map_session_data* sd, const char* str, int gmlvl) -{ - AtCommandInfo info; - AtCommandType type; - - memset(&info, 0, sizeof(info)); - - type = atcommand(sd, gmlvl, str, &info); - if (type != AtCommand_None) { - char command[100]; - const char* p = str; - - if (map[sd->bl.m].nocommand && - gmlvl < map[sd->bl.m].nocommand) - { //Command not allowed on this map. - sprintf(atcmd_output, msg_txt(143)); - clif_displaymessage(fd, atcmd_output); - return AtCommand_None; - } - - memset(command, '\0', sizeof(command)); - memset(atcmd_output, '\0', sizeof(atcmd_output)); - while (*p && !ISSPACE(*p)) - p++; - if (p - str >= sizeof(command)) // too long - return AtCommand_Unknown; - strncpy(command, str, p - str); - while (ISSPACE(*p)) - p++; - - if (type == AtCommand_Unknown || info.proc == NULL) { - sprintf(atcmd_output, msg_txt(153), command); // %s is Unknown Command. - clif_displaymessage(fd, atcmd_output); - } else { - if (info.proc(fd, sd, command, p) != 0) { - // Command can not be executed - sprintf(atcmd_output, msg_txt(154), command); // %s failed. - clif_displaymessage(fd, atcmd_output); - } - } - - return info.type; - } - - return AtCommand_None; -} - -/*========================================== - * - *------------------------------------------*/ -AtCommandType is_atcommand(const int fd, struct map_session_data* sd, const char* message) -{ - const char* str = message; - int s_flag = 0; - - nullpo_retr(AtCommand_None, sd); - - if (sd->sc.count && sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCOMMAND) { - return AtCommand_Unknown; - } - - if (!message || !*message) - return AtCommand_None; - - // temporary compatibility layer for previous implementation - if( *message != atcommand_symbol ) - { - str += strlen(sd->status.name); - while (*str && (ISSPACE(*str) || (s_flag == 0 && *str == ':'))) { - if (*str == ':') - s_flag = 1; - str++; - } - } - - if (!*str) - return AtCommand_None; - - if(str[0] == '|' && strlen(str) >= 4 && str[3] == atcommand_symbol) - str += 3; // skip 10/11-langtype's codepage indicator, if detected - - return is_atcommand_sub(fd,sd,str,pc_isGM(sd)); -} - -/*========================================== - * - *------------------------------------------*/ -AtCommandType atcommand(struct map_session_data* sd, const int level, const char* message, struct AtCommandInfo* info) -{ - char* p = (char *)message; // it's 'char' and not 'const char' to have possibility to modify the first character if necessary - - if (!info) - return AtCommand_None; - if (battle_config.atc_gmonly != 0 && !level) // level = pc_isGM(sd) - return AtCommand_None; - if (!p || !*p) { - ShowError("at command message is empty\n"); - return AtCommand_None; - } - - if (*p == atcommand_symbol) { // check first char - char command[101]; - int i = 0; - memset(info, 0, sizeof(AtCommandInfo)); - sscanf(p, "%100s", command); - command[100] = '\0'; - - while (atcommand_info[i].type != AtCommand_Unknown) { - if (strcmpi(command+1, atcommand_info[i].command+1) == 0 && level >= atcommand_info[i].level) { - p[0] = atcommand_info[i].command[0]; // set correct first symbol for after. - break; - } - i++; - } - - if (atcommand_info[i].type == AtCommand_Unknown) { - // doesn't return Unknown if player is normal player (display the text, not display: unknown command) - if (level == 0) - return AtCommand_None; - else - return AtCommand_Unknown; - } else if((log_config.gm) && (atcommand_info[i].level >= log_config.gm)) { - log_atcommand(sd, message); - } - memcpy(info, &atcommand_info[i], sizeof atcommand_info[i]); - } else { - return AtCommand_None; - } - - return info->type; -} /*========================================== * Read Message Data @@ -826,114 +166,8 @@ void do_final_msg(void) int i; for (i = 0; i < MAX_MSG; i++) aFree(msg_table[i]); - return; } -/*========================================== - * - *------------------------------------------*/ -static AtCommandInfo* get_atcommandinfo_byname(const char* name) -{ - int i; - - for (i = 0; atcommand_info[i].type != AtCommand_Unknown; i++) - if (strcmpi(atcommand_info[i].command + 1, name) == 0) - return &atcommand_info[i]; - - return NULL; -} - -/*========================================== - * - *------------------------------------------*/ -int atcommand_config_read(const char *cfgName) -{ - char line[1024], w1[1024], w2[1024]; - AtCommandInfo* p; - FILE* fp; - - if ((fp = fopen(cfgName, "r")) == NULL) { - ShowError("At commands configuration file not found: %s\n", cfgName); - return 1; - } - - while(fgets(line, sizeof(line), fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%1023[^:]:%1023s", w1, w2) != 2) - continue; - p = get_atcommandinfo_byname(w1); - if (p != NULL) { - p->level = atoi(w2); - if (p->level > 100) - p->level = 100; - else if (p->level < 0) - p->level = 0; - } - - if (strcmpi(w1, "import") == 0) - atcommand_config_read(w2); - else if (strcmpi(w1, "command_symbol") == 0 && w2[0] > 31 && - w2[0] != '/' && // symbol of standard ragnarok GM commands - w2[0] != '%' && // symbol of party chat speaking - w2[0] != '$' && // symbol of guild chat - w2[0] != '#') // symbol of charcommand - atcommand_symbol = w2[0]; - } - fclose(fp); - - return 0; -} - -/*========================================== -// @ command processing functions - *------------------------------------------*/ - -/*========================================== - * @commands Lists available @ commands to you (code 98% from Meruru) - *------------------------------------------*/ -int atcommand_commands(const int fd, struct map_session_data* sd, const char* command, const char* message) -{ - char cz_line_buff[CHATBOX_SIZE]; - - register char *lpcz_cur = cz_line_buff; - register unsigned int ui_slen; - - int i_cur_cmd,gm_lvl = pc_isGM(sd), count = 0; - - memset(cz_line_buff,' ',CHATBOX_SIZE); - cz_line_buff[CHATBOX_SIZE-1] = 0; - - clif_displaymessage(fd, msg_txt(273)); - - for (i_cur_cmd = 0;atcommand_info[i_cur_cmd].type != AtCommand_Unknown;i_cur_cmd++) - { - if(gm_lvl < atcommand_info[i_cur_cmd].level) - continue; - - count++; - ui_slen = (unsigned int)strlen(atcommand_info[i_cur_cmd].command); - - //remember not <= bc we need null terminator - if(((CHATBOX_SIZE+(int)cz_line_buff)-(int)lpcz_cur) < (int)ui_slen) - { - clif_displaymessage(fd,(char*)cz_line_buff); - lpcz_cur = cz_line_buff; - memset(cz_line_buff,' ',CHATBOX_SIZE); - cz_line_buff[CHATBOX_SIZE-1] = 0; - } - - memcpy(lpcz_cur,atcommand_info[i_cur_cmd].command,ui_slen); - lpcz_cur += ui_slen+(10-ui_slen%10); - } - - clif_displaymessage(fd,(char*)cz_line_buff); - sprintf(atcmd_output, msg_txt(274), count); //There will always be at least 1 command (@commands) - clif_displaymessage(fd, atcmd_output); - return 0; -} /*========================================== * @send (used for testing packet sends from the client) @@ -1171,9 +405,9 @@ int atcommand_send(const int fd, struct map_session_data* sd, const char* comman } /*========================================== - * @rura + * @rura, @warp, @mapmove *------------------------------------------*/ -int atcommand_rura( const int fd, struct map_session_data* sd, const char* command, const char* message) +int atcommand_mapmove(const int fd, struct map_session_data* sd, const char* command, const char* message) { char map_name[MAP_NAME_LENGTH_EXT]; unsigned short mapindex; @@ -3984,13 +3218,16 @@ int atcommand_makeegg(const int fd, struct map_session_data* sd, const char* com nullpo_retr(-1, sd); if (!message || !*message) { - clif_displaymessage(fd, "Please, enter a monster/egg name/id (usage: @makeegg )."); + clif_displaymessage(fd, "Please, enter a monster/egg name/id (usage: @makeegg )."); return -1; } if ((item_data = itemdb_searchname(message)) != NULL) // for egg name id = item_data->nameid; - else if ((id = mobdb_searchname(message)) == 0) // for monster name + else + if ((id = mobdb_searchname(message)) != 0) // for monster name + ; + else id = atoi(message); pet_id = search_petDB_index(id, PET_CLASS); @@ -4531,12 +3768,12 @@ int atcommand_questskill(const int fd, struct map_session_data* sd, const char* if (!(skill_get_inf2(skill_id) & INF2_QUEST_SKILL)) { clif_displaymessage(fd, msg_txt(197)); // This skill number doesn't exist or isn't a quest skill. return -1; - } + } if (pc_checkskill(sd, skill_id) > 0) { clif_displaymessage(fd, msg_txt(196)); // You already have this quest skill. return -1; } - + pc_skill(sd, skill_id, 1, 0); clif_displaymessage(fd, msg_txt(70)); // You have learned the skill. @@ -6272,9 +5509,6 @@ int atcommand_npcmove(const int fd, struct map_session_data* sd, const char* com return -1; } - //Who's idea was this? nullpo's are meant to check pointers that SHOULDN'T be null unless there's a bug... [Skotlex] -// nullpo_retr(-1, (nd = npc_name2id(atcmd_player_name))); - if ((nd = npc_name2id(atcmd_player_name)) == NULL) { clif_displaymessage(fd, msg_txt(111)); // This NPC doesn't exist. @@ -6308,13 +5542,13 @@ int atcommand_addwarp(const int fd, struct map_session_data* sd, const char* com nullpo_retr(-1, sd); if (!message || !*message || sscanf(message, "%23s %d %d[^\n]", atcmd_player_name, &x, &y) < 3) { - clif_displaymessage(fd, "usage: @addwarp ."); + clif_displaymessage(fd, "usage: @addwarp ."); return -1; } sprintf(w1,"%s,%d,%d", mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y); sprintf(w3,"%s%d%d%d%d", atcmd_player_name,sd->bl.x, sd->bl.y, x, y); - sprintf(w4,"1,1,%s.gat,%d,%d", atcmd_player_name, x, y); + sprintf(w4,"1,1,%s,%d,%d", atcmd_player_name, x, y); // FIXME check if it failed [FlavioJS] npc_parse_warp(w1, "warp", w3, w4, NULL, NULL, "console"); @@ -6677,28 +5911,6 @@ int atcommand_divorce(const int fd, struct map_session_data* sd, const char* com return 0; } - -#ifdef DMALLOC -unsigned long dmark_; -int atcommand_dmstart(const int fd, struct map_session_data* sd, const char* command, const char* message) -{ - dmark_ = dmalloc_mark(); - - clif_displaymessage(fd, "debug mark set"); - - return 0; -} - -int atcommand_dmtick(const int fd, struct map_session_data* sd, const char* command, const char* message) -{ - dmalloc_log_changed ( dmark_, 1, 0, 1 ) ; - dmark_ = dmalloc_mark(); - clif_displaymessage(fd, "malloc changes logged"); - - return 0; -} -#endif - /*========================================== * @changelook by [Celest] *------------------------------------------*/ @@ -7369,38 +6581,40 @@ int atcommand_summon(const int fd, struct map_session_data* sd, const char* comm *------------------------------------------*/ int atcommand_adjcmdlvl(const int fd, struct map_session_data* sd, const char* command, const char* message) { - int i, newlev; - char cmd[100]; + int newlev; + char name[100]; + AtCommandInfo* cmd; + nullpo_retr(-1, sd); - if (!message || !*message || sscanf(message, "%d %99s", &newlev, cmd) != 2) + if (!message || !*message || sscanf(message, "%d %99s", &newlev, name) != 2) { clif_displaymessage(fd, "Usage: @adjcmdlvl ."); return -1; } - if (newlev > pc_isGM(sd)) + cmd = get_atcommandinfo_byname(name); + if (cmd == NULL) + { + clif_displaymessage(fd, "@command not found."); + return -1; + } + else if (newlev > pc_isGM(sd)) { clif_displaymessage(fd, "You can't make a command require higher GM level than your own."); return -1; } - - for (i = 0; atcommand_info[i].command && atcommand_info[i].type != AtCommand_None; i++) + else if (cmd->level > pc_isGM(sd)) { - if (strcmpi(cmd, atcommand_info[i].command+1) != 0) - continue; - if (atcommand_info[i].level > pc_isGM(sd)) - { - clif_displaymessage(fd, "You can't adjust the level of a command which's level is above your own."); - return -1; - } - atcommand_info[i].level = newlev; + clif_displaymessage(fd, "You can't adjust the level of a command which's level is above your own."); + return -1; + } + else + { + cmd->level = newlev; clif_displaymessage(fd, "@command level changed."); return 0; } - - clif_displaymessage(fd, "@command not found."); - return -1; } /*========================================== @@ -7653,185 +6867,6 @@ int atcommand_misceffect(const int fd, struct map_session_data* sd, const char* return 0; } -/*========================================== - * Jump to a player by PID number - * Original by Dino9021 - * Added in by nsstrunks - *------------------------------------------*/ -int atcommand_jumptoid2(const int fd, struct map_session_data* sd, const char* command, const char* message) -{ - int aid=0; - struct map_session_data *pl_sd; - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - - if (!message || (aid = atoi(message)) == 0) { - clif_displaymessage(fd, "Please, enter a player AID (usage: @jumptoid/@warptoid/@gotoid )."); - return -1; - } - - pl_sd = map_id2sd(aid); - if (!pl_sd) { - clif_displaymessage(fd, msg_txt(154)); // Character not found. - return -1; - } - - if (map[pl_sd->bl.m].flag.nowarpto && - battle_config.any_warp_GM_min_level > pc_isGM(sd)) - { - clif_displaymessage(fd, msg_txt(247)); - return -1; - } - if (map[sd->bl.m].flag.nowarp && - battle_config.any_warp_GM_min_level > pc_isGM(sd)) - { - clif_displaymessage(fd, msg_txt(248)); - return -1; - } - pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, 3); - sprintf(atcmd_output, msg_txt(4), pl_sd->status.name); // Jump to %s - clif_displaymessage(fd, atcmd_output); - return 0; -} - -/*========================================== - * Recall a player by PID number - * Original by Dino9021 - * Added in by nsstrunks - *------------------------------------------*/ -int atcommand_recallid2(const int fd, struct map_session_data* sd, const char* command, const char* message) -{ - int aid=0; - struct map_session_data *pl_sd; - - memset(atcmd_output, '\0', sizeof(atcmd_output)); - - if (!message || (aid = atoi(message)) == 0) { - clif_displaymessage(fd, "Please, enter a player AID (usage: @recallid2 )."); - return -1; - } - - pl_sd = map_id2sd(aid); - if (!pl_sd) { - clif_displaymessage(fd, msg_txt(154)); // Character not found. - return -1; - } - if (pc_isGM(sd) < pc_isGM(pl_sd)) - { // you can recall only lower or same level - clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player. - return -1; - } - - if (map[pl_sd->bl.m].flag.nowarpto && - battle_config.any_warp_GM_min_level > pc_isGM(sd)) - { - clif_displaymessage(fd, msg_txt(247)); - return -1; - } - if (map[sd->bl.m].flag.nowarp && - battle_config.any_warp_GM_min_level > pc_isGM(sd)) - { - clif_displaymessage(fd, msg_txt(248)); - return -1; - } - - pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, 2); - sprintf(atcmd_output, msg_txt(46), pl_sd->status.name); // Jump to %s - clif_displaymessage(fd, atcmd_output); - return 0; -} - -/*========================================== - * Kick a player by PID number - * Original by Dino9021 - * Added in by nsstrunks - *------------------------------------------*/ -int atcommand_kickid2(const int fd, struct map_session_data* sd, const char* command, const char* message) -{ - struct map_session_data *pl_sd; - int aid=0; - - if (!message || (aid = atoi(message)) == 0) { - clif_displaymessage(fd, "Please, enter a player AID (usage: @kickid2 )."); - return -1; - } - - pl_sd = map_id2sd(aid); - if (!pl_sd) { - clif_displaymessage(fd, msg_txt(3)); // Character not found. - return -1; - } - if (pc_isGM(sd) < pc_isGM(pl_sd)) - { // you can kick only lower or same gm level - clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player. - return -1; - } - clif_GM_kick(sd, pl_sd, 1); - return 0; -} - -/*========================================== - * Revive a player by PID number - * Original by Dino9021 - * Added in by nsstrunks - *------------------------------------------*/ -int atcommand_reviveid2(const int fd, struct map_session_data* sd, const char* command, const char* message) -{ - int aid=0; - struct map_session_data *pl_sd; - - if (!message || (aid = atoi(message)) == 0) { - clif_displaymessage(fd, "Please, enter a player AID (usage: @reviveid2 )."); - return -1; - } - - pl_sd = map_id2sd(aid); - - if(!pl_sd) { - clif_displaymessage(fd, msg_txt(3)); // Character not found. - return -1; - } - - if(!status_revive(&pl_sd->bl, 100, 100)) - return -1; - - clif_skill_nodamage(&pl_sd->bl,&pl_sd->bl,ALL_RESURRECTION,4,1); - clif_displaymessage(fd, msg_txt(51)); // Character revived. - return 0; -} - -/*========================================== - * Kill a player by PID number - * Original by Dino9021 - * Added in by nsstrunks - *------------------------------------------*/ -int atcommand_killid2(const int fd, struct map_session_data* sd, const char* command, const char* message) -{ - int aid=0; - struct map_session_data *pl_sd; - - if (!message || (aid = atoi(message)) == 0) { - clif_displaymessage(fd, "Please, enter a player AID (usage: @killid2 )."); - return -1; - } - - pl_sd = map_id2sd(aid); - if (!pl_sd) { - clif_displaymessage(fd, msg_txt(3)); // Character not found. - return -1; - } - - if (pc_isGM(sd) < pc_isGM(pl_sd)) - { // you can kill only lower or same level - clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player. - return -1; - } - - status_kill(&pl_sd->bl); - clif_displaymessage(fd, msg_txt(14)); // Character killed. - return 0; -} - #ifndef TXT_ONLY /* Begin SQL-Only commands */ /*========================================== @@ -8089,7 +7124,7 @@ int atcommand_homlevel(const int fd, struct map_session_data* sd, const char* co int atcommand_homevolution(const int fd, struct map_session_data* sd, const char* command, const char* message) { nullpo_retr(-1, sd); - + if ( !merc_is_hom_active(sd->hd) ) { clif_displaymessage(fd, "You do not have a homunculus."); return -1; @@ -8099,7 +7134,7 @@ int atcommand_homevolution(const int fd, struct map_session_data* sd, const char clif_displaymessage(fd, "Your homunculus doesn't evolve."); return -1; } - + return 0; } @@ -8110,7 +7145,7 @@ int atcommand_makehomun(const int fd, struct map_session_data* sd, const char* c { int homunid; nullpo_retr(-1, sd); - + if ( merc_is_hom_active(sd->hd) ) { clif_displaymessage(fd, msg_txt(450)); return -1; @@ -8120,7 +7155,7 @@ int atcommand_makehomun(const int fd, struct map_session_data* sd, const char* c clif_displaymessage(fd, "Please, enter a homunculus id: (usage: @makehomun ."); return -1; } - + homunid = atoi(message); if( homunid < HM_CLASS_BASE || homunid > HM_CLASS_BASE + MAX_HOMUNCULUS_CLASS - 1 ) { @@ -9117,6 +8152,456 @@ int atcommand_feelreset(const int fd, struct map_session_data* sd, const char* c return 0; } + + + +/*========================================== + * atcommand_info[] structure definition + *------------------------------------------*/ + +AtCommandInfo atcommand_info[] = { + { "rura", 40, atcommand_mapmove }, + { "warp", 40, atcommand_mapmove }, + { "mapmove", 40, atcommand_mapmove }, // + /mm + { "where", 1, atcommand_where }, + { "jumpto", 20, atcommand_jumpto }, // + /shift + { "warpto", 20, atcommand_jumpto }, + { "goto", 20, atcommand_jumpto }, + { "jump", 40, atcommand_jump }, + { "who", 20, atcommand_who }, + { "whois", 20, atcommand_who }, + { "who2", 20, atcommand_who2 }, + { "who3", 20, atcommand_who3 }, + { "whomap", 20, atcommand_whomap }, + { "whomap2", 20, atcommand_whomap2 }, + { "whomap3", 20, atcommand_whomap3 }, + { "whogm", 20, atcommand_whogm }, + { "save", 40, atcommand_save }, + { "return", 40, atcommand_load }, + { "load", 40, atcommand_load }, + { "speed", 40, atcommand_speed }, + { "storage", 1, atcommand_storage }, + { "gstorage", 50, atcommand_guildstorage }, + { "option", 40, atcommand_option }, + { "hide", 40, atcommand_hide }, // + /hide + { "jobchange", 40, atcommand_jobchange }, + { "job", 40, atcommand_jobchange }, + { "die", 1, atcommand_die }, + { "kill", 60, atcommand_kill }, + { "alive", 60, atcommand_alive }, + { "kami", 40, atcommand_kami }, + { "kamib", 40, atcommand_kami }, + { "kamic", 40, atcommand_kami }, + { "heal", 40, atcommand_heal }, + { "item", 60, atcommand_item }, + { "item2", 60, atcommand_item2 }, + { "itemreset", 40, atcommand_itemreset }, + { "blvl", 60, atcommand_baselevelup }, + { "lvup", 60, atcommand_baselevelup }, + { "blevel", 60, atcommand_baselevelup }, + { "baselvl", 60, atcommand_baselevelup }, + { "baselvup", 60, atcommand_baselevelup }, + { "baselevel", 60, atcommand_baselevelup }, + { "baselvlup", 60, atcommand_baselevelup }, + { "jlvl", 60, atcommand_joblevelup }, + { "jlevel", 60, atcommand_joblevelup }, + { "joblvl", 60, atcommand_joblevelup }, + { "joblevel", 60, atcommand_joblevelup }, + { "joblvup", 60, atcommand_joblevelup }, + { "joblvlup", 60, atcommand_joblevelup }, + { "h", 20, atcommand_help }, + { "help", 20, atcommand_help }, + { "h2", 20, atcommand_help2 }, + { "help2", 20, atcommand_help2 }, + { "gm", 100, atcommand_gm }, + { "pvpoff", 40, atcommand_pvpoff }, + { "pvpon", 40, atcommand_pvpon }, + { "gvgoff", 40, atcommand_gvgoff }, + { "gpvpoff", 40, atcommand_gvgoff }, + { "gvgon", 40, atcommand_gvgon }, + { "gpvpon", 40, atcommand_gvgon }, + { "model", 20, atcommand_model }, + { "go", 10, atcommand_go }, + { "monster", 50, atcommand_monster }, + { "spawn", 50, atcommand_monster }, + { "monstersmall", 50, atcommand_monstersmall }, + { "monsterbig", 50, atcommand_monsterbig }, + { "killmonster", 60, atcommand_killmonster }, + { "killmonster2", 40, atcommand_killmonster2 }, + { "refine", 60, atcommand_refine }, + { "produce", 60, atcommand_produce }, + { "memo", 40, atcommand_memo }, + { "gat", 99, atcommand_gat }, + { "displaystatus", 99, atcommand_displaystatus }, + { "stpoint", 60, atcommand_statuspoint }, + { "skpoint", 60, atcommand_skillpoint }, + { "zeny", 60, atcommand_zeny }, + { "str", 60, atcommand_param }, + { "agi", 60, atcommand_param }, + { "vit", 60, atcommand_param }, + { "int", 60, atcommand_param }, + { "dex", 60, atcommand_param }, + { "luk", 60, atcommand_param }, + { "glvl", 60, atcommand_guildlevelup }, + { "glevel", 60, atcommand_guildlevelup }, + { "guildlvl", 60, atcommand_guildlevelup }, + { "guildlvup", 60, atcommand_guildlevelup }, + { "guildlevel", 60, atcommand_guildlevelup }, + { "guildlvlup", 60, atcommand_guildlevelup }, + { "makeegg", 60, atcommand_makeegg }, + { "hatch", 60, atcommand_hatch }, + { "petfriendly", 40, atcommand_petfriendly }, + { "pethungry", 40, atcommand_pethungry }, + { "petrename", 1, atcommand_petrename }, + { "recall", 60, atcommand_recall }, // + /recall + { "night", 80, atcommand_night }, + { "day", 80, atcommand_day }, + { "doom", 80, atcommand_doom }, + { "doommap", 80, atcommand_doommap }, + { "raise", 80, atcommand_raise }, + { "raisemap", 80, atcommand_raisemap }, + { "kick", 20, atcommand_kick }, // + right click menu for GM "(name) force to quit" + { "kickall", 99, atcommand_kickall }, + { "allskill", 60, atcommand_allskill }, + { "allskills", 60, atcommand_allskill }, + { "skillall", 60, atcommand_allskill }, + { "skillsall", 60, atcommand_allskill }, + { "questskill", 40, atcommand_questskill }, + { "lostskill", 40, atcommand_lostskill }, + { "spiritball", 40, atcommand_spiritball }, + { "party", 1, atcommand_party }, + { "guild", 50, atcommand_guild }, + { "agitstart", 60, atcommand_agitstart }, + { "agitend", 60, atcommand_agitend }, + { "mapexit", 99, atcommand_mapexit }, + { "idsearch", 60, atcommand_idsearch }, + { "broadcast", 40, atcommand_broadcast }, // + /b and /nb + { "localbroadcast", 40, atcommand_localbroadcast }, // + /lb and /nlb + { "recallall", 80, atcommand_recallall }, + { "reloaditemdb", 99, atcommand_reloaditemdb }, + { "reloadmobdb", 99, atcommand_reloadmobdb }, + { "reloadskilldb", 99, atcommand_reloadskilldb }, + { "reloadscript", 99, atcommand_reloadscript }, + { "reloadgmdb", 99, atcommand_reloadgmdb }, + { "reloadatcommand", 99, atcommand_reloadatcommand }, + { "reloadbattleconf", 99, atcommand_reloadbattleconf }, + { "reloadstatusdb", 99, atcommand_reloadstatusdb }, + { "reloadpcdb", 99, atcommand_reloadpcdb }, + { "reloadmotd", 99, atcommand_reloadmotd }, + { "mapinfo", 99, atcommand_mapinfo }, + { "dye", 40, atcommand_dye }, + { "ccolor", 40, atcommand_dye }, + { "hairstyle", 40, atcommand_hair_style }, + { "hstyle", 40, atcommand_hair_style }, + { "haircolor", 40, atcommand_hair_color }, + { "hcolor", 40, atcommand_hair_color }, + { "statall", 60, atcommand_stat_all }, + { "statsall", 60, atcommand_stat_all }, + { "allstats", 60, atcommand_stat_all }, + { "allstat", 60, atcommand_stat_all }, + { "block", 60, atcommand_char_block }, + { "charblock", 60, atcommand_char_block }, + { "ban", 60, atcommand_char_ban }, + { "banish", 60, atcommand_char_ban }, + { "charban", 60, atcommand_char_ban }, + { "charbanish", 60, atcommand_char_ban }, + { "unblock", 60, atcommand_char_unblock }, + { "charunblock", 60, atcommand_char_unblock }, + { "unban", 60, atcommand_char_unban }, + { "unbanish", 60, atcommand_char_unban }, + { "charunban", 60, atcommand_char_unban }, + { "charunbanish", 60, atcommand_char_unban }, + { "mount", 20, atcommand_mount_peco }, + { "mountpeco", 20, atcommand_mount_peco }, + { "guildspy", 60, atcommand_guildspy }, + { "partyspy", 60, atcommand_partyspy }, + { "repairall", 60, atcommand_repairall }, + { "guildrecall", 60, atcommand_guildrecall }, + { "partyrecall", 60, atcommand_partyrecall }, + { "nuke", 60, atcommand_nuke }, + { "shownpc", 80, atcommand_shownpc }, + { "hidenpc", 80, atcommand_hidenpc }, + { "loadnpc", 80, atcommand_loadnpc }, + { "unloadnpc", 80, atcommand_unloadnpc }, + { "time", 1, atcommand_servertime }, + { "date", 1, atcommand_servertime }, + { "serverdate", 1, atcommand_servertime }, + { "servertime", 1, atcommand_servertime }, + { "jail", 60, atcommand_jail }, + { "unjail", 60, atcommand_unjail }, + { "discharge", 60, atcommand_unjail }, + { "jailfor", 60, atcommand_jailfor }, + { "jailtime", 1, atcommand_jailtime }, + { "disguise", 20, atcommand_disguise }, + { "undisguise", 20, atcommand_undisguise }, + { "email", 1, atcommand_email }, + { "effect", 40, atcommand_effect }, + { "follow", 20, atcommand_follow }, + { "addwarp", 60, atcommand_addwarp }, + { "skillon", 80, atcommand_skillon }, + { "skilloff", 80, atcommand_skilloff }, + { "killer", 60, atcommand_killer }, + { "npcmove", 80, atcommand_npcmove }, + { "killable", 40, atcommand_killable }, + { "dropall", 40, atcommand_dropall }, + { "storeall", 40, atcommand_storeall }, + { "skillid", 40, atcommand_skillid }, + { "useskill", 40, atcommand_useskill }, + { "displayskill", 99, atcommand_displayskill }, + { "snow", 99, atcommand_snow }, + { "sakura", 99, atcommand_sakura }, + { "clouds", 99, atcommand_clouds }, + { "clouds2", 99, atcommand_clouds2 }, + { "fog", 99, atcommand_fog }, + { "fireworks", 99, atcommand_fireworks }, + { "leaves", 99, atcommand_leaves }, + { "summon", 60, atcommand_summon }, + { "adjgmlvl", 99, atcommand_adjgmlvl }, + { "adjcmdlvl", 99, atcommand_adjcmdlvl }, + { "trade", 60, atcommand_trade }, + { "send", 99, atcommand_send }, + { "setbattleflag", 99, atcommand_setbattleflag }, + { "unmute", 80, atcommand_unmute }, + { "clearweather", 99, atcommand_clearweather }, + { "uptime", 1, atcommand_uptime }, + { "changesex", 60, atcommand_changesex }, + { "mute", 80, atcommand_mute }, + { "whozeny", 20, atcommand_whozeny }, + { "refresh", 1, atcommand_refresh }, + { "identify", 40, atcommand_identify }, + { "gmotd", 20, atcommand_gmotd }, + { "misceffect", 50, atcommand_misceffect }, + { "mobsearch", 10, atcommand_mobsearch }, + { "cleanmap", 40, atcommand_cleanmap }, + { "npctalk", 20, atcommand_npctalk }, + { "pettalk", 10, atcommand_pettalk }, + { "users", 40, atcommand_users }, + { "reset", 40, atcommand_reset }, + { "skilltree", 40, atcommand_skilltree }, + { "marry", 40, atcommand_marry }, + { "divorce", 40, atcommand_divorce }, + { "sound", 40, atcommand_sound }, + { "undisguiseall", 99, atcommand_undisguiseall }, + { "disguiseall", 99, atcommand_disguiseall }, + { "changelook", 60, atcommand_changelook }, + { "autoloot", 10, atcommand_autoloot }, + { "mobinfo", 1, atcommand_mobinfo }, + { "monsterinfo", 1, atcommand_mobinfo }, + { "mi", 1, atcommand_mobinfo }, + { "exp", 1, atcommand_exp }, + { "adopt", 40, atcommand_adopt }, + { "version", 1, atcommand_version }, + { "mutearea", 99, atcommand_mutearea }, + { "stfu", 99, atcommand_mutearea }, + { "rates", 1, atcommand_rates }, + { "iteminfo", 1, atcommand_iteminfo }, + { "ii", 1, atcommand_iteminfo }, + { "whodrops", 1, atcommand_whodrops }, + { "whereis", 10, atcommand_whereis }, + { "mapflag", 99, atcommand_mapflag }, + { "me", 20, atcommand_me }, + { "monsterignore", 99, atcommand_monsterignore }, + { "battleignore", 99, atcommand_monsterignore }, + { "fakename", 20, atcommand_fakename }, + { "size", 20, atcommand_size }, + { "showexp", 10, atcommand_showexp}, + { "showzeny", 10, atcommand_showzeny}, + { "showdelay", 1, atcommand_showdelay}, + { "autotrade", 10, atcommand_autotrade }, + { "at", 10, atcommand_autotrade }, + { "changegm", 10, atcommand_changegm }, + { "changeleader", 10, atcommand_changeleader }, + { "partyoption", 10, atcommand_partyoption}, + { "invite", 1, atcommand_invite }, + { "duel", 1, atcommand_duel }, + { "leave", 1, atcommand_leave }, + { "accept", 1, atcommand_accept }, + { "reject", 1, atcommand_reject }, + { "away", 1, atcommand_away }, + { "aw", 1, atcommand_away }, + { "main", 1, atcommand_main }, + { "clone", 50, atcommand_clone }, + { "slaveclone", 50, atcommand_clone }, + { "evilclone", 50, atcommand_clone }, + { "tonpc", 40, atcommand_tonpc }, + { "commands", 1, atcommand_commands }, + { "noask", 1, atcommand_noask }, + { "request", 20, atcommand_request }, + { "hlvl", 60, atcommand_homlevel }, + { "hlevel", 60, atcommand_homlevel }, + { "homlvl", 60, atcommand_homlevel }, + { "homlvup", 60, atcommand_homlevel }, + { "homlevel", 60, atcommand_homlevel }, + { "homevolve", 60, atcommand_homevolution }, + { "homevolution", 60, atcommand_homevolution }, + { "makehomun", 60, atcommand_makehomun }, + { "homfriendly", 60, atcommand_homfriendly }, + { "homhungry", 60, atcommand_homhungry }, + { "homtalk", 10, atcommand_homtalk }, + { "hominfo", 1, atcommand_hominfo }, + { "homstats", 1, atcommand_homstats }, + { "homshuffle", 60, atcommand_homshuffle }, + { "showmobs", 10, atcommand_showmobs }, + { "feelreset", 10, atcommand_feelreset }, +#ifndef TXT_ONLY + { "mail", 1, atcommand_mail }, + { "refreshonline", 99, atcommand_refreshonline }, +#endif +}; + + +/*========================================== + * Command lookup functions + *------------------------------------------*/ +static AtCommandInfo* get_atcommandinfo_byname(const char* name) +{ + int i; + if( *name == atcommand_symbol ) name++; // for backwards compatibility + ARR_FIND( 0, ARRAYLENGTH(atcommand_info), i, strcmpi(atcommand_info[i].command, name) == 0 ); + return ( i != ARRAYLENGTH(atcommand_info) ) ? &atcommand_info[i] : NULL; +} + +static AtCommandInfo* get_atcommandinfo_byfunc(const AtCommandFunc func) +{ + int i; + ARR_FIND( 0, ARRAYLENGTH(atcommand_info), i, atcommand_info[i].func == func ); + return ( i != ARRAYLENGTH(atcommand_info) ) ? &atcommand_info[i] : NULL; +} + + +/*========================================== + * Retrieve the command's required gm level + *------------------------------------------*/ +int get_atcommand_level(const AtCommandFunc func) +{ + AtCommandInfo* info = get_atcommandinfo_byfunc(func); + return ( info != NULL ) ? info->level : 100; // 100: command can not be used +} + + +/// Executes an at-command. +/// To be called by internal server code (bypasses various restrictions). +bool is_atcommand_sub(const int fd, struct map_session_data* sd, const char* str, int gmlvl) +{ + AtCommandInfo* info; + char command[100]; + char args[100]; + char output[200]; + + if( !str || !*str ) + return false; + + if( *str != atcommand_symbol ) // check first char + return false; + + if( sscanf(str, "%99s %99[^\n]", command, args) < 2 ) + args[0] = '\0'; + + info = get_atcommandinfo_byname(command); + if( info == NULL || info->func == NULL || gmlvl < info->level ) + { + if( gmlvl == 0 ) + return false; // will just display as normal text + else + { + sprintf(output, msg_txt(153), command); // "%s is Unknown Command." + clif_displaymessage(fd, output); + return true; + } + } + + if( log_config.gm && info->level >= log_config.gm ) + log_atcommand(sd, str); + + if( info->func(fd, sd, command, args) != 0 ) + { + sprintf(output, msg_txt(154), command); // "%s failed." + clif_displaymessage(fd, output); + } + + return true; +} + +/// Executes an at-command. +/// To be used by player-invoked code (restrictions will be applied). +bool is_atcommand(const int fd, struct map_session_data* sd, const char* message) +{ + int gmlvl = pc_isGM(sd); + int s_flag = 0; + + nullpo_retr(false, sd); + + if( !message || !*message ) + return false; // shouldn't happen + + if( sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCOMMAND ) + return true; // so that it won't display as normal message + + if( battle_config.atc_gmonly != 0 && gmlvl == 0 ) + return false; + + if( map[sd->bl.m].nocommand && gmlvl < map[sd->bl.m].nocommand ) + { + clif_displaymessage(fd, msg_txt(143)); // "Commands are disabled on this map." + return false; + } + + // skip 10/11-langtype's codepage indicator, if detected + if( message[0] == '|' && strlen(message) >= 4 && message[3] == atcommand_symbol ) + message += 3; + + return is_atcommand_sub(fd,sd,message,gmlvl); +} + + +/*========================================== + * + *------------------------------------------*/ +int atcommand_config_read(const char* cfgName) +{ + char line[1024], w1[1024], w2[1024]; + AtCommandInfo* p; + FILE* fp; + + if( (fp = fopen(cfgName, "r")) == NULL ) + { + ShowError("AtCommand configuration file not found: %s\n", cfgName); + return 1; + } + + while( fgets(line, sizeof(line), fp) ) + { + if( line[0] == '/' && line[1] == '/' ) + continue; + + if( sscanf(line, "%1023[^:]:%1023s", w1, w2) != 2 ) + continue; + + p = get_atcommandinfo_byname(w1); + if( p != NULL ) + { + p->level = atoi(w2); + p->level = cap_value(p->level, 0, 100); + } + else + if( strcmpi(w1, "import") == 0 ) + atcommand_config_read(w2); + else + if( strcmpi(w1, "command_symbol") == 0 && + w2[0] > 31 && // control characters + w2[0] != '/' && // symbol of standard ragnarok GM commands + w2[0] != '%' && // symbol of party chat speaking + w2[0] != '$' && // symbol of guild chat speaking + w2[0] != '#' ) // symbol of charcommand + atcommand_symbol = w2[0]; + else + ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); + } + fclose(fp); + + return 0; +} + void do_init_atcommand() { users_db = db_alloc(__FILE__,__LINE__,DB_UINT,DB_OPT_BASE,sizeof(int)); @@ -9130,3 +8615,51 @@ void do_final_atcommand() { users_db->destroy(users_db,NULL); } + + +// commands that need to go _after_ the commands table + +/*========================================== + * @commands Lists available @ commands to you + *------------------------------------------*/ +int atcommand_commands(const int fd, struct map_session_data* sd, const char* command, const char* message) +{ + char line_buff[CHATBOX_SIZE]; + int i, gm_lvl = pc_isGM(sd), count = 0; + char* cur = line_buff; + + memset(line_buff,' ',CHATBOX_SIZE); + line_buff[CHATBOX_SIZE-1] = 0; + + clif_displaymessage(fd, msg_txt(273)); // "Commands available:" + + for( i = 0; i < ARRAYLENGTH(atcommand_info); i++ ) + { + unsigned int slen; + + if( gm_lvl < atcommand_info[i].level ) + continue; + + slen = (unsigned int)strlen(atcommand_info[i].command); + + // flush the text buffer if this command won't fit into it + if( ((CHATBOX_SIZE-1+(int)line_buff)-(int)cur) < (int)slen ) + { + clif_displaymessage(fd,line_buff); + cur = line_buff; + memset(line_buff,' ',CHATBOX_SIZE); + line_buff[CHATBOX_SIZE-1] = 0; + } + + memcpy(cur,atcommand_info[i].command,slen); + cur += slen+(10-slen%10); + + count++; + } + clif_displaymessage(fd,line_buff); + + sprintf(atcmd_output, msg_txt(274), count); // "%d commands found." + clif_displaymessage(fd, atcmd_output); + + return 0; +} diff --git a/src/map/atcommand.h b/src/map/atcommand.h index d2532fda7..c8823b38e 100644 --- a/src/map/atcommand.h +++ b/src/map/atcommand.h @@ -4,297 +4,42 @@ #ifndef _ATCOMMAND_H_ #define _ATCOMMAND_H_ +//#include "map.h" +struct map_session_data; + //This is the distance at which @autoloot works, //if the item drops farther from the player than this, //it will not be autolooted. [Skotlex] //Note: The range is unlimited unless this define is set. //#define AUTOLOOT_DISTANCE AREA_SIZE -//#include "map.h" -struct map_session_data; - -enum AtCommandType { - AtCommand_None = -1, - AtCommand_Broadcast = 0, - AtCommand_LocalBroadcast, - AtCommand_MapMove, - AtCommand_ResetState, - AtCommand_RuraP, - AtCommand_Rura, - AtCommand_Warp, - AtCommand_Where, - AtCommand_JumpTo, - AtCommand_Jump, - AtCommand_Who, - AtCommand_Who2, - AtCommand_Who3, - AtCommand_WhoMap, - AtCommand_WhoMap2, - AtCommand_WhoMap3, - AtCommand_WhoGM, - AtCommand_Save, - AtCommand_Load, - AtCommand_Speed, - AtCommand_CharSpeed, - AtCommand_Storage, - AtCommand_GuildStorage, - AtCommand_Option, - AtCommand_Hide, - AtCommand_JobChange, - AtCommand_JobChange2, - AtCommand_JobChange3, - AtCommand_Die, - AtCommand_Kill, - AtCommand_Alive, - AtCommand_Kami, - AtCommand_KamiB, - AtCommand_KamiC, //LuzZza - AtCommand_Heal, - AtCommand_Item, - AtCommand_Item2, - AtCommand_ItemReset, - AtCommand_BaseLevelUp, - AtCommand_JobLevelUp, - AtCommand_H, - AtCommand_Help, - AtCommand_H2, - AtCommand_Help2, - AtCommand_GM, - AtCommand_PvPOff, - AtCommand_PvPOn, - AtCommand_GvGOff, - AtCommand_GvGOn, - AtCommand_Model, - AtCommand_Go, - AtCommand_Spawn, - AtCommand_MonsterSmall, - AtCommand_MonsterBig, - AtCommand_KillMonster, - AtCommand_KillMonster2, - AtCommand_Refine, - AtCommand_Produce, - AtCommand_Memo, - AtCommand_GAT, - AtCommand_DisplayStatus, - AtCommand_StatusPoint, - AtCommand_SkillPoint, - AtCommand_Zeny, - AtCommand_Param, - AtCommand_Strength, - AtCommand_Agility, - AtCommand_Vitality, - AtCommand_Intelligence, - AtCommand_Dexterity, - AtCommand_Luck, - AtCommand_GuildLevelUp, - AtCommand_MakeEgg, - AtCommand_PetFriendly, - AtCommand_PetHungry, - AtCommand_PetRename, - AtCommand_Recall, - AtCommand_Night, - AtCommand_Day, - AtCommand_Doom, - AtCommand_DoomMap, - AtCommand_Raise, - AtCommand_RaiseMap, - AtCommand_Kick, - AtCommand_KickAll, - AtCommand_AllSkill, - AtCommand_QuestSkill, - AtCommand_LostSkill, - AtCommand_SpiritBall, - AtCommand_Party, - AtCommand_Guild, - AtCommand_AgitStart, - AtCommand_AgitEnd, - AtCommand_MapExit, - AtCommand_IDSearch, - AtCommand_RecallAll, - AtCommand_ReloadItemDB, - AtCommand_ReloadMobDB, - AtCommand_ReloadSkillDB, - AtCommand_ReloadScript, - AtCommand_ReloadGMDB, - AtCommand_ReloadAtcommand, - AtCommand_ReloadBattleConf, - AtCommand_ReloadStatusDB, - AtCommand_ReloadPcDB, - AtCommand_ReloadMOTD, // [Valaris] - AtCommand_MapInfo, - AtCommand_Dye, - AtCommand_Hstyle, - AtCommand_Hcolor, - AtCommand_StatAll, - AtCommand_CharBlock, // by Yor - AtCommand_CharBan, // by Yor - AtCommand_CharUnBlock, // by Yor - AtCommand_CharUnBan, // by Yor - AtCommand_MountPeco, // by Valaris - AtCommand_GuildSpy, // [Syrus22] - AtCommand_PartySpy, // [Syrus22] - AtCommand_RepairAll, // [Valaris] - AtCommand_GuildRecall, // by Yor - AtCommand_PartyRecall, // by Yor - AtCommand_Nuke, // [Valaris] - AtCommand_Shownpc, - AtCommand_Hidenpc, - AtCommand_Loadnpc, - AtCommand_Unloadnpc, - AtCommand_ServerTime, // by Yor - AtCommand_Jail, // by Yor - AtCommand_UnJail, // by Yor - AtCommand_JailFor, // Meruru - AtCommand_JailTime, // Coltaro - AtCommand_Disguise, // [Valaris] - AtCommand_UnDisguise, // by Yor - AtCommand_EMail, // by Yor - AtCommand_Hatch, - AtCommand_Effect, // by Apple - AtCommand_AddWarp, // by MouseJstr - AtCommand_Follow, // by MouseJstr - AtCommand_SkillOn, // by MouseJstr - AtCommand_SkillOff, // by MouseJstr - AtCommand_Killer, // by MouseJstr - AtCommand_NpcMove, // by MouseJstr - AtCommand_Killable, // by MouseJstr - AtCommand_Dropall, // by MouseJstr - AtCommand_Storeall, // by MouseJstr - AtCommand_Skillid, // by MouseJstr - AtCommand_Useskill, // by MouseJstr - AtCommand_DisplaySkill, - AtCommand_Summon, - AtCommand_Rain, - AtCommand_Snow, - AtCommand_Sakura, - AtCommand_Clouds, - AtCommand_Clouds2, // [Valaris] - AtCommand_Fog, - AtCommand_Fireworks, - AtCommand_Leaves, - AtCommand_AdjGmLvl, // MouseJstr - AtCommand_AdjCmdLvl, // MouseJstr - AtCommand_Trade, // MouseJstr - AtCommand_Send, - AtCommand_SetBattleFlag, - AtCommand_UnMute, - AtCommand_Clearweather, // by Dexity - AtCommand_UpTime, // by MC Cameri - AtCommand_ChangeSex, // by MC Cameri - AtCommand_Mute, // [celest] - AtCommand_WhoZeny, // [Valaris] <-- LOL...(MC Cameri) worth it. - AtCommand_Refresh, // by MC Cameri - AtCommand_PetId, // by MC Cameri - AtCommand_Identify, // by MC Cameri - AtCommand_Gmotd, // Added by MC Cameri, created by davidsiaw - AtCommand_MiscEffect, // by MC Cameri - AtCommand_MobSearch, - AtCommand_CleanMap, - AtCommand_NpcTalk, - AtCommand_PetTalk, - AtCommand_Users, - AtCommand_SkillTree, // by MouseJstr - AtCommand_Marry, // by MouseJstr - AtCommand_Divorce, // by MouseJstr - AtCommand_Me, //added by massdriller, code by lordalfa - AtCommand_DMStart, // by MouseJstr - AtCommand_DMTick, // by MouseJstr - AtCommand_JumpToId2, // by Dino9021 - AtCommand_RecallId2, // by Dino9021 - AtCommand_KickId2, // by Dino9021 - AtCommand_ReviveId2, // by Dino9021 - AtCommand_KillId2, // by Dino9021 - AtCommand_Sound, - AtCommand_UndisguiseAll, - AtCommand_DisguiseAll, - AtCommand_ChangeLook, - AtCommand_AutoLoot, //by Upa-Kun - AtCommand_MobInfo, //by Lupus - AtCommand_Exp, // by Skotlex - AtCommand_Adopt, // by Veider - AtCommand_Version, // by Ancyker - AtCommand_MuteArea, // MouseJstr - AtCommand_Rates, // MouseJstr - AtCommand_ItemInfo, // Lupus - AtCommand_WhoDrops, // Skotlex - AtCommand_WhereIs, // Skotlex - AtCommand_MapFlag, // Lupus - AtCommand_MonsterIgnore, // [Valaris] - AtCommand_FakeName, // [Valaris] - AtCommand_Size, // [Valaris] - AtCommand_ShowDelay, - AtCommand_ShowExp, - AtCommand_ShowZeny, - AtCommand_AutoTrade,//durf - AtCommand_ChangeGM,//durf - AtCommand_ChangeLeader, - AtCommand_PartyOption, - AtCommand_Invite, // By LuzZza - AtCommand_Duel, // By LuzZza - AtCommand_Leave, // By LuzZza - AtCommand_Accept, // By LuzZza - AtCommand_Reject, // By LuzZza - AtCommand_Away, // LuzZza - AtCommand_Main, // LuzZza - AtCommand_Clone, // [Valaris] - AtCommand_ToNPC, // LuzZza - AtCommand_Commands, // [Skotlex] - AtCommand_NoAsk, // [LuzZza] - AtCommand_Request, // [Skotlex] - AtCommand_HomLevel, //[orn] - AtCommand_HomEvolution, //[orn] - AtCommand_MakeHomun, //[orn] - AtCommand_HomFriendly, //[orn] - AtCommand_HomHungry, //[orn] - AtCommand_HomTalk, //[orn] - AtCommand_HomInfo, //[Toms] - AtCommand_HomStats, //[Skotlex] - AtCommand_HomShuffle, //[Skotlex] - AtCommand_ShowMobs, //KarLaeda - AtCommand_FeelReset, //[HiddenDragon] - AtCommand_HappyHappyJoyJoy, - // SQL-only commands start -#ifndef TXT_ONLY - AtCommand_Mail, // [Mail System] - AtCommand_RefreshOnline, // [Valaris] - // SQL-only commands end -#endif - // No more commands after this line - AtCommand_Unknown, - AtCommand_MAX -}; - -typedef enum AtCommandType AtCommandType; - -typedef struct AtCommandInfo { - AtCommandType type; - const char* command; - int level; - int (*proc)(const int fd, struct map_session_data* sd, const char* command, const char* message); -} AtCommandInfo; - -AtCommandType is_atcommand(const int fd, struct map_session_data* sd, const char* message); -AtCommandType is_atcommand_sub(const int fd, struct map_session_data* sd, const char* str, int gmlvl); -AtCommandType atcommand(struct map_session_data *sd, const int level, const char* message, AtCommandInfo* info); -int get_atcommand_level(const AtCommandType type); +extern char atcommand_symbol; +typedef int (*AtCommandFunc)(const int fd, struct map_session_data* sd, const char* command, const char* message); -char* msg_txt(int msg_number); // [Yor] +bool is_atcommand(const int fd, struct map_session_data* sd, const char* message); +bool is_atcommand_sub(const int fd, struct map_session_data* sd, const char* str, int gmlvl); +int get_atcommand_level(const AtCommandFunc func); void do_init_atcommand(void); void do_final_atcommand(void); +int atcommand_config_read(const char *cfgName); -int atcommand_item(const int fd, struct map_session_data* sd,const char* command, const char* message); // [Valaris] -int atcommand_rura(const int fd, struct map_session_data* sd,const char* command, const char* message); // [Yor] -int atcommand_jumpto(const int fd, struct map_session_data* sd, const char* command, const char* message); // [Yor] -int atcommand_recall(const int fd, struct map_session_data* sd, const char* command, const char* message); // [Yor] +int atcommand_item(const int fd, struct map_session_data* sd,const char* command, const char* message); +int atcommand_mapmove(const int fd, struct map_session_data* sd,const char* command, const char* message); int atcommand_monster(const int fd, struct map_session_data* sd, const char* command, const char* message); +int atcommand_jumpto(const int fd, struct map_session_data* sd, const char* command, const char* message); +int atcommand_recall(const int fd, struct map_session_data* sd, const char* command, const char* message); +int atcommand_hide(const int fd, struct map_session_data* sd, const char* command, const char* message); +int atcommand_mute(const int fd, struct map_session_data* sd, const char* command, const char* message); +int atcommand_kick(const int fd, struct map_session_data* sd, const char* command, const char* message); +int atcommand_broadcast(const int fd, struct map_session_data* sd,const char* command, const char* message); +int atcommand_localbroadcast(const int fd, struct map_session_data* sd,const char* command, const char* message); +int atcommand_reset(const int fd, struct map_session_data* sd,const char* command, const char* message); -int atcommand_config_read(const char *cfgName); -int msg_config_read(const char *cfgName); -void do_final_msg(void); - -extern char atcommand_symbol; #define MAX_MSG 1000 extern char* msg_table[MAX_MSG]; +char* msg_txt(int msg_number); +int msg_config_read(const char* cfgName); +void do_final_msg(void); #endif /* _ATCOMMAND_H_ */ diff --git a/src/map/charcommand.c b/src/map/charcommand.c index c2689b8e8..d5746d379 100644 --- a/src/map/charcommand.c +++ b/src/map/charcommand.c @@ -1,32 +1,31 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include "../common/cbasetypes.h" -#include "../common/socket.h" #include "../common/timer.h" #include "../common/nullpo.h" #include "../common/showmsg.h" +#include "../common/strlib.h" #include "../common/utils.h" -#include "log.h" +#include "atcommand.h" // msg_txt() +#include "charcommand.h" +#include "battle.h" #include "clif.h" #include "chrif.h" #include "intif.h" #include "itemdb.h" +#include "log.h" #include "map.h" #include "pc.h" #include "status.h" #include "skill.h" #include "mob.h" +#include "npc.h" #include "pet.h" -#include "mercenary.h" //[orn] -#include "battle.h" -#include "charcommand.h" -#include "atcommand.h" +#include "mercenary.h" #include "party.h" #include "guild.h" #include "script.h" -#include "npc.h" #include "trade.h" #include "unit.h" @@ -40,379 +39,16 @@ char charcommand_symbol = '#'; extern char *msg_table[1000]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) #define CCMD_FUNC(x) int charcommand_ ## x (const int fd, struct map_session_data* sd, const char* command, const char* message) -CCMD_FUNC(jobchange); -CCMD_FUNC(petrename); -CCMD_FUNC(petfriendly); -CCMD_FUNC(stats); -CCMD_FUNC(option); -CCMD_FUNC(save); -CCMD_FUNC(stats_all); -CCMD_FUNC(reset); -CCMD_FUNC(spiritball); -CCMD_FUNC(itemlist); -CCMD_FUNC(effect); -CCMD_FUNC(storagelist); -CCMD_FUNC(item); -CCMD_FUNC(warp); -CCMD_FUNC(zeny); -CCMD_FUNC(fakename); -CCMD_FUNC(baselevel); -CCMD_FUNC(joblevel); -CCMD_FUNC(questskill); -CCMD_FUNC(lostskill); -CCMD_FUNC(skreset); -CCMD_FUNC(streset); -CCMD_FUNC(model); -CCMD_FUNC(stpoint); -CCMD_FUNC(skpoint); -CCMD_FUNC(changesex); -CCMD_FUNC(feelreset); -CCMD_FUNC(help); -CCMD_FUNC(load); -CCMD_FUNC(speed); -CCMD_FUNC(storage); -CCMD_FUNC(guildstorage); -CCMD_FUNC(hide); -CCMD_FUNC(alive); -CCMD_FUNC(heal); -CCMD_FUNC(item2); -CCMD_FUNC(itemreset); -CCMD_FUNC(refine); -CCMD_FUNC(produce); -CCMD_FUNC(param); -CCMD_FUNC(guildlevelup); -CCMD_FUNC(hatch); -CCMD_FUNC(pethungry); -CCMD_FUNC(allskill); -CCMD_FUNC(dye); -CCMD_FUNC(hair_style); -CCMD_FUNC(hair_color); -CCMD_FUNC(allstats); -CCMD_FUNC(mount_peco); -CCMD_FUNC(delitem); -CCMD_FUNC(jailtime); -CCMD_FUNC(disguise); -CCMD_FUNC(undisguise); -CCMD_FUNC(cart_list); -CCMD_FUNC(killer); -CCMD_FUNC(killable); -CCMD_FUNC(refresh); -CCMD_FUNC(exp); -CCMD_FUNC(monsterignore); -CCMD_FUNC(size); -CCMD_FUNC(homlevel); -CCMD_FUNC(homevolution); -CCMD_FUNC(homfriendly); -CCMD_FUNC(homhungry); -CCMD_FUNC(hominfo); - -/*========================================== - *CharCommandInfo charcommand_info[]構造体の定義 - *------------------------------------------*/ - -// First char of commands is configured in charcommand_athena.conf. Leave # in this list for default value. -// to set default level, read charcommand_athena.conf first please. -static CharCommandInfo charcommand_info[] = { - { CharCommandJobChange, "#job", 60, charcommand_jobchange }, - { CharCommandJobChange, "#jobchange", 60, charcommand_jobchange }, - { CharCommandPetRename, "#petrename", 50, charcommand_petrename }, - { CharCommandPetFriendly, "#petfriendly", 50, charcommand_petfriendly }, - { CharCommandStats, "#stats", 40, charcommand_stats }, - { CharCommandOption, "#option", 60, charcommand_option }, - { CharCommandReset, "#reset", 60, charcommand_reset }, - { CharCommandSave, "#save", 60, charcommand_save }, - { CharCommandSpiritball, "#spiritball", 40, charcommand_spiritball }, - { CharCommandItemList, "#itemlist", 40, charcommand_itemlist }, - { CharCommandEffect, "#effect", 40, charcommand_effect }, - { CharCommandStorageList, "#storagelist", 40, charcommand_storagelist }, - { CharCommandItem, "#item", 60, charcommand_item }, - { CharCommandWarp, "#warp", 60, charcommand_warp }, - { CharCommandWarp, "#rura", 60, charcommand_warp }, - { CharCommandWarp, "#rura+", 60, charcommand_warp }, - { CharCommandZeny, "#zeny", 60, charcommand_zeny }, - { CharCommandFakeName, "#fakename", 50, charcommand_fakename}, - { CharCommandBaseLevel, "#baselvl", 60, charcommand_baselevel}, - { CharCommandBaseLevel, "#baselevel", 60, charcommand_baselevel}, - { CharCommandBaseLevel, "#blvl", 60, charcommand_baselevel}, - { CharCommandBaseLevel, "#blevel", 60, charcommand_baselevel}, - { CharCommandJobLevel, "#joblvl", 60, charcommand_joblevel}, - { CharCommandJobLevel, "#joblevel", 60, charcommand_joblevel}, - { CharCommandJobLevel, "#jlvl", 60, charcommand_joblevel}, - { CharCommandJobLevel, "#jlevel", 60, charcommand_joblevel}, - { CharCommandQuestSkill, "#questskill", 60, charcommand_questskill }, - { CharCommandLostSkill, "#lostskill", 60, charcommand_lostskill }, - { CharCommandSkReset, "#skreset", 60, charcommand_skreset }, - { CharCommandStReset, "#streset", 60, charcommand_streset }, - { CharCommandModel, "#model", 50, charcommand_model }, - { CharCommandSKPoint, "#skpoint", 60, charcommand_skpoint }, - { CharCommandSTPoint, "#stpoint", 60, charcommand_stpoint }, - { CharCommandChangeSex, "#changesex", 60, charcommand_changesex }, - { CharCommandFeelReset, "#feelreset", 60, charcommand_feelreset }, - { CharCommandHelp, "#help", 20, charcommand_help }, - { CharCommandLoad, "#load", 60, charcommand_load }, - { CharCommandSpeed, "#speed", 60, charcommand_speed }, - { CharCommandStorage, "#storage", 60, charcommand_storage }, - { CharCommandGStorage, "#gstorage", 60, charcommand_guildstorage }, - { CharCommandHide, "#hide", 60, charcommand_hide }, - { CharCommandAlive, "#alive", 60, charcommand_alive }, - { CharCommandHeal, "#heal", 60, charcommand_heal }, - { CharCommandItem2, "#item2", 60, charcommand_item2 }, - { CharCommandItemReset, "#itemreset", 60, charcommand_itemreset }, - { CharCommandRefine, "#refine", 60, charcommand_refine }, - { CharCommandProduce, "#produce", 60, charcommand_produce }, - { CharCommandStrength, "#str", 60, charcommand_param }, - { CharCommandAgility, "#agi", 60, charcommand_param }, - { CharCommandVitality, "#vit", 60, charcommand_param }, - { CharCommandIntelligence, "#int", 60, charcommand_param }, - { CharCommandDexterity, "#dex", 60, charcommand_param }, - { CharCommandLuck, "#luk", 60, charcommand_param }, - { CharCommandGuildLevelUp, "#glvl", 60, charcommand_guildlevelup }, - { CharCommandGuildLevelUp, "#glevel", 60, charcommand_guildlevelup }, - { CharCommandGuildLevelUp, "#guildlvl", 60, charcommand_guildlevelup }, - { CharCommandGuildLevelUp, "#guildlevel", 60, charcommand_guildlevelup }, - { CharCommandHatch, "#hatch", 50, charcommand_hatch }, - { CharCommandPetHungry, "#pethungry", 60, charcommand_pethungry }, - { CharCommandAllSkill, "#allskill", 60, charcommand_allskill }, - { CharCommandAllSkill, "#allskills", 60, charcommand_allskill }, - { CharCommandAllSkill, "#skillall", 60, charcommand_allskill }, - { CharCommandAllSkill, "#skillsall", 60, charcommand_allskill }, - { CharCommandDye, "#dye", 50, charcommand_dye }, - { CharCommandHStyle, "#hairstyle", 50, charcommand_hair_style }, - { CharCommandHStyle, "#hstyle", 50, charcommand_hair_style }, - { CharCommandHColor, "#haircolor", 50, charcommand_hair_color }, - { CharCommandHColor, "#hcolor", 50, charcommand_hair_color }, - { CharCommandAllStats, "#allstat", 60, charcommand_allstats }, - { CharCommandAllStats, "#allstats", 60, charcommand_allstats }, - { CharCommandAllStats, "#statall", 60, charcommand_allstats }, - { CharCommandAllStats, "#statsall", 60, charcommand_allstats }, - { CharCommandMountPeco, "#mount", 50, charcommand_mount_peco }, - { CharCommandMountPeco, "#mountpeco", 50, charcommand_mount_peco }, - { CharCommandDelItem, "#delitem", 60, charcommand_delitem }, - { CharCommandJailTime, "#jailtime", 40, charcommand_jailtime }, - { CharCommandDisguie, "#disguise", 60, charcommand_disguise }, - { CharCommandUnDisguise, "#undisguise", 60, charcommand_undisguise }, - { CharCommandCartList, "#cartlist", 40, charcommand_cart_list }, - { CharCommandKiller, "#killer", 60, charcommand_killer }, - { CharCommandKillable, "#killable", 60, charcommand_killable }, - { CharCommandRefresh, "#refresh", 40, charcommand_refresh }, - { CharCommandExp, "#exp", 1, charcommand_exp }, - { CharCommandMonsterIgnore, "#monsterignore", 60, charcommand_monsterignore }, - { CharCommandSize, "#size", 50, charcommand_size }, - { CharCommandHomLevel, "#hlvl", 60, charcommand_homlevel }, - { CharCommandHomLevel, "#hlevel", 60, charcommand_homlevel }, - { CharCommandHomLevel, "#homlvl", 60, charcommand_homlevel }, - { CharCommandHomLevel, "#homlevel", 60, charcommand_homlevel }, - { CharCommandHomEvolve, "#homevolve", 60, charcommand_homevolution }, - { CharCommandHomEvolve, "#homevolvution", 60, charcommand_homevolution }, - { CharCommandHomFriendly, "#homfriendly", 60, charcommand_homfriendly }, - { CharCommandHomHungry, "#homhungry", 60, charcommand_homhungry }, - { CharCommandHomInfo, "#hominfo", 40, charcommand_hominfo }, - -// add new commands before this line - { CharCommand_Unknown, NULL, 1, NULL } -}; - -int get_charcommand_level(const CharCommandType type) -{ - int i; - - for (i = 0; charcommand_info[i].type != CharCommand_None; i++) - if (charcommand_info[i].type == type) - return charcommand_info[i].level; - - return 100; // 100: command can not be used -} - -CharCommandType is_charcommand_sub(const int fd, struct map_session_data* sd, const char* str, int gmlvl) -{ - CharCommandInfo info; - CharCommandType type; - - memset(&info, 0, sizeof(info)); - - type = charcommand(sd, gmlvl, str, &info); - if (type != CharCommand_None) { - char command[100]; - char output[200]; - const char* p = str; - - if (map[sd->bl.m].nocommand && - gmlvl < map[sd->bl.m].nocommand) - { //Command not allowed on this map. - sprintf(output, msg_txt(143)); - clif_displaymessage(fd, output); - return AtCommand_None; - } - - memset(command, '\0', sizeof(command)); - memset(output, '\0', sizeof(output)); - while (*p && !ISSPACE(*p)) - p++; - if (p - str >= sizeof(command)) // too long - return CharCommand_Unknown; - strncpy(command, str, p - str); - while (ISSPACE(*p)) - p++; - - if (type == CharCommand_Unknown || info.proc == NULL) { - snprintf(output, sizeof(output),msg_txt(153), command); // %s is Unknown Command. - clif_displaymessage(fd, output); - } else { - if (info.proc(fd, sd, command, p) != 0) { - // Command can not be executed - snprintf(output, sizeof(output), msg_txt(154), command); // %s failed. - clif_displaymessage(fd, output); - } - } - - return info.type; - } - - return CharCommand_None; -} - -/*========================================== - *is_charcommand @コマンドに存在するかどうか確認する - *------------------------------------------*/ -CharCommandType is_charcommand(const int fd, struct map_session_data* sd, const char* message) -{ - const char* str = message; - int s_flag = 0; - - nullpo_retr(CharCommand_None, sd); - - if (sd->sc.count && sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCOMMAND) - return CharCommand_None; - - if (!message || !*message) - return CharCommand_None; - - // temporary compatibility layer for previous implementation - if( *message != charcommand_symbol ) - { - str += strlen(sd->status.name); - while (*str && (ISSPACE(*str) || (s_flag == 0 && *str == ':'))) { - if (*str == ':') - s_flag = 1; - str++; - } - } - - if (!*str) - return CharCommand_None; - - if(str[0] == '|' && strlen(str) >= 4 && str[3] == charcommand_symbol) - str += 3; // skip 10/11-langtype's codepage indicator, if detected - - return is_charcommand_sub(fd,sd,str,pc_isGM(sd)); -} - -/*========================================== - * - *------------------------------------------*/ -CharCommandType charcommand(struct map_session_data* sd, const int level, const char* message, CharCommandInfo* info) -{ - char* p = (char *)message; - - if (!info) - return CharCommand_None; - if (battle_config.atc_gmonly != 0 && !level) // level = pc_isGM(sd) - return CharCommand_None; - if (!p || !*p) { - ShowError("char command message is empty\n"); - return CharCommand_None; - } - - if (*p == charcommand_symbol) { // check first char - char command[101]; - int i = 0; - memset(info, 0, sizeof(CharCommandInfo)); - sscanf(p, "%100s", command); - command[100] = '\0'; - - while (charcommand_info[i].type != CharCommand_Unknown) { - if (strcmpi(command+1, charcommand_info[i].command+1) == 0 && level >= charcommand_info[i].level) { - p[0] = charcommand_info[i].command[0]; // set correct first symbol for after. - break; - } - i++; - } - if (charcommand_info[i].type == CharCommand_Unknown) { - // doesn't return Unknown if player is normal player (display the text, not display: unknown command) - if (level == 0) - return CharCommand_None; - else - return CharCommand_Unknown; - } else if((log_config.gm) && (charcommand_info[i].level >= log_config.gm)) { - log_atcommand(sd, message); - } - memcpy(info, &charcommand_info[i], sizeof charcommand_info[i]); - } else { - return CharCommand_None; - } - - return info->type; -} - - -/*========================================== - * - *------------------------------------------*/ -static CharCommandInfo* get_charcommandinfo_byname(const char* name) -{ - int i; - - for (i = 0; charcommand_info[i].type != CharCommand_Unknown; i++) - if (strcmpi(charcommand_info[i].command + 1, name) == 0) - return &charcommand_info[i]; - - return NULL; -} - -/*========================================== - * - *------------------------------------------*/ -int charcommand_config_read(const char *cfgName) -{ - char line[1024], w1[1024], w2[1024]; - CharCommandInfo* p; - FILE* fp; - - if ((fp = fopen(cfgName, "r")) == NULL) { - ShowError("CharCommands configuration file not found: %s\n", cfgName); - return 1; - } - - while (fgets(line, sizeof(line), fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; +typedef struct CharCommandInfo { + const char* command; + int level; + CharCommandFunc func; +} CharCommandInfo; - if (sscanf(line, "%1023[^:]:%1023s", w1, w2) != 2) - continue; - p = get_charcommandinfo_byname(w1); - if (p != NULL) { - p->level = atoi(w2); - if (p->level > 100) - p->level = 100; - else if (p->level < 0) - p->level = 0; - } +static CharCommandInfo* get_charcommandinfo_byname(const char* name); +static CharCommandInfo* get_charcommandinfo_byfunc(const CharCommandFunc func); - if (strcmpi(w1, "import") == 0) - charcommand_config_read(w2); - else if (strcmpi(w1, "command_symbol") == 0 && w2[0] > 31 && - w2[0] != '/' && // symbol of standard ragnarok GM commands - w2[0] != '%' && // symbol of party chat speaking - w2[0] != '$' && // symbol of guild chat speaking - w2[0] != '@') // symbol of atcommand - charcommand_symbol = w2[0]; - } - fclose(fp); - - return 0; -} /*========================================== * 対象キャラクターを転職させる upper指定で転生や養子も可能 @@ -1558,9 +1194,9 @@ int charcommand_lostskill(const int fd, struct map_session_data* sd, const char* } if (skill_id < 0 && skill_id >= MAX_SKILL) { - clif_displaymessage(fd, msg_txt(198)); // This skill number doesn't exist. - return -1; - } + clif_displaymessage(fd, msg_txt(198)); // This skill number doesn't exist. + return -1; + } if (!(skill_get_inf2(skill_id) & INF2_QUEST_SKILL)) { clif_displaymessage(fd, msg_txt(197)); // This skill number doesn't exist or isn't a quest skill. return -1; @@ -3497,6 +3133,78 @@ int charcommand_killable(const int fd, struct map_session_data* sd, const char* return 0; } +/*========================================== + * Drop all of the target's possessions on the ground + *------------------------------------------*/ +int charcommand_dropall(const int fd, struct map_session_data* sd, const char* command, const char* message) +{ + int i; + struct map_session_data *pl_sd = NULL; + nullpo_retr(-1, sd); + + if (!message || !*message) + return -1; + if((pl_sd=map_nick2sd((char *) message)) == NULL) + return -1; + for (i = 0; i < MAX_INVENTORY; i++) { + if (pl_sd->status.inventory[i].amount) { + if(pl_sd->status.inventory[i].equip != 0) + pc_unequipitem(pl_sd, i, 3); + pc_dropitem(pl_sd, i, pl_sd->status.inventory[i].amount); + } + } + + clif_displaymessage(pl_sd->fd, "All items dropped"); + clif_displaymessage(fd, "It is done"); + + return 0; +} + +/*========================================== + * Put all of the target's possessions into storage + *------------------------------------------*/ +int charcommand_storeall(const int fd, struct map_session_data* sd, const char* command, const char* message) +{ + int i; + struct map_session_data *pl_sd = NULL; + nullpo_retr(-1, sd); + + if (!message || !*message) + return -1; + if((pl_sd=map_nick2sd((char *) message)) == NULL) + return -1; + + if (pl_sd->state.storage_flag != 1) + { //Open storage. + switch (storage_storageopen(pl_sd)) { + case 2: //Try again + clif_displaymessage(fd, "Had to open the characters storage window..."); + clif_displaymessage(fd, "run this command again.."); + return 0; + case 1: //Failure + clif_displaymessage(fd, "The character currently can't use the storage."); + return 1; + } + } + + for (i = 0; i < MAX_INVENTORY; i++) { + if (pl_sd->status.inventory[i].amount) { + if(pl_sd->status.inventory[i].equip != 0) + pc_unequipitem(pl_sd, i, 3); + storage_storageadd(pl_sd, i, sd->status.inventory[i].amount); + } + } + storage_storageclose(pl_sd); + + clif_displaymessage(pl_sd->fd, "Everything you own has been put away for safe keeping."); + clif_displaymessage(pl_sd->fd, "go to the nearest kafka to retrieve it.."); + clif_displaymessage(pl_sd->fd, " -- the management"); + + clif_displaymessage(fd, "It is done"); + + return 0; +} + /*========================================== * Refreshes target [HiddenDragon] *------------------------------------------*/ @@ -3734,7 +3442,7 @@ int charcommand_homevolution(const int fd, struct map_session_data* sd, const ch clif_displaymessage(fd, "Please, enter a player name (usage: #homevolution )."); return -1; } - + if ( (pl_sd = map_nick2sd(character)) == NULL ) { clif_displaymessage(fd, msg_txt(3)); // Character not found. @@ -3746,7 +3454,7 @@ int charcommand_homevolution(const int fd, struct map_session_data* sd, const ch clif_displaymessage(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player. return -1; } - + if ( !merc_is_hom_active(pl_sd->hd) ) { clif_displaymessage(fd, "Target player does not have a homunculus."); return -1; @@ -3961,3 +3669,261 @@ int charcommand_hominfo(const int fd, struct map_session_data* sd, const char* c return 0; } + + +/*========================================== + * charcommand_info[] structure definition + *------------------------------------------*/ + +CharCommandInfo charcommand_info[] = { + { "job", 60, charcommand_jobchange }, + { "jobchange", 60, charcommand_jobchange }, + { "petrename", 50, charcommand_petrename }, + { "petfriendly", 50, charcommand_petfriendly }, + { "stats", 40, charcommand_stats }, + { "option", 60, charcommand_option }, + { "reset", 60, charcommand_reset }, + { "save", 60, charcommand_save }, + { "spiritball", 40, charcommand_spiritball }, + { "itemlist", 40, charcommand_itemlist }, + { "effect", 40, charcommand_effect }, + { "storagelist", 40, charcommand_storagelist }, + { "item", 60, charcommand_item }, + { "warp", 60, charcommand_warp }, + { "rura", 60, charcommand_warp }, + { "rura+", 60, charcommand_warp }, + { "zeny", 60, charcommand_zeny }, + { "fakename", 50, charcommand_fakename }, + { "baselvl", 60, charcommand_baselevel }, + { "baselevel", 60, charcommand_baselevel }, + { "blvl", 60, charcommand_baselevel }, + { "blevel", 60, charcommand_baselevel }, + { "joblvl", 60, charcommand_joblevel }, + { "joblevel", 60, charcommand_joblevel }, + { "jlvl", 60, charcommand_joblevel }, + { "jlevel", 60, charcommand_joblevel }, + { "questskill", 60, charcommand_questskill }, + { "lostskill", 60, charcommand_lostskill }, + { "skreset", 60, charcommand_skreset }, + { "streset", 60, charcommand_streset }, + { "model", 50, charcommand_model }, + { "skpoint", 60, charcommand_skpoint }, + { "stpoint", 60, charcommand_stpoint }, + { "changesex", 60, charcommand_changesex }, + { "feelreset", 60, charcommand_feelreset }, + { "help", 20, charcommand_help }, + { "load", 60, charcommand_load }, + { "speed", 60, charcommand_speed }, + { "storage", 60, charcommand_storage }, + { "gstorage", 60, charcommand_guildstorage }, + { "hide", 60, charcommand_hide }, + { "alive", 60, charcommand_alive }, + { "revive", 60, charcommand_alive }, + { "heal", 60, charcommand_heal }, + { "item2", 60, charcommand_item2 }, + { "itemreset", 60, charcommand_itemreset }, + { "refine", 60, charcommand_refine }, + { "produce", 60, charcommand_produce }, + { "str", 60, charcommand_param }, + { "agi", 60, charcommand_param }, + { "vit", 60, charcommand_param }, + { "int", 60, charcommand_param }, + { "dex", 60, charcommand_param }, + { "luk", 60, charcommand_param }, + { "glvl", 60, charcommand_guildlevelup }, + { "glevel", 60, charcommand_guildlevelup }, + { "guildlvl", 60, charcommand_guildlevelup }, + { "guildlevel", 60, charcommand_guildlevelup }, + { "hatch", 50, charcommand_hatch }, + { "pethungry", 60, charcommand_pethungry }, + { "allskill", 60, charcommand_allskill }, + { "allskills", 60, charcommand_allskill }, + { "skillall", 60, charcommand_allskill }, + { "skillsall", 60, charcommand_allskill }, + { "dye", 50, charcommand_dye }, + { "hairstyle", 50, charcommand_hair_style }, + { "hstyle", 50, charcommand_hair_style }, + { "haircolor", 50, charcommand_hair_color }, + { "hcolor", 50, charcommand_hair_color }, + { "allstat", 60, charcommand_allstats }, + { "allstats", 60, charcommand_allstats }, + { "statall", 60, charcommand_allstats }, + { "statsall", 60, charcommand_allstats }, + { "mount", 50, charcommand_mount_peco }, + { "mountpeco", 50, charcommand_mount_peco }, + { "delitem", 60, charcommand_delitem }, + { "jailtime", 40, charcommand_jailtime }, + { "disguise", 60, charcommand_disguise }, + { "undisguise", 60, charcommand_undisguise }, + { "cartlist", 40, charcommand_cart_list }, + { "killer", 60, charcommand_killer }, + { "killable", 60, charcommand_killable }, + { "dropall", 60, charcommand_dropall }, + { "storeall", 60, charcommand_storeall }, + { "refresh", 40, charcommand_refresh }, + { "exp", 1, charcommand_exp }, + { "monsterignore", 60, charcommand_monsterignore }, + { "size", 50, charcommand_size }, + { "hlvl", 60, charcommand_homlevel }, + { "hlevel", 60, charcommand_homlevel }, + { "homlvl", 60, charcommand_homlevel }, + { "homlevel", 60, charcommand_homlevel }, + { "homevolve", 60, charcommand_homevolution }, + { "homevolution", 60, charcommand_homevolution }, + { "homfriendly", 60, charcommand_homfriendly }, + { "homhungry", 60, charcommand_homhungry }, + { "hominfo", 40, charcommand_hominfo }, +}; + + +/*========================================== + * Command lookup functions + *------------------------------------------*/ +static CharCommandInfo* get_charcommandinfo_byname(const char* name) +{ + int i; + if( *name == charcommand_symbol ) name++; // for backwards compatibility + ARR_FIND( 0, ARRAYLENGTH(charcommand_info), i, strcmpi(charcommand_info[i].command, name) == 0 ); + return ( i != ARRAYLENGTH(charcommand_info) ) ? &charcommand_info[i] : NULL; +} + +static CharCommandInfo* get_charcommandinfo_byfunc(const CharCommandFunc func) +{ + int i; + ARR_FIND( 0, ARRAYLENGTH(charcommand_info), i, charcommand_info[i].func == func ); + return ( i != ARRAYLENGTH(charcommand_info) ) ? &charcommand_info[i] : NULL; +} + + +/*========================================== + * Retrieve the command's required gm level + *------------------------------------------*/ +int get_charcommand_level(const CharCommandFunc func) +{ + CharCommandInfo* info = get_charcommandinfo_byfunc(func); + return ( info != NULL ) ? info->level : 100; // 100: command can not be used +} + + +/// Executes a char-command. +/// To be called by internal server code (bypasses various restrictions). +bool is_charcommand_sub(const int fd, struct map_session_data* sd, const char* str, int gmlvl) +{ + CharCommandInfo* info; + char command[100]; + char args[100]; + char output[200]; + + if( !str || !*str ) + return false; + + if( *str != charcommand_symbol ) // check first char + return false; + + if( sscanf(str, "%99s %99[^\n]", command, args) < 2 ) + args[0] = '\0'; + + info = get_charcommandinfo_byname(command); + if( info == NULL || info->func == NULL || gmlvl < info->level ) + { + if( gmlvl == 0 ) + return false; // will just display as normal text + else + { + sprintf(output, msg_txt(153), command); // "%s is Unknown Command." + clif_displaymessage(fd, output); + return true; + } + } + + if( log_config.gm && info->level >= log_config.gm ) + log_atcommand(sd, str); + + if( info->func(fd, sd, command, args) != 0 ) + { + sprintf(output, msg_txt(154), command); // "%s failed." + clif_displaymessage(fd, output); + } + + return true; +} + +/// Executes a char-command. +/// To be used by player-invoked code (restrictions will be applied) +bool is_charcommand(const int fd, struct map_session_data* sd, const char* message) +{ + int gmlvl = pc_isGM(sd); + int s_flag = 0; + + nullpo_retr(false, sd); + + if( !message || !*message ) + return false; + + if( sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCOMMAND ) + return true; + + if( battle_config.atc_gmonly != 0 && gmlvl == 0 ) + return false; + + if( map[sd->bl.m].nocommand && gmlvl < map[sd->bl.m].nocommand ) + { + clif_displaymessage(fd, msg_txt(143)); // "Commands are disabled on this map." + return false; + } + + // skip 10/11-langtype's codepage indicator, if detected + if( message[0] == '|' && strlen(message) >= 4 && message[3] == charcommand_symbol ) + message += 3; + + return is_atcommand_sub(fd,sd,message,gmlvl); +} + + +/*========================================== + * + *------------------------------------------*/ +int charcommand_config_read(const char* cfgName) +{ + char line[1024], w1[1024], w2[1024]; + CharCommandInfo* p; + FILE* fp; + + if( (fp = fopen(cfgName, "r")) == NULL ) + { + ShowError("CharCommand configuration file not found: %s\n", cfgName); + return 1; + } + + while( fgets(line, sizeof(line), fp) ) + { + if( line[0] == '/' && line[1] == '/' ) + continue; + + if( sscanf(line, "%1023[^:]:%1023s", w1, w2) != 2 ) + continue; + + p = get_charcommandinfo_byname(w1); + if( p != NULL ) + { + p->level = atoi(w2); + p->level = cap_value(p->level, 0, 100); + } + else + if( strcmpi(w1, "import") == 0 ) + charcommand_config_read(w2); + else + if( strcmpi(w1, "command_symbol") == 0 && + w2[0] > 31 && // control characters + w2[0] != '/' && // symbol of standard ragnarok GM commands + w2[0] != '%' && // symbol of party chat speaking + w2[0] != '$' && // symbol of guild chat speaking + w2[0] != '@' ) // symbol of atcommand + charcommand_symbol = w2[0]; + else + ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); + } + fclose(fp); + + return 0; +} diff --git a/src/map/charcommand.h b/src/map/charcommand.h index 754989d4b..25a27b732 100644 --- a/src/map/charcommand.h +++ b/src/map/charcommand.h @@ -4,101 +4,16 @@ #ifndef _CHARCOMMAND_H_ #define _CHARCOMMAND_H_ -enum CharCommandType { - CharCommand_None = -1, - CharCommandJobChange, - CharCommandPetRename, - CharCommandPetFriendly, - CharCommandReset, - CharCommandStats, - CharCommandOption, - CharCommandSave, - CharCommandSpiritball, - CharCommandItemList, - CharCommandEffect, - CharCommandStorageList, - CharCommandItem, // by MC Cameri - CharCommandWarp, - CharCommandZeny, - CharCommandFakeName, - CharCommandBaseLevel, - CharCommandJobLevel, - CharCommandQuestSkill, - CharCommandLostSkill, - CharCommandSkReset, - CharCommandStReset, - CharCommandModel, - CharCommandSKPoint, - CharCommandSTPoint, - CharCommandChangeSex, - CharCommandFeelReset, // Komurka - CharCommandHelp, - CharCommandLoad, - CharCommandSpeed, - CharCommandStorage, - CharCommandGStorage, - CharCommandHide, - CharCommandAlive, - CharCommandHeal, - CharCommandItem2, - CharCommandItemReset, - CharCommandRefine, - CharCommandProduce, - CharCommandStrength, - CharCommandAgility, - CharCommandVitality, - CharCommandIntelligence, - CharCommandDexterity, - CharCommandLuck, - CharCommandGuildLevelUp, - CharCommandHatch, - CharCommandPetHungry, - CharCommandAllSkill, - CharCommandDye, - CharCommandHStyle, - CharCommandHColor, - CharCommandAllStats, - CharCommandMountPeco, - CharCommandDelItem, - CharCommandJailTime, - CharCommandDisguie, - CharCommandUnDisguise, - CharCommandCartList, - CharCommandKiller, - CharCommandKillable, - CharCommandRefresh, - CharCommandExp, - CharCommandMonsterIgnore, - CharCommandSize, - CharCommandHomLevel, - CharCommandHomEvolve, - CharCommandHomFriendly, - CharCommandHomHungry, - CharCommandHomInfo, - // No more commands after this line - CharCommand_Unknown, - CharCommand_MAX -}; +//#include "map.h" +struct map_session_data; -typedef enum CharCommandType CharCommandType; -typedef struct CharCommandInfo { - CharCommandType type; - const char* command; - int level; - int (*proc)(const int, struct map_session_data*, - const char* command, const char* message); -} CharCommandInfo; - -CharCommandType -is_charcommand(const int fd, struct map_session_data* sd, const char* message); -CharCommandType -is_charcommand_sub(const int fd, struct map_session_data* sd, const char* str, int gmlvl); +extern char charcommand_symbol; +typedef int (*CharCommandFunc)(const int fd, struct map_session_data* sd, const char* command, const char* message); -CharCommandType charcommand( - struct map_session_data* sd, const int level, const char* message, CharCommandInfo* info); -int get_charcommand_level(const CharCommandType type); +bool is_charcommand(const int fd, struct map_session_data* sd, const char* message); +bool is_charcommand_sub(const int fd, struct map_session_data* sd, const char* str, int gmlvl); +int get_charcommand_level(const CharCommandFunc func); -int charcommand_config_read(const char *cfgName); -extern char charcommand_symbol; +int charcommand_config_read(const char* cfgName); #endif /* _CHARCOMMAND_H_ */ diff --git a/src/map/clif.c b/src/map/clif.c index c020d5760..8f86ddc6b 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -8248,7 +8248,7 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) if( !clif_process_message(sd, 0, &name, &namelen, &message, &messagelen) ) return; - if( is_atcommand(fd, sd, message) != AtCommand_None || is_charcommand(fd, sd, message) != CharCommand_None ) + if( is_atcommand(fd, sd, message) || is_charcommand(fd, sd, message) ) return; if( sd->sc.data[SC_BERSERK].timer != -1 || (sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT) ) @@ -8331,14 +8331,14 @@ void clif_parse_MapMove(int fd, struct map_session_data *sd) if (battle_config.atc_gmonly && !pc_isGM(sd)) return; - if(pc_isGM(sd) < get_atcommand_level(AtCommand_MapMove)) + if(pc_isGM(sd) < get_atcommand_level(atcommand_mapmove)) return; map_name = (char*)RFIFOP(fd,2); map_name[MAP_NAME_LENGTH_EXT-1]='\0'; sprintf(output, "%s %d %d", map_name, RFIFOW(fd,18), RFIFOW(fd,20)); - atcommand_rura(fd, sd, "@rura", output); - if(log_config.gm && get_atcommand_level(AtCommand_MapMove) >= log_config.gm) + atcommand_mapmove(fd, sd, "@mapmove", output); + if( log_config.gm && get_atcommand_level(atcommand_mapmove) >= log_config.gm ) { sprintf(message, "/mm %s", output); log_atcommand(sd, message); @@ -8559,7 +8559,7 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) if( !clif_process_message(sd, 1, &target, &namelen, &message, &messagelen) ) return; - if (is_atcommand(fd, sd, message) != AtCommand_None || is_charcommand(fd, sd, message) != CharCommand_None ) + if (is_atcommand(fd, sd, message) || is_charcommand(fd, sd, message) ) return; if (sd->sc.data[SC_BERSERK].timer!=-1 || (sd->sc.data[SC_NOCHAT].timer != -1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT)) @@ -8694,9 +8694,9 @@ void clif_parse_GMmessage(int fd, struct map_session_data* sd) unsigned int len = RFIFOW(fd,2)-4; int lv; - if (battle_config.atc_gmonly && !pc_isGM(sd)) + if( battle_config.atc_gmonly && !pc_isGM(sd) ) return; - if (pc_isGM(sd) < (lv=get_atcommand_level(AtCommand_Broadcast))) + if( pc_isGM(sd) < (lv=get_atcommand_level(atcommand_broadcast)) ) return; // as the length varies depending on the command used, just block unreasonably long strings @@ -9674,17 +9674,18 @@ void clif_parse_SolveCharName(int fd, struct map_session_data *sd) *------------------------------------------*/ void clif_parse_ResetChar(int fd, struct map_session_data *sd) { - if (battle_config.atc_gmonly && !pc_isGM(sd)) + if( battle_config.atc_gmonly && !pc_isGM(sd) ) return; - if (pc_isGM(sd) < get_atcommand_level(AtCommand_ResetState)) + + if( pc_isGM(sd) < get_atcommand_level(atcommand_reset) ) return; - if (RFIFOW(fd,2)) + if( RFIFOW(fd,2) ) pc_resetskill(sd,1); else pc_resetstate(sd); - if(log_config.gm && get_atcommand_level(AtCommand_ResetState >= log_config.gm)) + if( log_config.gm && get_atcommand_level(atcommand_reset) >= log_config.gm ) log_atcommand(sd, RFIFOW(fd,2) ? "/resetskill" : "/resetstate"); } @@ -9698,9 +9699,10 @@ void clif_parse_LGMmessage(int fd, struct map_session_data* sd) unsigned int len = RFIFOW(fd,2)-4; int lv; - if (battle_config.atc_gmonly && !pc_isGM(sd)) + if( battle_config.atc_gmonly && !pc_isGM(sd) ) return; - if (pc_isGM(sd) < (lv=get_atcommand_level(AtCommand_LocalBroadcast))) + + if( pc_isGM(sd) < (lv=get_atcommand_level(atcommand_localbroadcast)) ) return; // as the length varies depending on the command used, just block unreasonably long strings @@ -9708,7 +9710,7 @@ void clif_parse_LGMmessage(int fd, struct map_session_data* sd) clif_GMmessage(&sd->bl, msg, len, 1); - if(log_config.gm && lv >= log_config.gm) { + if( log_config.gm && lv >= log_config.gm ) { char logmsg[CHAT_SIZE_MAX+5]; sprintf(logmsg, "/lb %s", msg); log_atcommand(sd, logmsg); @@ -9963,13 +9965,13 @@ void clif_parse_PartyMessage(int fd, struct map_session_data* sd) if( !clif_process_message(sd, 0, &name, &namelen, &message, &messagelen) ) return; - if (is_charcommand(fd, sd, message) != CharCommand_None || is_atcommand(fd, sd, message) != AtCommand_None) + if( is_atcommand(fd, sd, message) || is_charcommand(fd, sd, message) ) return; - if (sd->sc.data[SC_BERSERK].timer!=-1 || (sd->sc.data[SC_NOCHAT].timer!=-1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT)) + if( sd->sc.data[SC_BERSERK].timer!=-1 || (sd->sc.data[SC_NOCHAT].timer!=-1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT) ) return; - if (battle_config.min_chat_delay) + if( battle_config.min_chat_delay ) { //[Skotlex] if (DIFF_TICK(sd->cantalk_tick, gettick()) > 0) return; @@ -10236,13 +10238,13 @@ void clif_parse_GuildMessage(int fd, struct map_session_data* sd) if( !clif_process_message(sd, 0, &name, &namelen, &message, &messagelen) ) return; - if (is_charcommand(fd, sd, message) != CharCommand_None || is_atcommand(fd, sd, message) != AtCommand_None) + if( is_atcommand(fd, sd, message) || is_charcommand(fd, sd, message) ) return; - if (sd->sc.data[SC_BERSERK].timer!=-1 || (sd->sc.data[SC_NOCHAT].timer!=-1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT)) + if( sd->sc.data[SC_BERSERK].timer!=-1 || (sd->sc.data[SC_NOCHAT].timer!=-1 && sd->sc.data[SC_NOCHAT].val1&MANNER_NOCHAT) ) return; - if (battle_config.min_chat_delay) + if( battle_config.min_chat_delay ) { //[Skotlex] if (DIFF_TICK(sd->cantalk_tick, gettick()) > 0) return; @@ -10379,10 +10381,10 @@ void clif_parse_GMKick(int fd, struct map_session_data *sd) struct block_list *target; int tid,lv; - if (battle_config.atc_gmonly && !pc_isGM(sd)) + if( battle_config.atc_gmonly && !pc_isGM(sd) ) return; - if (pc_isGM(sd) < (lv=get_atcommand_level(AtCommand_Kick))) + if( pc_isGM(sd) < (lv=get_atcommand_level(atcommand_kick)) ) return; tid = RFIFOL(fd,2); @@ -10429,15 +10431,15 @@ void clif_parse_Shift(int fd, struct map_session_data *sd) char *player_name; int lv; - if (battle_config.atc_gmonly && !pc_isGM(sd)) + if( battle_config.atc_gmonly && !pc_isGM(sd) ) return; - if (pc_isGM(sd) < (lv=get_atcommand_level(AtCommand_JumpTo))) + if( pc_isGM(sd) < (lv=get_atcommand_level(atcommand_jumpto)) ) return; player_name = (char*)RFIFOP(fd,2); player_name[NAME_LENGTH-1] = '\0'; atcommand_jumpto(fd, sd, "@jumpto", player_name); // as @jumpto - if(log_config.gm && lv >= log_config.gm) { + if( log_config.gm && lv >= log_config.gm ) { char message[NAME_LENGTH+7]; sprintf(message, "/shift %s", player_name); log_atcommand(sd, message); @@ -10453,16 +10455,16 @@ void clif_parse_Recall(int fd, struct map_session_data *sd) char *player_name; int lv; - if (battle_config.atc_gmonly && !pc_isGM(sd)) + if( battle_config.atc_gmonly && !pc_isGM(sd) ) return; - if (pc_isGM(sd) < (lv=get_atcommand_level(AtCommand_Recall))) + if( pc_isGM(sd) < (lv=get_atcommand_level(atcommand_recall)) ) return; player_name = (char*)RFIFOP(fd,2); player_name[NAME_LENGTH-1] = '\0'; atcommand_recall(fd, sd, "@recall", player_name); // as @recall - if(log_config.gm && lv >= log_config.gm) { + if( log_config.gm && lv >= log_config.gm ) { char message[NAME_LENGTH+8]; sprintf(message, "/recall %s", player_name); log_atcommand(sd, message); @@ -10479,29 +10481,29 @@ void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd) char message[NAME_LENGTH+10]; //For logging. int level; - if (battle_config.atc_gmonly && !pc_isGM(sd)) + if( battle_config.atc_gmonly && !pc_isGM(sd) ) return; monster_item_name = (char*)RFIFOP(fd,2); monster_item_name[NAME_LENGTH-1] = '\0'; - if (mobdb_searchname(monster_item_name)) { - if (pc_isGM(sd) < (level=get_atcommand_level(AtCommand_Spawn))) + if( mobdb_searchname(monster_item_name) ) { + if( pc_isGM(sd) < (level=get_atcommand_level(atcommand_monster)) ) return; - atcommand_monster(fd, sd, "@spawn", monster_item_name); // as @spawn - if(log_config.gm && level >= log_config.gm) + atcommand_monster(fd, sd, "@monster", monster_item_name); // as @monster + if( log_config.gm && level >= log_config.gm ) { //Log action. [Skotlex] snprintf(message, sizeof(message)-1, "@spawn %s", monster_item_name); log_atcommand(sd, message); } return; } - if (itemdb_searchname(monster_item_name) == NULL) + if( itemdb_searchname(monster_item_name) == NULL ) return; - if (pc_isGM(sd) < (level = get_atcommand_level(AtCommand_Item))) + if( pc_isGM(sd) < (level = get_atcommand_level(atcommand_item)) ) return; atcommand_item(fd, sd, "@item", monster_item_name); // as @item - if(log_config.gm && level >= log_config.gm) + if( log_config.gm && level >= log_config.gm ) { //Log action. [Skotlex] sprintf(message, "@item %s", monster_item_name); log_atcommand(sd, message); @@ -10513,12 +10515,13 @@ void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd) *------------------------------------------*/ void clif_parse_GMHide(int fd, struct map_session_data *sd) { - if (battle_config.atc_gmonly && !pc_isGM(sd)) + if( battle_config.atc_gmonly && !pc_isGM(sd) ) return; - if (pc_isGM(sd) < get_atcommand_level(AtCommand_Hide)) + + if( pc_isGM(sd) < get_atcommand_level(atcommand_hide) ) return; - if (sd->sc.option & OPTION_INVISIBLE) { + if( sd->sc.option & OPTION_INVISIBLE ) { sd->sc.option &= ~OPTION_INVISIBLE; if (sd->disguise) status_set_viewdata(&sd->bl, sd->disguise); @@ -10529,7 +10532,7 @@ void clif_parse_GMHide(int fd, struct map_session_data *sd) sd->sc.option |= OPTION_INVISIBLE; sd->vd.class_ = INVISIBLE_CLASS; clif_displaymessage(fd, "Invisible: On."); - if(log_config.gm && get_atcommand_level(AtCommand_Hide) >= log_config.gm) + if( log_config.gm && get_atcommand_level(atcommand_hide) >= log_config.gm ) log_atcommand(sd, "/hide"); } clif_changeoption(&sd->bl); @@ -10560,7 +10563,7 @@ void clif_parse_GMReqNoChat(int fd,struct map_session_data *sd) return; if ( - ((level = pc_isGM(sd)) > pc_isGM(dstsd) && level >= get_atcommand_level(AtCommand_Mute)) + ((level = pc_isGM(sd)) > pc_isGM(dstsd) && level >= get_atcommand_level(atcommand_mute)) || (type == 2 && !level)) { clif_GM_silence(sd, dstsd, ((type == 2) ? 1 : type)); diff --git a/src/map/map.c b/src/map/map.c index fd50012e4..cc09132f5 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -2691,7 +2691,7 @@ int parse_console(char* buf) ShowInfo("Type of command: '%s' || Command: '%s' || Map: '%s' Coords: %d %d\n", type, command, map, x, y); if( n == 5 && strcmpi("admin",type) == 0 ){ - if( is_atcommand_sub(sd.fd,&sd,command,99) == AtCommand_None ) + if( !is_atcommand_sub(sd.fd,&sd,command,99) ) printf("Console: not atcommand\n"); } else if( n == 2 && strcmpi("server",type) == 0 ){ if( strcmpi("shutdown",command) == 0 || diff --git a/src/map/pc.c b/src/map/pc.c index 2b218586d..5db1502c1 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -666,7 +666,7 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t pc_checkitem(sd); status_change_init(&sd->bl); - if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) && (pc_isGM(sd) >= get_atcommand_level(AtCommand_Hide))) + if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) && (pc_isGM(sd) >= get_atcommand_level(atcommand_hide))) sd->status.option &= (OPTION_MASK | OPTION_INVISIBLE); else sd->status.option &= OPTION_MASK; diff --git a/src/map/script.c b/src/map/script.c index 8b2464be4..28cb7ed7e 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -11006,80 +11006,82 @@ BUILDIN_FUNC(nude) *------------------------------------------*/ BUILDIN_FUNC(atcommand) { - TBL_PC *sd=NULL; - const char *cmd; + TBL_PC dummy_sd; + TBL_PC* sd; + int fd; + const char* cmd; cmd = script_getstr(st,2); - if (st->rid) - sd = script_rid2sd(st); - if (sd){ - if(cmd[0] != atcommand_symbol){ - cmd += strlen(sd->status.name); - while(*cmd != atcommand_symbol && *cmd != 0) - cmd++; - } - is_atcommand_sub(sd->fd, sd, cmd, 99); + if (st->rid) { + sd = script_rid2sd(st); + fd = sd->fd; } else { //Use a dummy character. - TBL_PC dummy_sd; - struct block_list *bl = NULL; + sd = &dummy_sd; + fd = 0; + memset(&dummy_sd, 0, sizeof(TBL_PC)); - if (st->oid) bl = map_id2bl(st->oid); - if (bl) { + if (st->oid) + { + struct block_list* bl = map_id2bl(st->oid); memcpy(&dummy_sd.bl, bl, sizeof(struct block_list)); if (bl->type == BL_NPC) - strncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); + safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); } - if(cmd[0] != atcommand_symbol){ - cmd += strlen(dummy_sd.status.name); - while(*cmd != atcommand_symbol && *cmd != 0) - cmd++; - } - is_atcommand_sub(0, &dummy_sd, cmd, 99); } + // compatibility with previous implementation (deprecated!) + if(cmd[0] != atcommand_symbol) + { + cmd += strlen(sd->status.name); + while(*cmd != atcommand_symbol && *cmd != 0) + cmd++; + } + + is_atcommand_sub(fd, sd, cmd, 99); + return 0; } BUILDIN_FUNC(charcommand) { - TBL_PC *sd=NULL; - const char *cmd; - + TBL_PC dummy_sd; + TBL_PC* sd; + int fd; + const char* cmd; + cmd = script_getstr(st,2); - if (st->rid) + if (st->rid) { sd = script_rid2sd(st); - - if (sd){ - if(cmd[0] != charcommand_symbol){ - cmd += strlen(sd->status.name); - while(*cmd != charcommand_symbol && *cmd != 0) - cmd++; - } - is_charcommand_sub(sd->fd, sd, cmd,99); + fd = sd->fd; } else { //Use a dummy character. - TBL_PC dummy_sd; - struct block_list *bl = NULL; + sd = &dummy_sd; + fd = 0; + memset(&dummy_sd, 0, sizeof(TBL_PC)); - if (st->oid) bl = map_id2bl(st->oid); - if (bl) { + if (st->oid) + { + struct block_list* bl = map_id2bl(st->oid); memcpy(&dummy_sd.bl, bl, sizeof(struct block_list)); if (bl->type == BL_NPC) - strncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); + safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); } - if(cmd[0] != charcommand_symbol){ - cmd += strlen(dummy_sd.status.name); - while(*cmd != charcommand_symbol && *cmd != 0) - cmd++; - } - is_charcommand_sub(0, &dummy_sd, cmd, 99); } + // compatibility with previous implementation (deprecated!) + if(cmd[0] != charcommand_symbol) + { + cmd += strlen(sd->status.name); + while(*cmd != charcommand_symbol && *cmd != 0) + cmd++; + } + + is_charcommand_sub(fd, sd, cmd, 99); + return 0; } - /*========================================== * Displays a message for the player only (like system messages like "you got an apple" ) *------------------------------------------*/ -- cgit v1.2.3-60-g2f50