소스 검색

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://svn.code.sf.net/p/rathena/svn/trunk@11607 54d463be-8e91-2dee-dedb-b68131a5f0ec

ultramage 17 년 전
부모
커밋
fc9d14b1bd
12개의 변경된 파일962개의 추가작업 그리고 2048개의 파일을 삭제
  1. 22 0
      Changelog-Trunk.txt
  2. 8 0
      conf/Changelog.txt
  3. 395 367
      conf/atcommand_athena.conf
  4. 15 4
      conf/charcommand_athena.conf
  5. 49 835
      src/map/atcommand.c
  6. 22 277
      src/map/atcommand.h
  7. 349 383
      src/map/charcommand.c
  8. 8 93
      src/map/charcommand.h
  9. 44 41
      src/map/clif.c
  10. 1 1
      src/map/map.c
  11. 1 1
      src/map/pc.c
  12. 48 46
      src/map/script.c

+ 22 - 0
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.

+ 8 - 0
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]

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 395 - 367
conf/atcommand_athena.conf


+ 15 - 4
conf/charcommand_athena.conf

@@ -1,10 +1,12 @@
-// Athena charcommand Configuration file.
-// Translated by Peter Kieser <pfak@telus.net>
+//--------------------------------------------------------------
+// eAthena charcommand configuration file.
+// Originally translated by Peter Kieser <pfak@telus.net>
+//--------------------------------------------------------------
 
 // 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
 

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 49 - 835
src/map/atcommand.c


+ 22 - 277
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_ */

+ 349 - 383
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 <player>).");
 		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;
+}

+ 8 - 93
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_ */

+ 44 - 41
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));

+ 1 - 1
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 ||

+ 1 - 1
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;

+ 48 - 46
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" )
  *------------------------------------------*/

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.