As mentioned earlier, I modified the command_interpreter() function because I wanted to change the order of the commands.
The original order of command input is
Code:
<command> <subcmd> <arg>
For example, the command should be entered as follows:
Code:
say <msg>
look <obj>
tell <vict> <msg>
Code:
typo list
typo submit <header>
Typo show <num>
I wanted to change the order of the commands as follows.
Code:
<msg> say
<obj> look
list typo
<vict> <msg> tell
Code:
list typo
Submit <header> typo
show <num> typo
All commands work in the order I want.
But I get errors in typo, bug, idea commands.
The code where the error occurred is as follows.
Code:
void command_interpreter(struct char_data *ch, char *argument)
{
int cmd, length;
char *line;
char arg[MAX_INPUT_LENGTH];
char hanparse[MAX_INPUT_LENGTH]; /* Korean Input Order */
char hancommand[MAX_INPUT_LENGTH]; /* Korean command */
REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_HIDE);
/* just drop to next line for hitting CR */
skip_spaces(&argument);
if (!*argument)
return;
if(strlen(argument) > MAX_INPUT_LENGTH - 100) {
send_to_char(ch,"You've entered too many.\r\n");
return;
}
sprintf(hanparse, "%s", argument);
if(check_comma(hanparse))
strcat(hanparse, " 말"); // say
if((strlen(hanparse) <= 2) && is_number(hanparse))
switch(atoi(hanparse)) {
case 6:
sprintf(hanparse, "동"); break; // East
case 4:
sprintf(hanparse, "서"); break; // West
case 2:
sprintf(hanparse, "남"); break; // South
case 8:
sprintf(hanparse, "북"); break; // North
case 9:
sprintf(hanparse, "북동"); break; // Northeast
case 7:
sprintf(hanparse, "북서"); break; // Northwest
case 3:
sprintf(hanparse, "남동"); break; // SouthEast
case 1:
sprintf(hanparse, "남서"); break; // Southwest
}
if(strrchr(hanparse, ' ')) {
sprintf(hancommand, "%s ", strrchr(hanparse, ' '));
hanparse[strlen(hanparse) - (strlen(hancommand) - 1)] = '\0';
strcat(hancommand, hanparse);
argument = hancommand;
} else
argument = hanparse;
skip_spaces(&argument);
/* special case to handle one-character, non-alphanumeric commands; requested
* by many people so "'hi" or ";godnet test" is possible. Patch sent by Eric
* Green and Stefan Wasilewski. */
if (!ishanalp(*argument)) {
arg[0] = argument[0];
arg[1] = '\0';
line = argument + 1;
} else
line = any_one_arg(argument, arg);
/* Since all command triggers check for valid_dg_target before acting, the levelcheck
* here has been removed. Otherwise, find the command. */
{
int cont; /* continue the command checks */
cont = command_wtrigger(ch, arg, line); /* any world triggers ? */
if (!cont) cont = command_mtrigger(ch, arg, line); /* any mobile triggers ? */
if (!cont) cont = command_otrigger(ch, arg, line); /* any object triggers ? */
if (cont) return; /* yes, command trigger took over */
}
/* Allow IMPLs to switch into mobs to test the commands. */
if (IS_NPC(ch) && ch->desc && GET_LEVEL(ch->desc->original) >= LVL_IMPL) {
if (script_command_interpreter(ch, argument))
return;
}
for (length = strlen(arg), cmd = 0; *complete_cmd_info[cmd].command != '\n'; cmd++)
if(complete_cmd_info[cmd].command_pointer != do_action &&
!strncmp(complete_cmd_info[cmd].command, arg, length))
if (GET_LEVEL(ch) >= complete_cmd_info[cmd].minimum_level)
break;
/* it's not a 'real' command, so it's a social */
if(*complete_cmd_info[cmd].command == '\n')
for (length = strlen(arg), cmd = 0; *complete_cmd_info[cmd].command != '\n'; cmd++)
if (complete_cmd_info[cmd].command_pointer == do_action &&
!strncmp(complete_cmd_info[cmd].command, arg, length))
if (GET_LEVEL(ch) >= complete_cmd_info[cmd].minimum_level)
break;
if (*complete_cmd_info[cmd].command == '\n') {
int found = 0;
send_to_char(ch, "%s", CONFIG_HUH);
for (cmd = 0; *cmd_info[cmd].command != '\n'; cmd++)
{
if (*arg != *cmd_info[cmd].command || cmd_info[cmd].minimum_level > GET_LEVEL(ch))
continue;
/* Only apply levenshtein counts if the command is not a trigger command. */
if ( (levenshtein_distance(arg, cmd_info[cmd].command) <= 2) &&
(cmd_info[cmd].minimum_level >= 0) )
{
if (!found)
{
send_to_char(ch, "\r\nDid you mean:\r\n");
found = 1;
}
send_to_char(ch, " %s\r\n", cmd_info[cmd].command);
}
}
}
else if (!IS_NPC(ch) && PLR_FLAGGED(ch, PLR_FROZEN) && GET_LEVEL(ch) < LVL_IMPL)
send_to_char(ch, "You try, but the mind-numbing cold prevents you...\r\n");
else if (complete_cmd_info[cmd].command_pointer == NULL)
send_to_char(ch, "Sorry, that command hasn't been implemented yet.\r\n");
else if (IS_NPC(ch) && complete_cmd_info[cmd].minimum_level >= LVL_IMMORT)
send_to_char(ch, "You can't use immortal commands while switched.\r\n");
else if (GET_POS(ch) < complete_cmd_info[cmd].minimum_position)
switch (GET_POS(ch)) {
case POS_DEAD:
send_to_char(ch, "Lie still; you are DEAD!!! :-(\r\n");
break;
case POS_INCAP:
case POS_MORTALLYW:
send_to_char(ch, "You are in a pretty bad shape, unable to do anything!\r\n");
break;
case POS_STUNNED:
send_to_char(ch, "All you can do right now is think about the stars!\r\n");
break;
case POS_SLEEPING:
send_to_char(ch, "In your dreams, or what?\r\n");
break;
case POS_RESTING:
send_to_char(ch, "Nah... You feel too relaxed to do that..\r\n");
break;
case POS_SITTING:
send_to_char(ch, "Maybe you should get on your feet first?\r\n");
break;
case POS_FIGHTING:
send_to_char(ch, "No way! You're fighting for your life!\r\n");
break;
} else if (no_specials || !special(ch, cmd, line))
((*complete_cmd_info[cmd].command_pointer) (ch, line, cmd, complete_cmd_info[cmd].subcmd));
}
The additional functions used in this code are defined in Utils.c.
Code:
/* add_commas takes a numeric value, and adds commas to it, returning a string */
char *add_commas(long num)
{
int i, j = 0, len;
int negative = (num < 0);
char num_string[MAX_INPUT_LENGTH];
static char commastring[MAX_INPUT_LENGTH];
sprintf(num_string, "%ld", num);
len = strlen(num_string);
for (i = 0; num_string[i]; i++) {
if ((len - i) % 3 == 0 && i && i - negative)
commastring[j++] = ',';
commastring[j++] = num_string[i];
}
commastring[j] = '\0';
return commastring;
}
/* Inspect the entered contents for exclamation marks, question marks, and periods.
If present, it is used to replace it with a say command. */
int check_comma(char *argume)
{
char argum[MAX_INPUT_LENGTH];
int targe=0;
strcpy(argum, argume);
targe = argum[strlen(argum)-1];
switch(targe) {
case 33: return(1); break; /* 느낌표 */
case 63: return(1); break; /* 물음표 */
case 46: return(1); break; /* 마침표 */
default: return(0);
}
}
/* Remove the space on the left. */
char *TrimLeft(char *_str) {
char *start = _str;
while (*start != '\0' && isspace(*start))
++start;
_str = start;
return _str;
}
/* Remove the space on the right. */
char *TrimRight(char *_str) {
char t[1024];
char *end;
strcpy(t, _str);
end = t + strlen(t) - 1;
while (end != _str && isspace(*end))
--end;
*(end + 1) = '\0';
_str = t;
return _str;
}
/* Remove spaces on both sides. */
char *Trim(char *_str) {
return(TrimLeft(TrimRight(_str)));
}
unsigned int NumLen(unsigned int num) // 숫자의자릿수를구하는함수1234 -> 3
{
int len = 0;
while (1) {
if (num / 10 > 0) {
len++;
num /= 10;
}
else {
break;
}
}
return len;
}
/* This function revolves by changing the number into Korean. */
char *han_num(unsigned int num, int type)
{
const char HanNum[10][3] = { "", "일", "이", "삼", "사",
"오", "육", "칠", "팔", "구" };
const char HanJari[10][4] = { "", "십", "백", "천", "만 ",
"십", "백", "천", "억 ", "십" };
const char HanNum1[10][5] = { "", "한", "두", "세", "네", "다섯",
"여섯", "일곱", "여덟", "아홉" };
const char HanNum2[10][5] = { "", "열", "스물", "서른", "마흔", "쉰",
"예순", "일흔", "여든", "아흔" };
unsigned int numj, numj2; // 자릿수 저장 1234 면 1000
int temp, temp2; // 각자리의숫자한개임시저장용.
int zerocount = 0;
static char str[50]; // 리턴할문자열변수.
if (num <= 0) // 오류막기: - 또는0 일경우"영" 넘김.
return "영";
if (num >= 2147483647) // 이십억이하막기"수십억" 넘김
return "수십억";
strcpy(str, "");
numj = numj2 = (unsigned int)pow(10, NumLen(num));
for (; numj2 > 0; numj2 /= 10) {
temp2 = num / numj2;
temp2 -= (num / (numj2 * 10)) * 10;
if (temp2 == 0)
zerocount++;
}
for (; numj > 0; numj /= 10) {
temp = num / numj;
temp -= (num / (numj * 10)) * 10;
if (temp == -8) temp = 2;
else if (temp == -9) temp = 1;
if (!type) {
// 일, 만, 억의자리의일은제외하지않고그외자리는넣지않음.
if (temp != 1 || (numj == 1 || numj == 10000 || numj == 100000000))
strcat(str, HanNum[temp]);
// 10의자리부터는0일때는자리한글넣지않음. 302 삼백()이(만, 억은표시)
if (temp != 0 || ((zerocount <= 7 && numj == 10000) || numj == 100000000))
strcat(str, HanJari[NumLen(numj)]);
}
else {
// 일의자리의경우에는
if (numj == 1)
strcat(str, HanNum1[temp]);
// 십의자리의경우에는
else if (numj == 10) {
if (!(num % 10) && temp == 2)
strcat(str, "스무");
else
strcat(str, HanNum2[temp]);
}
else {
if (temp != 1 || (numj == 1 || numj == 10000 || numj == 100000000))
strcat(str, HanNum[temp]);
if (temp != 0 || ((zerocount <= 7 && numj == 10000) || numj == 100000000))
strcat(str, HanJari[NumLen(numj)]);
}
}
}
if (str[strlen(str) - 1] == ' ') {
str[strlen(str) - 1] = '\0';
}
return str;
}
char *replaceAll(const char *s, const char *oldW, const char *newW)
{
char *result;
int i, cnt = 0;
int newWlen = strlen(newW);
int oldWlen = strlen(oldW);
// Counting the number of times old word
// occur in the string
for (i = 0; s[i] != '\0'; i++)
{
if (strstr(&s[i], oldW) == &s[i])
{
cnt++;
// Jumping to index after the old word.
i += oldWlen - 1;
}
}
// Making new string of enough length
result = (char *)malloc(i + cnt * (newWlen - oldWlen) + 1);
i = 0;
while (*s)
{
// compare the substring with the result
if (strstr(s, oldW) == s)
{
strcpy(&result[i], newW);
i += newWlen;
s += oldWlen;
}
else
result[i++] = *s++;
}
result[i] = '\0';
return result;
}
int CountWords(const char sentence[])
{
int counted = 0; // result
// state:
const char* it = sentence;
int inword = 0;
do switch (*it) {
case '\0':
case ' ': case '\t': case '\n': case '\r': // TODO others?
if (inword) { inword = 0; counted++; }
break;
default: inword = 1;
} while (*it++);
return counted;
}
char *FirstWord(char* line)
{
char* word = strtok(line, " ");
return word;
}
char *LastWord(const char *s, int *plen) {
int i, j = strlen(s);
while (j > 0 && isspace((unsigned char)s[j - 1]))
j--;
for (i = j; i > 0 && !isspace((unsigned char)s[i - 1]); i--)
continue;
*plen = j - i;
return (char *)(s + i);
}
char* substring(char* string, int position, int length)
{
char* pointer;
int c;
pointer = malloc(length + 1);
if (pointer == NULL)
{
printf("Unable to allocate memory.\n");
exit(1);
}
for (c = 0; c < length; c++)
{
*(pointer + c) = *(string + position - 1);
string++;
}
*(pointer + c) = '\0';
return pointer;
}
char *RemoveFirstWord(char* orig)
{
char *res;
for (res = orig; *res && *res != ' '; res++);
// If there was a space, skip it too
if (*res) res++;
return res;
}
I got most of the above code from the Internet.
I began to correct the code where the error occurred for a few days.
I succeeded in separating commands from subcommands.
In addition, arguments other than the command are separated but not delivered to other commands.
Code:
void command_interpreter(struct char_data *ch, char *argument)
{
int cmd, length;
char *line;
char *p;
char arg[MAX_INPUT_LENGTH];
char hanparse[MAX_INPUT_LENGTH]; /* 한글 어순 */
char hancommand[MAX_INPUT_LENGTH]; /* 한글 명령 */
REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_HIDE);
/* just drop to next line for hitting CR */
skip_spaces(&argument);
if (!*argument)
return;
if(strlen(argument) > MAX_INPUT_LENGTH - 100) {
send_to_char(ch,"너무 많이 입력하였습니다.\r\n");
return;
}
/* Make a copy to process a string. */
sprintf(hanparse, "%s", argument);
/* Inspect the entered contents for exclamation marks, question marks, and periods.
If present, it is used to replace it with a say command. */
if(check_comma(hanparse))
strcat(hanparse, " 말"); // say
/* Replace the number entered with the keypad with the move command.. */
if((strlen(hanparse) <= 2) && is_number(hanparse))
switch(atoi(hanparse)) {
case 6:
sprintf(hanparse, "동"); break; // East
case 4:
sprintf(hanparse, "서"); break; // West
case 2:
sprintf(hanparse, "남"); break; // South
case 8:
sprintf(hanparse, "북"); break; // North
case 9:
sprintf(hanparse, "북동"); break; // Northeast
case 7:
sprintf(hanparse, "북서"); break; // Northwest
case 3:
sprintf(hanparse, "남동"); break; // SouthEast
case 1:
sprintf(hanparse, "남서"); break; // Southwest
}
if(strrchr(hanparse, ' ')) { /* If there is a space in a sentence, it is two words. */
int len;
p = LastWord(hanparse, &len);
strcat(hancommand, p);
hanparse[strlen(hanparse) - (strlen(hancommand)+1)] = '\0';
argument = RemoveFirstWord(hanparse);
}
else
argument = hanparse;
/* special case to handle one-character, non-alphanumeric commands; requested
* by many people so "'hi" or ";godnet test" is possible. Patch sent by Eric
* Green and Stefan Wasilewski. */
// strcat(arg, hancommand);
// line = FirstWord(hanparse);
strcat(arg, FirstWord(hanparse));
line = hancommand;
log("hancommand:%s<<\r\n", hancommand);
log("arg:%s<<\r\n", arg);
log("argument:%s<<\r\n", argument);
log("line:%s<<\r\n", line);
/* Since all command triggers check for valid_dg_target before acting, the levelcheck
* here has been removed. Otherwise, find the command. */
{
int cont; /* continue the command checks */
cont = command_wtrigger(ch, arg, line); /* any world triggers ? */
if (!cont) cont = command_mtrigger(ch, arg, line); /* any mobile triggers ? */
if (!cont) cont = command_otrigger(ch, arg, line); /* any object triggers ? */
if (cont) return; /* yes, command trigger took over */
}
/* Allow IMPLs to switch into mobs to test the commands. */
if (IS_NPC(ch) && ch->desc && GET_LEVEL(ch->desc->original) >= LVL_IMPL) {
if (script_command_interpreter(ch, argument))
return;
}
for (length = strlen(arg), cmd = 0; *complete_cmd_info[cmd].command != '\n'; cmd++)
if(complete_cmd_info[cmd].command_pointer != do_action &&
!strncmp(complete_cmd_info[cmd].command, arg, length))
if (GET_LEVEL(ch) >= complete_cmd_info[cmd].minimum_level)
break;
/* it's not a 'real' command, so it's a social */
if(*complete_cmd_info[cmd].command == '\n')
for (length = strlen(arg), cmd = 0; *complete_cmd_info[cmd].command != '\n'; cmd++)
if (complete_cmd_info[cmd].command_pointer == do_action &&
!strncmp(complete_cmd_info[cmd].command, arg, length))
if (GET_LEVEL(ch) >= complete_cmd_info[cmd].minimum_level)
break;
if (*complete_cmd_info[cmd].command == '\n') {
int found = 0;
send_to_char(ch, "%s", CONFIG_HUH);
for (cmd = 0; *cmd_info[cmd].command != '\n'; cmd++)
{
if (*arg != *cmd_info[cmd].command || cmd_info[cmd].minimum_level > GET_LEVEL(ch))
continue;
/* Only apply levenshtein counts if the command is not a trigger command. */
if ( (levenshtein_distance(arg, cmd_info[cmd].command) <= 2) &&
(cmd_info[cmd].minimum_level >= 0) )
{
if (!found)
{
send_to_char(ch, "\r\nDid you mean:\r\n");
found = 1;
}
send_to_char(ch, " %s\r\n", cmd_info[cmd].command);
}
}
}
else if (!IS_NPC(ch) && PLR_FLAGGED(ch, PLR_FROZEN) && GET_LEVEL(ch) < LVL_IMPL)
send_to_char(ch, "You try, but the mind-numbing cold prevents you...\r\n");
else if (complete_cmd_info[cmd].command_pointer == NULL)
send_to_char(ch, "Sorry, that command hasn't been implemented yet.\r\n");
else if (IS_NPC(ch) && complete_cmd_info[cmd].minimum_level >= LVL_IMMORT)
send_to_char(ch, "You can't use immortal commands while switched.\r\n");
else if (GET_POS(ch) < complete_cmd_info[cmd].minimum_position)
switch (GET_POS(ch)) {
case POS_DEAD:
send_to_char(ch, "Lie still; you are DEAD!!! :-(\r\n");
break;
case POS_INCAP:
case POS_MORTALLYW:
send_to_char(ch, "You are in a pretty bad shape, unable to do anything!\r\n");
break;
case POS_STUNNED:
send_to_char(ch, "All you can do right now is think about the stars!\r\n");
break;
case POS_SLEEPING:
send_to_char(ch, "In your dreams, or what?\r\n");
break;
case POS_RESTING:
send_to_char(ch, "Nah... You feel too relaxed to do that..\r\n");
break;
case POS_SITTING:
send_to_char(ch, "Maybe you should get on your feet first?\r\n");
break;
case POS_FIGHTING:
send_to_char(ch, "No way! You're fighting for your life!\r\n");
break;
} else if (no_specials || !special(ch, cmd, line))
((*complete_cmd_info[cmd].command_pointer) (ch, line, cmd, complete_cmd_info[cmd].subcmd));
}
Hangul judgment of characters is defined in utils.h.
Code:
#define ishan(ch) (((ch) & 0xE0) > 0x90)
#define ishanasc(ch) (isascii(ch) || ishan(ch))
#define ishanalp(ch) (isalpha(ch) || ishan(ch))
#define isnhdigit(ch) (!ishan(ch) && isdigit(ch))
#define isnhspace(ch) (!ishan(ch) && isspace(ch))
int is_hangul(unsigned char *str);
int is_han(unsigned char *str);
int under_han(unsigned char *str);
int check_comma(char *argume);
char *first_han(unsigned char *str);
char *check_josa(char *str, int m);
char *ReadNumber(char *strNum, char *res);
char *ReadBaseNumber(char *strNum,char *res);
char *TrimLeft(char *_str);
char *TrimRight(char *_str);
char *Trim(char *_str);
char *replaceAll(const char *s, const char *oldW, const char *newW);
unsigned int NumLen(unsigned int num);
char *han_num(unsigned int num, int type);
int CountWords(const char sentence[]);
char *FirstWord(char* line);
char *LastWord(const char* s, int* plen);
char *substring(char* string, int position, int length);
char* RemoveFirstWord(char* orig);
This is the explanation of command_interpreter() that I modified this time.
I brought the first word as subcmd as a function of FirstWord().
The last word was imported as a command as a function LastWord().
As the code said, line and arg knew subcmd and command.
Excluding the two commands, the aggregate is not passed to the original command.
The middle sentence, excluding the two commands, was taken as an argument.
The following command was of course entered in Korean, but it was expressed in English for your understanding.
Code:
submit typos in the salesperson's description typo
The results are as follows, but the argument is not delivered to the existing command.
Code:
hancommand: typo // The last word entered is a Korean command
arg: submit // Subcommand as the first word entered
argument: typos in the salesperson's description // Subject, content, and argument with a middle sentence except for two commands
line: typo // The last word entered is a Korean command
The following code is assumed to have been used in Circlemud 3.0 version.
It was created by someone other than me to handle Korean commands.
I tried to convert this function to tbamud but failed.
I'm writing it because I don't know if it will help you.
The annotation described in the code was originally written in Korean, but I translated it into Google Translator so you can understand it.
Code:
#define __HASH_C__
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
extern struct command_info cmd_info[];
CMDHASH *command_hash[256];
int hash_findcmd(struct char_data * ch, char *argument)
{
CMDHASH *command;
int hash;
/* find the hash key. */
hash = LOWER((unsigned char) argument[0]) % 256;
command = command_hash[hash];
while (command) {
if (is_abbrev(argument, command->name) &&
GET_LEVEL(ch) >= command->min_level)
return command->cmd;
command = command->next;
}
return (-1); /* If not found, -1 is returned */
}
void hash_addcmd(char *argument, int cmd, int level)
{
CMDHASH *command, *tmp;
int i, hash;
if (!argument || !*argument) {
mudlog("SYSERR: hash_addcmd() No command string.",
BRF, LVL_GRGOD, TRUE);
return;
}
if (cmd <= 0) {
mudlog("SYSERR: The command number is less than 0", BRF, LVL_IMPL, TRUE);
return;
}
/* Memory allocation */
CREATE(command, CMDHASH, 1);
/* Specify command name, number, and minimum level */
command->name = str_dup(argument);
command->cmd = cmd;
command->min_level = level;
/* Commands to be added to the hash table must be replaced with lowercase letters. (English) */
for (i = 0; command->name[i] != '\0'; i++)
command->name[i] = LOWER(command->name[i]);
/* find the hash key. */
hash = ((unsigned char) command->name[0]) % 256;
/*
* When command_hash[hash] points to NULL, this command is
first added to the array structure with the hash key number.
*/
if (!(tmp = command_hash[hash])) {
/* Next to the list is NULL because it is the first command. */
command->next = NULL;
/* The command structure is designated as common_hash[hash]. */
command_hash[hash] = command;
return;
}
/*
* tmp (equivalent to command_hash] is added at the end of the list unless it is NULL.
*/
for (; tmp; tmp = tmp->next)
if (!tmp->next) {
tmp->next = command;
command->next = NULL;
}
}
void hash_init(void)
{
int i;
for (i = 0; i < 256; i++) /* Initializing the Hash table */
command_hash[i] = NULL;
/*
* The reason for starting with 1 is that the 0 array of
cmd_info is RESERVED for SPECIAL functions.
*/
for (i = 1; *cmd_info[i].command != '\n'; i++) {
/* Add the command to the hash table. */
hash_addcmd(cmd_info[i].command, i, cmd_info[i].minimum_level);
}
}
I'll try to modify it again with the do_ibt function you gave me.