/* ************************************************************************ * file: spell.c Basic routines and parsing Part of DIKUMUD * * Usage : Interpreter of cast magic * * Copyright (C) 1990, 1991 - see 'license.doc' for complete information. * ************************************************************************* */ #include CONFIG #include "structs.h" #include "utils.h" #include "comm.h" #include "db.h" #include "interp.h" #include "skills.h" #include "magic.h" #include "error.h" #include "proto.h" #if HAVE_STRINGS_H #include <strings.h> #endif #if HAVE_STRING_H #include <string.h> #endif /* Global data */ extern struct room_data *world; extern char *spell_wear_off_msg[]; extern struct mattrib_info mattribs[]; extern char log_buf[]; extern char *errors[]; /* Extern procedures */ char *strdup(char *str); /* Extern procedures */ const byte saving_throws[4][5][25] = { { {16,14,14,14,14,14,13,13,13,13,13,11,11,11,11,11,10,10,10,10,10, 8, 6, 4, 0}, {13,11,11,11,11,11, 9, 9, 9, 9, 9, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 3, 2, 1, 0}, {15,13,13,13,13,13,11,11,11,11,11, 9, 9, 9, 9, 9, 7, 7, 7, 7, 7, 5, 4, 2, 0}, {17,15,15,15,15,15,13,13,13,13,13,11,11,11,11,11, 9, 9, 9, 9, 9, 7, 5, 3, 0}, {14,12,12,12,12,12,10,10,10,10,10, 8, 8, 8, 8, 8, 6, 6, 6, 6, 6, 4, 3, 2, 0} }, { {11,10,10,10, 9, 9, 9, 7, 7, 7, 6, 6, 6, 5, 5, 5, 4, 4, 4, 2, 2, 2, 2, 1, 0}, {16,14,14,14,13,13,13,11,11,11,10,10,10, 9, 9, 9, 8, 8, 8, 6, 6, 5, 4, 3, 0}, {15,13,13,13,12,12,12,10,10,10, 9, 9, 9, 8, 8, 8, 7, 7, 7, 5, 5, 4, 3, 2, 0}, {18,16,16,16,15,15,15,13,13,13,12,12,12,11,11,11,10,10,10, 8, 8, 7, 6, 5, 0}, {17,15,15,15,14,14,14,12,12,12,11,11,11,10,10,10, 9, 9, 9, 7, 7, 6, 5, 4, 0} }, { {15,13,13,13,13,12,12,12,12,11,11,11,11,10,10,10,10, 9, 9, 9, 9, 8, 7, 6, 0}, {16,14,14,14,14,12,12,12,12,10,10,10,10, 8, 8, 8, 8, 6, 6, 6, 6, 4, 3, 2, 0}, {14,12,12,12,12,11,11,11,11,10,10,10,10, 9, 9, 9, 9, 8, 8, 8, 8, 7, 5, 3, 0}, {18,16,16,16,16,15,15,15,15,14,14,14,14,13,13,13,13,12,12,12,12,11, 9, 5, 0}, {17,15,15,15,15,13,13,13,13,11,11,11,11, 9, 9, 9, 9, 7, 7, 7, 7, 5, 3, 1, 0} }, { {16,14,14,13,13,11,11,10,10, 8, 8, 7, 7, 5, 5, 4, 4, 3, 3, 3, 3, 2, 2, 1, 0}, {18,16,16,15,15,13,13,12,12,10,10, 9, 9, 7, 7, 6, 6, 5, 5, 5, 5, 4, 3, 2, 0}, {17,15,15,14,14,12,12,11,11, 9, 9, 8, 8, 6, 6, 5, 5, 4, 4, 4, 4, 3, 2, 1, 0}, {20,17,17,16,16,13,13,12,12, 9, 9, 8, 8, 5, 5, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0}, {19,17,17,16,16,14,14,13,13,11,11,10,10, 8, 8, 7, 7, 6, 6, 6, 6, 4, 2, 1, 0} } }; int USE_MANA(struct char_data *ch,int sn) { int mana; /* if(GET_LEVEL(ch)>=SPELL_LEVEL(ch,sn)) mana=((float)spell_info[sn].min_usesmana * (1.0+(1.0/(float)(GET_LEVEL(ch)-SPELL_LEVEL(ch,sn)+1.0)))); else mana=2*spell_info[sn].min_usesmana+SPELL_LEVEL(ch,sn)-GET_LEVEL(ch); */ mana=number(5,60); mana=MAX(2,MIN(100,mana)); return(mana); } /* I am loathe to make it too easy to decode spells, but it shouldn't be impossible either - just enough not impossible so small gains can be made without endangering vast portions of the scheme. I consider an index which randomly changes the order of syllables taken, yet remain consistent for the spell ("aaabbb" becoming "ytytytooo" and "pipipildaldalda" on different castings, for example)... */ void say_spell( struct char_data *ch, char *name ) { char buf[MAX_STRING_LENGTH]; char buf2[MAX_STRING_LENGTH]; int j, offs; struct char_data *temp_char; struct s_syllable { char org[10]; char new[10]; }; struct s_syllable syls[] = { { " ", " " }, { "ar", "abra" }, { "au", "kada" }, { "bles", "fid" }, { "bl", "no" }, { "ind", "se" }, { "bur", "mosa" }, { "cu", "judi" }, { "de", "oculo"}, { "en", "unso" }, { "light", "dies" }, { "lo", "hi" }, { "mor", "zak" }, { "move", "sido" }, { "ness", "locri" }, { "ning", "illa" }, { "per", "duda" }, { "ra", "gru" }, { "re", "candus" }, { "son", "sabru" }, { "tect", "infra" }, { "tri", "cula" }, { "ven", "nofo" }, { ":", "heh" }, { ",", "uh"}, { ".", "eh"}, {"a", "a"},{"b","b"},{"c","q"},{"d","e"},{"e","z"},{"f","y"},{"g","o"}, {"h", "p"},{"i","u"},{"j","y"},{"k","t"},{"l","r"},{"m","w"},{"n","i"}, {"o", "a"},{"p","s"},{"q","d"},{"r","f"},{"s","g"},{"t","h"},{"u","j"}, {"v", "z"},{"w","x"},{"x","n"},{"y","l"},{"z","k"}, {"",""} }; strcpy(buf, ""); offs = 0; while(*(name+offs)) { for(j=0; *(syls[j].org); j++) if (strncmp(syls[j].org, name+offs, strlen(syls[j].org))==0) { strcat(buf, syls[j].new); if (strlen(syls[j].org)) offs+=strlen(syls[j].org); else ++offs; break; } if(!*(syls[j].org)) { /* we didn't match */ ++offs; } } sprintf(buf2, "You utter the words, '%s'", buf); act(buf2, FALSE, ch, 0, temp_char, TO_CHAR); sprintf(buf2,"$n utters the words, '%s'", buf); for(temp_char = world[ch->in_room].people; temp_char; temp_char = temp_char->next_in_room) if(temp_char != ch) { act(buf2, FALSE, ch, 0, temp_char, TO_VICT); } } bool saves_spell(struct char_data *ch, sh_int save_type) { int save; /* Negative apply_saving_throw makes saving throw better! */ save = ch->specials.apply_saving_throw[save_type]; if (!IS_NPC(ch)) { /*save += saving_throws[GET_CLASS(ch)-1][save_type][GET_LEVEL(ch)];*/ } return(MAX(1,save) < number(1,20)); } int count_lines(FILE *fl) { char buf[100]; int count=0; rewind(fl); while(fgets(buf,99,fl)) { count++; } rewind(fl); return(count); } int top_syllable; struct syllable *syllables; void boot_syllables() { FILE *fl; int i,count; char buf[80],*token; if(!(fl=fopen(SYL_FILE,"r"))) { log("BUG: Can't open syllables"); return; /* or exit? */ } i = count_lines(fl) - count_char('#',fl); CREATE(syllables,struct syllable,i); top_syllable=0; while(fgets(buf,80,fl)) { if(buf[0]=='#') /* comment */ continue; token=strtok(buf," \n"); syllables[top_syllable].syl = strdup(token); count=0; while((token=strtok(NULL,",\n "))) { for(i=0;*mattribs[i].name!='\n';i++) { if(!strcasecmp(token,mattribs[i].name)) { syllables[top_syllable].impart[count++]=i; break; } } if(*mattribs[i].name=='\n') { sprintf(log_buf,"BUG: Unknown magic attribute %s in syl file", token); log(log_buf); } } for(i=count;i<8;i++) syllables[top_syllable].impart[i]=-1; top_syllable++; } } struct syllable *match_syl(char *input) { int i; for(i=0;i<top_syllable;i++) if(!(strcmp(syllables[i].syl,input))) return &syllables[i]; return(NULL); } char *skip_spaces(char *string) { for(;*string && (*string)==' ';string++); return(string); } /* Assumes that *argument does start with first letter of chopped string */ int do_cast(struct char_data *ch, char *argument, int cmd) { struct obj_data *tar_obj; struct char_data *tar_char; struct char_skill_data *sk; struct syllable *syl; char name[MAX_STRING_LENGTH], sbuf[MAX_INPUT_LENGTH], *token, *say_save; int qend, ret, i; int last_impart,impart[100]; /* should be large enough */ bool target_ok; void *target; struct magic *m; struct generic object,creator; int error; if(!(sk=get_skill(ch,SKILL_CAST))) { send_to_char("You don't seem to know how.\n",ch); return ERROR_NO_KNOWLEDGE; } /* Let's consider how to pass arguments here... * * spell vs. attrib? * * cast 'spell' target (with book/scroll in hand?) * * cast 'attrib' target - this seems wrong, somehow... * - a spell is a list of attributes - perhaps a way * to make a list? (shall we delay the caster by the * complexity of spell/attrib-list?) * */ argument = skip_spaces(argument); /* If there is no chars in argument */ if (!(*argument)) { send_to_char("Cast which what where?\n\r", ch); return ERROR_SYNTAX; } if (*argument != '\'') { send_to_char("Magic must always be enclosed by the holy magic symbols : '\n\r",ch); return ERROR_SYNTAX; } /* Locate the last quote && lowercase the magic words (if any) */ for (qend=1; *(argument+qend) && (*(argument+qend) != '\'') ; qend++) *(argument+qend) = LOWER(*(argument+qend)); if (*(argument+qend) != '\'') { send_to_char("Magic must always be enclosed by the holy magic symbols : '\n\r",ch); return ERROR_SYNTAX; } /* Save that magic while we can */ say_save=argument+1; say_save[qend]='\0'; strncpy(sbuf,argument+1,qend-1); sbuf[qend]='\0'; /* Syllabificate that bastard! */ last_impart=0; token=strtok(sbuf," ,.:!"); while(token) { /* If no match, we add garbage */ if(!(syl=match_syl(token))) { impart[last_impart++] = 0; /*garbage it when I have time */ } else { /* Eventually check to see if this is even known... */ for(i=0;i<8 && syl->impart[i]!=-1;i++) { impart[last_impart++] = syl->impart[i]; } } token=strtok(NULL," ,.:!"); } say_spell(ch, say_save); argument+=qend+1; /* Point to the last ' */ for(;*argument == ' '; argument++); /* **************** Locate targets **************** */ target_ok = FALSE; tar_char = 0; tar_obj = 0; target = 0; one_argument(argument, name); if(*name) { ret = generic_find(name, FIND_CHAR_ROOM | FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_ROOM, ch,&target); if(!ret) { /* we're we thinking of something? */ /* if not, then... */ send_to_char("You must cast on something.\n\r",ch); return ERROR_MISSING_TARGET; } object.attach_type = (ret==FIND_CHAR_ROOM ? ATTACH_CHAR : (ret==FIND_OBJ_INV || ret==FIND_OBJ_ROOM ? ATTACH_OBJ : ATTACH_ROOM)); object.attached_to.ch=(struct char_data *)target; } else { /** no arg means cast on yourself, for now **/ object.attach_type = ATTACH_CHAR; object.attached_to.ch = ch; } /*TEMP TEMP if (number(0,100) > sk->learned) { send_to_char("You lost your concentration!\n\r", ch); GET_MANA(ch) -= (USE_MANA(ch, spl)>>1); return ERROR_FAILED; } ***/ if(IS_SET(world[ch->in_room].room_flags,NO_MAGIC)) send_to_char("The magic gathers, then fades away.\n\r",ch); creator.attach_type = ATTACH_CHAR; creator.attached_to.ch = ch; if((error=create_magic(&creator,&m))!=OKAY) return(error); if((error=bind_magic_to_object(m,&object))!=OKAY) return(error); for(i=0;i<last_impart;i++) { sprintf(sbuf,"Syl %d = %s[%d]\n",i,mattribs[impart[i]].name,impart[i]); send_to_char(sbuf,ch); if((error = attribute_to_magic(m,mattribs[impart[i]].number,-5))) { sprintf(sbuf,"Error: %s\n",errors[error]); send_to_char(sbuf,ch); } } expend_magic(m,&object); return OKAY; }