/**************************************************************************/ // langedit.cpp - olc based language editor, Kalahn /*************************************************************************** * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt * * >> A number of people have contributed to the Dawn codebase, with the * * majority of code written by Michael Garratt - www.dawnoftime.org * * >> To use this source code, you must fully comply with the dawn license * * in licenses.txt... In particular, you may not remove this copyright * * notice. * **************************************************************************/ #include "include.h" #include "olc.h" #include "security.h" extern language_data *languages; /**************************************************************************/ bool langedit_show(char_data *ch, char *) { language_data *lang; EDIT_LANGUAGE(ch,lang); SET_BIT(ch->dyn,DYN_SHOWFLAGS); ch->titlebarf("LANGUAGE EDIT%s %s", IS_SET(lang->flags, LANGFLAG_CHANGED)?"*":":", uppercase(lang->name)); ch->printlnf("`=rName: `x%s `=rSkillName: `x%s `=X%-9s `=rCommandName: `x%s", capitalize(lang->name), capitalize(lang->skillname), lang->gsn==-1?"UNFOUND!":"", capitalize(lang->commandname)); int flags=lang->flags; REMOVE_BIT(lang->flags, LANGFLAG_CHANGED); mxp_display_olc_flags_ex(ch, language_flags, lang->flags, "flags", "Flags:", 77, 8 , 8); lang->flags=flags; ch->titlebar("What The Language Flags Do"); ch->wrapln("no_scramble `S- The language isn't scrambled.`x"); ch->wrapln("no_holyspeech `S- Holyspeech doesn't make everyone can understand, even if they dont' know the language.`x"); ch->wrapln("no_order `S- People can't be ordered to change to start speaking in this language.`x"); ch->wrapln("reverse `S- Output is backwards if not understood.`x"); ch->wrapln("no_language_name `S- The name of the language isn't displayed.`x"); ch->titlebar("BASE WORDMAP"); { // create the wordlist so we can display it, will be deallocated later lang->words_recreate_list(); wordmapping_data *word; int count=0; int extrawordcount=0; size_t len; size_t widestto=0; size_t widestfrom=0; // loop thru doing all single letter mappings for(word=lang->words; word; word=word->next){ len=str_len(word->to); widestto=UMAX(len, widestto); len=str_len(word->from); widestfrom=UMAX(len, widestfrom); if(len==1){ if(count%6!=0){ ch->print(" `=t|`x"); }else{ ch->print(" "); } ch->printf(" %s -> %-5s", word->from, word->to); if(++count%6==0){ ch->println(""); } }else{ extrawordcount++; } } if(count%6!=0){ ch->println(""); } lang->words_deallocate_list(); ch->println(" 'recreatebase' can be used to automatically create a new base wordmap"); ch->printlnf(" There are %d extra word%s mapped for this language, viewed with 'words'", extrawordcount, extrawordcount==1?"":"s"); ch->println(" Wordmappings can be manipulated using 'addword' and 'delword'"); } ch->titlebar(""); REMOVE_BIT(ch->dyn,DYN_SHOWFLAGS); return false; } /**************************************************************************/ void language_recreatebase(language_data *lang) { // create an array of all the letters in the alphabet char shuffle[26]; int i; for(i=0; i<26; i++){ shuffle[i]=i+'a'; } // shuffle the array using a system of swapping for(i=0; i<25; i++){ int pos=number_range(i+1, 25); char t=shuffle[i]; shuffle[i]=shuffle[pos]; shuffle[pos]=t; } // load the shuffled array as new words char from[2],to[2]; from[1]='\0'; to[1]='\0'; for(i=0; i<26; i++){ from[0]=i+'a'; to[0]=shuffle[i]; lang->add_wordmap_to_tree(from, to); } } /**************************************************************************/ bool langedit_recreatebase(char_data *ch, char *argument) { char confirm[MIL]; argument=one_argument(argument, confirm); if(IS_NULLSTR(confirm) || str_cmp(confirm, "confirm")){ ch->println("syntax: recreatebase confirm"); return false; } language_data *lang; EDIT_LANGUAGE(ch,lang); language_recreatebase(lang); SET_BIT(lang->flags, LANGFLAG_CHANGED); langedit_show(ch, ""); return true; } /**************************************************************************/ // Entry Point for editing the languages void do_langedit( char_data *ch, char *argument ) { int count=0; language_data *language; if(ch){ if ( IS_NPC( ch )){ ch->println("Players only."); return; } // do security checks if (!HAS_SECURITY(ch, 2)){ ch->println( "You must have an olc security 2 or higher to use this command." ); return; } // do security checks if (!HAS_SECURITY(ch, LANGEDIT_MINSECURITY)) { ch->printlnf("You must have an olc security %d or higher to use this command.", LANGEDIT_MINSECURITY); return; } if ( !IS_TRUSTED(ch, LANGEDIT_MINTRUST)) { ch->printlnf("You must have a trust of %d or above " "to use this command.", LANGEDIT_MINTRUST); return; } } if (IS_NULLSTR(argument)){ ch->titlebar("LANGEDIT"); ch->println("syntax: langedit <language>"); ch->println("syntax: langedit create <newlanguage>"); ch->println("syntax: langedit list - list the languages in a table"); ch->println("This command takes you into an olc editor, to edit/create languages"); ch->println("`x"); ch->println("The following uneditable system languages exist:"); for(language=languages; language; language=language->next){ if(IS_SET(language->flags, LANGFLAG_SYSTEM_LANGUAGE)){ ch->printf(" `S%-24s", language->name); if(++count%3==0){ ch->print_blank_lines(1); } } } if(count%3!=0){ ch->print_blank_lines(1); } count=0; ch->println("`x"); ch->println("The following existing languages can be edited:"); for(language=languages; language; language=language->next){ if(!IS_SET(language->flags, LANGFLAG_SYSTEM_LANGUAGE)){ ch->printf(" `=C%s", mxp_create_send(ch,FORMATF("langedit %s", language->name), FORMATF("%-24s", language->name))); if(++count%3==0){ ch->print_blank_lines(1); } } } if(count%3!=0){ ch->print_blank_lines(1); } ch->titlebar(""); return; } char arg[MIL]; argument=one_argument(argument,arg); if(!str_cmp(arg,"create")){ argument=one_argument(argument,arg); if(IS_NULLSTR(arg)){ ch->println("You must specify the name of the language you wish to create."); return; } // Allow only letters, numbers and underscore. int length=str_len(arg); for(int i=0; i<length; i++){ if(!is_alnum(arg[i]) && arg[i]!='_'){ ch->println( "Only letters, the underscore character '_' and numbers are valid in a language name." ); return; } } // check if there is an existing language with matching name language=language_exact_lookup(arg); if(language){ ch->printlnf("There is already a language named '%s'", language->name); return; } language=new language_data; language->name=str_dup(lowercase(arg)); language->flags=0; if(ch){ language->skillname=str_dup(""); }else{ language->skillname=str_dup(language->name); } language->gsn=skill_exact_lookup(language->skillname); language->commandname=str_dup("-"); language->words=NULL; language->initialise_tree(); // add new language to the front of the list language->next=languages; languages=language; language_recreatebase(language); if(ch){ ch->printlnf("Language '%s' created", arg); ch->desc->pEdit = (void*)language; ch->desc->editor = ED_LANGUAGE; langedit_show(ch, ""); } return; } if(!str_cmp(arg,"list")){ for(language=languages; language; language=language->next){ if(IS_SET(language->flags, LANGFLAG_SYSTEM_LANGUAGE)){ ch->printlnf("`=$Name: `x%-18s `=$SkillName: `x%-18s `=$CommandName: `x%s", capitalize(language->name), capitalize(language->skillname), capitalize(language->commandname)); }else{ ch->printlnf("`=rName: `x%-18s `=rSkillName: `x%-18s `=rCommandName: `x%s", mxp_create_send(ch,FORMATF("langedit %s", language->name), FORMATF("%-18s", capitalize(language->name))), capitalize(language->skillname), capitalize(language->commandname)); } } return; } // find an existing social language=language_lookup(arg); if(!language){ ch->printlnf("There is no language named '%s'", arg); do_langedit(ch, ""); return; } // ensure it isn't a system language if(IS_SET(language->flags, LANGFLAG_SYSTEM_LANGUAGE)){ ch->printlnf("'%s' is a system language, therefore can not be edited.", language->name); return; } ch->desc->pEdit = (void*)language; ch->desc->editor = ED_LANGUAGE; ch->printlnf("Editing '%s' language.", language->name); langedit_show(ch, ""); return; } /**************************************************************************/ bool langedit_rename(char_data *ch, char *argument) { char arg[MIL]; argument=one_argument(argument,arg); if ( IS_NULLSTR(arg)) { ch->println( "Syntax: rename <string>"); ch->println( "Rename the language."); return false; } // Allow only letters, numbers and underscore. int length=str_len(arg); for(int i=0; i<length; i++){ if(!is_alnum(arg[i]) && arg[i]!='_'){ ch->println( "Only letters, the underscore character '_' and numbers are valid in a language name." ); return false; } } language_data *lang; // check if there is an existing language with matching name lang=language_exact_lookup(arg); if(lang){ ch->printlnf("There is already a language named '%s'", lang->name); return false; } EDIT_LANGUAGE(ch,lang); ch->printlnf("Language name changed from '%s' to '%s'.", lang->name, lowercase(arg) ); replace_string( lang->name, lowercase(arg) ); return true; } /**************************************************************************/ bool langedit_skillname(char_data *ch, char *argument) { char arg[MIL]; argument=one_argument(argument,arg); if ( IS_NULLSTR(arg)) { ch->println( "Syntax: skillname <string>"); ch->println( "Set/change the skillname of the language."); return false; } language_data *lang; EDIT_LANGUAGE(ch,lang); // find the skill first int sn=skill_exact_lookup(arg); if(sn<0){ ch->printlnf("There is no skill called '%s'", arg); return false; } if(lang->gsn==sn){ ch->printlnf("Language skillname is already set to %s", lang->skillname); } ch->printlnf("Language skillname changed from '%s' to '%s'.", lang->skillname, lowercase(arg) ); replace_string( lang->skillname, lowercase(arg) ); lang->gsn=sn; return true; } /**************************************************************************/ bool langedit_commandname(char_data *ch, char *argument) { char arg[MIL]; argument=one_argument(argument,arg); if ( IS_NULLSTR(arg)) { ch->println( "Syntax: commandname <string>"); ch->println( "Syntax: commandname - (to clear the command name)"); ch->println( "Set/change the commandname of the language."); ch->println( "Note: if this is blank, the language can't be accessed as a command."); return false; } language_data *lang; EDIT_LANGUAGE(ch,lang); if(!str_cmp(arg, "-")){ ch->println("Commandname cleared."); replace_string(lang->commandname,"-"); return true; } ch->printlnf("Language commandname changed from '%s' to '%s'.", lang->commandname, lowercase(arg) ); replace_string( lang->commandname, lowercase(arg) ); return true; } /**************************************************************************/ bool langedit_flags(char_data *ch, char *argument) { language_data *lang; EDIT_LANGUAGE(ch,lang); return olc_generic_flag_toggle(ch, argument, "flags", "flags", language_flags, &lang->flags); } /**************************************************************************/ // this is inefficient, but the code will very rarely be used bool langedit_words(char_data *ch, char *argument) { language_data *lang; EDIT_LANGUAGE(ch,lang); char buf[MSL]; BUFFER *output; output = new_buf(); // create the wordlist so we can display it, will be deallocated later lang->words_recreate_list(); wordmapping_data *word; int count=0; int len; int widestto=0; int widestfrom=0; // loop thru doing all single letter mappings add_buf( output, makef_titlebar(FORMATF("%s WORD MAPPINGS", uppercase(lang->name)))); for(word=lang->words; word; word=word->next){ len=str_len(word->to); widestto=UMAX(len, widestto); len=str_len(word->from); widestfrom=UMAX(len, widestfrom); } count=0; for(word=lang->words; word; word=word->next){ if(!IS_NULLSTR(argument)){ // support infix word matching if(str_infix(argument, word->from) && str_infix(argument, word->to)){ continue; } } if(str_len(word->from)!=1){ if(count%3!=0){ add_buf( output, " `=t|`x"); }else{ add_buf( output, " "); } sprintf(buf, FORMATF(" %%-%ds -> %%-%ds", widestfrom, widestto) ,word->from, word->to); if(++count%3==0){ strcat(buf, "\r\n"); } add_buf( output, buf); } } if(count){ if(count%3!=0){ add_buf( output, "\r\n"); } } add_buf( output, "Add/change word mappings using the addword command\r\n"); add_buf( output, "You can delete words with delword and infix search this list.\r\n"); add_buf( output, makef_titlebar("=")); ch->sendpage(buf_string(output)); free_buf(output); lang->words_deallocate_list(); return false; } /**************************************************************************/ bool langedit_addword(char_data *ch, char *argument) { char from[MIL]; char to[MIL]; argument=one_argument(argument, from); argument=one_argument(argument, to); if(IS_NULLSTR(to)){ ch->println("syntax: addword <word_from> <word_to>"); return false; } if(str_len(from)==1){ if(!is_alnum(*from)){ ch->println("You can't add single character 'words' other than letters and numbers"); return false; } } language_data *lang; EDIT_LANGUAGE(ch,lang); languagetree_data *tail; // look for an existing word first int length=lang->find(from, &tail); if(length==str_len(from)){ if(!str_cmp(to, tail->stored_word)){ ch->printlnf("No changed required, '%s' is already mapped to '%s'.", from, to); return false; } ch->printlnf("Modified mapping '%s'->'%s' to '%s'->'%s'", from, tail->stored_word, from, to); lang->add_wordmap_to_tree(from, to); }else{ ch->printlnf("Added new word mapping to '%s'->'%s'", from, to); lang->add_wordmap_to_tree(from, to); } return true; } /**************************************************************************/ bool langedit_delword(char_data *ch, char *argument) { char delword[MIL]; argument=one_argument(argument, delword); if(IS_NULLSTR(delword)){ ch->println("syntax: delword <word_to_delete>"); return false; } if(str_len(delword)==1 && is_alpha(*delword) ){ ch->wrapln("You can't delete single character 'words' that are letters, " "only change them with addword. To blank a single character " "wordmapping use \"addword <word> ''\""); return false; } language_data *lang; EDIT_LANGUAGE(ch,lang); languagetree_data *tail; // first check the delword exists, before trying to remove it int length=lang->find(delword, &tail); if(length!=str_len(delword)){ ch->printlnf("Couldn't find any word '%s' to remove.", delword); return false; } // create the wordlist so we can pull it out then reinitialise the tree lang->words_recreate_list(); wordmapping_data *word, *prev; prev=NULL; bool found=false; for(word=lang->words; !found && word; word=word->next){ if(!str_cmp(delword, word->from)){ if(prev){ prev->next=word->next; }else{ // we are the head of the list lang->words=word->next; } // deallocate the memory used by the deleted node free_string(word->from); free_string(word->to); word->next=NULL; delete word; found=true; // we don't have to worry about words_last here, as we call words_deallocate_list() below } prev=word; } // it has to be found, because lang->find() matched the word assert(found); // reinitialise the tree from the wordmap list which has // just had the word we are deleting removed from it lang->reinitialise_tree(); // return the memory lang->words_deallocate_list(); ch->printlnf("Word mapping for '%s' has been removed.", delword); return true; } /**************************************************************************/ /**************************************************************************/