diff --git a/src/Makefile.in b/src/Makefile.in index 5308258..895db0e 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -20,8 +20,8 @@ CFLAGS = @CFLAGS@ $(MYFLAGS) $(PROFILE) LIBS = @LIBS@ @CRYPTLIB@ @NETLIB@ -SRCFILES := act.comm.c act.informative.c act.item.c act.movement.c act.offensive.c act.other.c act.social.c act.wizard.c aedit.c asciimap.c ban.c boards.c bsd-snprintf.c castle.c cedit.c class.c comm.c config.c constants.c db.c dg_comm.c dg_db_scripts.c dg_event.c dg_handler.c dg_misc.c dg_mobcmd.c dg_objcmd.c dg_olc.c dg_scripts.c dg_triggers.c dg_variables.c dg_wldcmd.c fight.c genmob.c genobj.c genolc.c genqst.c genshp.c genwld.c genzon.c graph.c handler.c hedit.c house.c ibt.c improved-edit.c interpreter.c limits.c lists.c magic.c mail.c medit.c mobact.c modify.c msgedit.c mud_event.c oasis.c oasis_copy.c oasis_delete.c oasis_list.c objsave.c oedit.c players.c prefedit.c protocol.c qedit.c quest.c random.c redit.c sedit.c shop.c spec_assign.c spec_procs.c spell_parser.c spells.c tedit.c utils.c weather.c zedit.c zmalloc.c -OBJFILES := act.comm.o act.informative.o act.item.o act.movement.o act.offensive.o act.other.o act.social.o act.wizard.o aedit.o asciimap.o ban.o boards.o bsd-snprintf.o castle.o cedit.o class.o comm.o config.o constants.o db.o dg_comm.o dg_db_scripts.o dg_event.o dg_handler.o dg_misc.o dg_mobcmd.o dg_objcmd.o dg_olc.o dg_scripts.o dg_triggers.o dg_variables.o dg_wldcmd.o fight.o genmob.o genobj.o genolc.o genqst.o genshp.o genwld.o genzon.o graph.o handler.o hedit.o house.o ibt.o improved-edit.o interpreter.o limits.o lists.o magic.o mail.o medit.o mobact.o modify.o msgedit.o mud_event.o oasis.o oasis_copy.o oasis_delete.o oasis_list.o objsave.o oedit.o players.o prefedit.o protocol.o qedit.o quest.o random.o redit.o sedit.o shop.o spec_assign.o spec_procs.o spell_parser.o spells.o tedit.o utils.o weather.o zedit.o zmalloc.o +SRCFILES := act.comm.c act.informative.c act.item.c act.movement.c act.offensive.c act.other.c act.social.c act.wizard.c aedit.c asciimap.c ban.c boards.c bsd-snprintf.c castle.c cedit.c class.c comm.c config.c constants.c db.c dg_comm.c dg_db_scripts.c dg_event.c dg_handler.c dg_misc.c dg_mobcmd.c dg_objcmd.c dg_olc.c dg_scripts.c dg_triggers.c dg_variables.c dg_wldcmd.c fight.c genmob.c genobj.c genolc.c genqst.c genshp.c genwld.c genzon.c graph.c handler.c hedit.c house.c ibt.c improved-edit.c interpreter.c limits.c lists.c magic.c mail.c medit.c memorization.c mobact.c modify.c msgedit.c mud_event.c oasis.c oasis_copy.c oasis_delete.c oasis_list.c objsave.c oedit.c players.c prefedit.c protocol.c qedit.c quest.c random.c redit.c sedit.c shop.c spec_assign.c spec_procs.c spell_parser.c spells.c tedit.c utils.c weather.c zedit.c zmalloc.c +OBJFILES := act.comm.o act.informative.o act.item.o act.movement.o act.offensive.o act.other.o act.social.o act.wizard.o aedit.o asciimap.o ban.o boards.o bsd-snprintf.o castle.o cedit.o class.o comm.o config.o constants.o db.o dg_comm.o dg_db_scripts.o dg_event.o dg_handler.o dg_misc.o dg_mobcmd.o dg_objcmd.o dg_olc.o dg_scripts.o dg_triggers.o dg_variables.o dg_wldcmd.o fight.o genmob.o genobj.o genolc.o genqst.o genshp.o genwld.o genzon.o graph.o handler.o hedit.o house.o ibt.o improved-edit.o interpreter.o limits.o lists.o magic.o mail.o medit.o memorization.o mobact.o modify.o msgedit.o mud_event.o oasis.o oasis_copy.o oasis_delete.o oasis_list.o objsave.o oedit.o players.o prefedit.o protocol.o qedit.o quest.o random.o redit.o sedit.o shop.o spec_assign.o spec_procs.o spell_parser.o spells.o tedit.o utils.o weather.o zedit.o zmalloc.o default: all diff --git a/src/act.h b/src/act.h index 93cce58..cbb4496 100644 --- a/src/act.h +++ b/src/act.h @@ -226,6 +226,7 @@ ACMD(do_gen_tog); #define SCMD_PAGELENGTH 31 #define SCMD_SCREENWIDTH 32 #define SCMD_COLOR 33 +#define SCMD_AUTOMEM 34 /* do_quit */ ACMD(do_quit); @@ -250,7 +251,19 @@ ACMD(do_split); ACMD(do_steal); ACMD(do_title); ACMD(do_visible); +ACMD(do_cooldowns); +ACMD(do_memorize); +void do_mem_spell(struct char_data *ch, char *arg, int type, int message); +int is_memorized(struct char_data *ch, int spellnum, int single); +void update_mem(struct char_data *ch, bool mem_all); +void memorize_add(struct char_data * ch, int spellnum, int timer); +int is_innate(struct char_data *ch, int spellnum); +void cooldown_remove(struct char_data * ch, struct cooldown_node * cd); +int get_cooldown_timer(struct char_data *ch, int spellnum); +void cooldown_add(struct char_data * ch, int spellnum, int timer); +void update_cooldowns(); +void add_cooldown_timer(struct char_data *ch, int spellnum); /***************************************************************************** * Begin Functions and defines for act.social.c @@ -350,4 +363,10 @@ ACMD(do_zpurge); ACMD(do_zreset); ACMD(do_zunlock); +/* do_memorize */ +#define SCMD_MEMORIZE 0 +#define SCMD_STOP 1 +#define SCMD_FORGET 2 +#define SCMD_WHEN_SLOT 3 + #endif /* _ACT_H_ */ diff --git a/src/act.informative.c b/src/act.informative.c index e1187ef..d6f564b 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -1921,6 +1921,9 @@ ACMD(do_toggle) {"zoneresets", PRF_ZONERESETS, LVL_IMPL, "You will no longer see zone resets.\r\n", "You will now see zone resets.\r\n"}, + {"automem", PRF_AUTOMEM, 1, + "You will no longer automatically rememorize cast spells.\r\n", + "You will now automatically rememorize cast spells.\r\n"}, {"syslog", 0, LVL_IMMORT, "\n", "\n"}, {"wimpy", 0, 0, "\n", "\n"}, {"pagelength", 0, 0, "\n", "\n"}, @@ -2011,7 +2014,9 @@ ACMD(do_toggle) " Autokey: %-3s " " Autodoor: %-3s " - " Color: %s \r\n ", + " Color: %s \r\n " + + " Automem: %-3s \r\n ", ONOFF(PRF_FLAGGED(ch, PRF_DISPHP)), ONOFF(PRF_FLAGGED(ch, PRF_BRIEF)), @@ -2047,7 +2052,9 @@ ACMD(do_toggle) ONOFF(PRF_FLAGGED(ch, PRF_AUTOKEY)), ONOFF(PRF_FLAGGED(ch, PRF_AUTODOOR)), - types[COLOR_LEV(ch)]); + types[COLOR_LEV(ch)], + + ONOFF(PRF_FLAGGED(ch, PRF_AUTOMEM))); return; } diff --git a/src/act.offensive.c b/src/act.offensive.c index cb54edd..8da632f 100644 --- a/src/act.offensive.c +++ b/src/act.offensive.c @@ -126,13 +126,18 @@ ACMD(do_backstab) { char buf[MAX_INPUT_LENGTH]; struct char_data *vict; - int percent, prob; + int percent, prob, cd; if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_BACKSTAB)) { send_to_char(ch, "You have no idea how to do that.\r\n"); return; } + if((cd = get_cooldown_timer(ch, SKILL_BACKSTAB)) > 0) { + send_to_char(ch, "You must wait %d pulses before using %s\r\n", cd, spell_info[SKILL_BACKSTAB].name); + return; + } + one_argument(argument, buf); if (!(vict = get_char_vis(ch, buf, NULL, FIND_CHAR_ROOM))) { @@ -172,7 +177,8 @@ ACMD(do_backstab) else hit(ch, vict, SKILL_BACKSTAB); - WAIT_STATE(ch, 2 * PULSE_VIOLENCE); + WAIT_STATE(ch, 1 * PULSE_VIOLENCE); + add_cooldown_timer(ch, SKILL_BACKSTAB); } ACMD(do_order) @@ -269,7 +275,7 @@ ACMD(do_bash) { char arg[MAX_INPUT_LENGTH]; struct char_data *vict; - int percent, prob; + int percent, prob, cd; one_argument(argument, arg); @@ -277,6 +283,12 @@ ACMD(do_bash) send_to_char(ch, "You have no idea how.\r\n"); return; } + + if((cd = get_cooldown_timer(ch, SKILL_BASH)) > 0) { + send_to_char(ch, "You must wait %d pulses before using %s\r\n", cd, spell_info[SKILL_BASH].name); + return; + } + if (ROOM_FLAGGED(IN_ROOM(ch), ROOM_PEACEFUL)) { send_to_char(ch, "This room just has such a peaceful, easy feeling...\r\n"); return; @@ -324,20 +336,26 @@ ACMD(do_bash) GET_POS(vict) = POS_SITTING; } } - WAIT_STATE(ch, PULSE_VIOLENCE * 2); + WAIT_STATE(ch, PULSE_VIOLENCE * 1); + add_cooldown_timer(ch, SKILL_BASH); } ACMD(do_rescue) { char arg[MAX_INPUT_LENGTH]; struct char_data *vict, *tmp_ch; - int percent, prob; + int percent, prob, cd; if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_RESCUE)) { send_to_char(ch, "You have no idea how to do that.\r\n"); return; } + if((cd = get_cooldown_timer(ch, SKILL_RESCUE)) > 0) { + send_to_char(ch, "You must wait %d pulses before using %s\r\n", cd, spell_info[SKILL_RESCUE].name); + return; + } + one_argument(argument, arg); if (!(vict = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM))) { @@ -388,7 +406,8 @@ ACMD(do_rescue) set_fighting(ch, tmp_ch); set_fighting(tmp_ch, ch); - WAIT_STATE(vict, 2 * PULSE_VIOLENCE); + WAIT_STATE(vict, 1 * PULSE_VIOLENCE); + add_cooldown_timer(ch, SKILL_RESCUE); } EVENTFUNC(event_whirlwind) @@ -452,12 +471,18 @@ EVENTFUNC(event_whirlwind) * mud event and list systems. */ ACMD(do_whirlwind) { - + int cd; + if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_WHIRLWIND)) { send_to_char(ch, "You have no idea how.\r\n"); return; } - + + if((cd = get_cooldown_timer(ch, SKILL_WHIRLWIND)) > 0) { + send_to_char(ch, "You must wait %d pulses before using %s\r\n", cd, spell_info[SKILL_WHIRLWIND].name); + return; + } + if ROOM_FLAGGED(IN_ROOM(ch), ROOM_PEACEFUL) { send_to_char(ch, "This room just has such a peaceful, easy feeling...\r\n"); return; @@ -486,19 +511,25 @@ ACMD(do_whirlwind) * additional data. The event will be called in "3 * PASSES_PER_SEC" or 3 seconds */ NEW_EVENT(eWHIRLWIND, ch, NULL, 3 * PASSES_PER_SEC); WAIT_STATE(ch, PULSE_VIOLENCE * 3); + add_cooldown_timer(ch, SKILL_WHIRLWIND); } ACMD(do_kick) { char arg[MAX_INPUT_LENGTH]; struct char_data *vict; - int percent, prob; + int percent, prob, cd; if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_KICK)) { send_to_char(ch, "You have no idea how.\r\n"); return; } + if((cd = get_cooldown_timer(ch, SKILL_KICK)) > 0) { + send_to_char(ch, "You must wait %d pulses before using %s\r\n", cd, spell_info[SKILL_KICK].name); + return; + } + one_argument(argument, arg); if (!(vict = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM))) { @@ -522,14 +553,15 @@ ACMD(do_kick) } else damage(ch, vict, GET_LEVEL(ch) / 2, SKILL_KICK); - WAIT_STATE(ch, PULSE_VIOLENCE * 3); + WAIT_STATE(ch, PULSE_VIOLENCE * 1); + add_cooldown_timer(ch, SKILL_KICK); } ACMD(do_bandage) { char arg[MAX_INPUT_LENGTH]; struct char_data * vict; - int percent, prob; + int percent, prob, cd; if (!GET_SKILL(ch, SKILL_BANDAGE)) { @@ -537,6 +569,11 @@ ACMD(do_bandage) return; } + if((cd = get_cooldown_timer(ch, SKILL_BANDAGE)) > 0) { + send_to_char(ch, "You must wait %d pulses before using %s\r\n", cd, spell_info[SKILL_BANDAGE].name); + return; + } + if (GET_POS(ch) != POS_STANDING) { send_to_char(ch, "You are not in a proper position for that!\r\n"); return; @@ -554,7 +591,8 @@ ACMD(do_bandage) return; } - WAIT_STATE(ch, PULSE_VIOLENCE * 2); + WAIT_STATE(ch, PULSE_VIOLENCE * 1); + add_cooldown_timer(ch, SKILL_BANDAGE); percent = rand_number(1, 101); /* 101% is a complete failure */ prob = GET_SKILL(ch, SKILL_BANDAGE); diff --git a/src/act.other.c b/src/act.other.c index d5bb798..1eb0da8 100644 --- a/src/act.other.c +++ b/src/act.other.c @@ -731,7 +731,9 @@ ACMD(do_gen_tog) {"Autodoor disabled.\r\n", "Autodoor enabled.\r\n"}, {"ZoneResets disabled.\r\n", - "ZoneResets enabled.\r\n"} + "ZoneResets enabled.\r\n"}, + {"You will no longer automatically rememorize cast spells.\r\n", + "You will now automatically rememorize cast spells.\r\n"} }; if (IS_NPC(ch)) @@ -845,6 +847,9 @@ ACMD(do_gen_tog) case SCMD_ZONERESETS: result = PRF_TOG_CHK(ch, PRF_ZONERESETS); break; + case SCMD_AUTOMEM: + result = PRF_TOG_CHK(ch, PRF_AUTOMEM); + break; default: log("SYSERR: Unknown subcmd %d in do_gen_toggle.", subcmd); return; @@ -970,3 +975,148 @@ ACMD(do_happyhour) (3600 / SECS_PER_MUD_HOUR) ); } } + +/* Returns true if the spell/skillnum is innate to the character + (as opposed to just practiced). + */ +int is_innate(struct char_data *ch, int spellnum) +{ +/* + switch(spellnum) { + case SPELL_FAERIE_FIRE: + if(GET_RACE(ch) == RACE_DROW) + return TRUE; + break; + } +*/ + return FALSE; + +} + +/* called when a player enters the game to set permanent affects. + Usually these will stay set, but certain circumstances will + cause them to wear off (ie. removing eq with a perm affect). +*/ +void add_innate_affects(struct char_data *ch) +{ +/* + switch(GET_RACE(ch)) { + case RACE_ELF: + case RACE_DROW: + case RACE_DWARF: + case RACE_HALFELF: + case RACE_ILLITHID: + case RACE_HALFLING: + affect_modify(ch, APPLY_NONE, 0, AFF_INFRAVISION, TRUE); + break; + } + affect_total(ch); +*/ +} + +/* Remove a cooldown from a character's cooldown linked list */ +void cooldown_remove(struct char_data * ch, struct cooldown_node * cd) +{ + struct cooldown_node *temp; + + if (ch->cooldown == NULL) { + core_dump(); + return; + } + + REMOVE_FROM_LIST(cd, ch->cooldown, next); + free(cd); +} + +void cooldown_add(struct char_data * ch, int spellnum, int timer) +{ + struct cooldown_node * cd; + + CREATE(cd, struct cooldown_node, 1); + cd->timer = timer; + cd->spellnum = spellnum; + cd->next = ch->cooldown; + ch->cooldown = cd; +} + +/* Adds a node to the linked list with a timer which indicates + that the skill/spell is NOT ready to be used. */ +void add_cooldown_timer(struct char_data *ch, int spellnum) +{ + int timer = 1; /* number of pulses */ + + timer = spell_info[spellnum].cooldown; + + if(get_cooldown_timer(ch, spellnum) < 1) { + cooldown_add(ch, spellnum, timer); + } else { + send_to_char(ch, "BUG!\r\n"); + } +} + +/* Returns timer if the spell is found in the cooldown linked list, + otherwise returns 0. */ +int get_cooldown_timer(struct char_data *ch, int spellnum) +{ + struct cooldown_node *cd, *next_cd; + + for(cd = ch->cooldown; cd; cd = next_cd) { + next_cd = cd->next; + if(cd->spellnum == spellnum) + return cd->timer; + } + return 0; +} + +void update_cooldown(struct char_data *ch) +{ + struct cooldown_node *cd, *next_cd; + + for (cd = ch->cooldown; cd; cd = next_cd) { + next_cd = cd->next; + if (cd->timer > 1) { + cd->timer--; + } else { + /* add a case if you want a custom message */ + switch(cd->spellnum) { + case SPELL_ARMOR: + send_to_char(ch, "You are now able to use armor again!!\r\n"); + break; + default: + send_to_char(ch, "You are now able to use %s again.\r\n", spell_info[cd->spellnum].name); + break; + } + cooldown_remove(ch, cd); + } + } +} + +void update_cooldowns() +{ + struct char_data *i; + for (i = character_list; i; i = i->next) + { + if(!IS_NPC(i)) + update_cooldown(i); + } +} + +ACMD(do_cooldowns) +{ + struct cooldown_node *cd, *next_cd; + int count = 0; + + send_to_char(ch, "You are affected with these cooldowns: \r\n"); + + for (cd = ch->cooldown; cd; cd = next_cd) { + next_cd = cd->next; + send_to_char(ch, "%s%-22s %-3d%s", CCCYN(ch, C_NRM), spell_info[cd->spellnum].name, + cd->timer, CCNRM(ch, C_NRM)); + count ++; + if (count == 3) { + count = 0; + send_to_char(ch, "\r\n"); + } + } + send_to_char(ch, "\r\n"); +} diff --git a/src/act.wizard.c b/src/act.wizard.c index b0694ee..46d0a22 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -1622,6 +1622,8 @@ ACMD(do_restore) vict->real_abils.cha = 25; } } + /* memorize all spells */ + update_mem(NULL, TRUE); update_pos(vict); affect_total(vict); send_to_char(ch, "%s", CONFIG_OK); diff --git a/src/comm.c b/src/comm.c index 0c1ec9e..6f44257 100644 --- a/src/comm.c +++ b/src/comm.c @@ -1003,7 +1003,10 @@ void heartbeat(int heart_pulse) mobile_activity(); if (!(heart_pulse % PULSE_VIOLENCE)) + { perform_violence(); + update_cooldowns(); + } if (!(heart_pulse % (SECS_PER_MUD_HOUR * PASSES_PER_SEC))) { /* Tick ! */ next_tick = SECS_PER_MUD_HOUR; /* Reset tick coundown */ diff --git a/src/constants.c b/src/constants.c index 50e50f9..7779703 100644 --- a/src/constants.c +++ b/src/constants.c @@ -253,6 +253,7 @@ const char *preference_bits[] = { "AUTOKEY", "AUTODOOR", "ZONERESETS", + "AUTOMEM", "\n" }; diff --git a/src/handler.c b/src/handler.c index 61bca67..c81a396 100644 --- a/src/handler.c +++ b/src/handler.c @@ -198,6 +198,46 @@ static void aff_apply_modify(struct char_data *ch, byte loc, sbyte mod, char *ms GET_SAVE(ch, SAVING_SPELL) += mod; break; + case APPLY_SPELL_LVL_1: + if(!IS_NPC(ch)) + GET_SPELL_LEVEL(ch, SPELL_LEVEL_1) += mod; + break; + + case APPLY_SPELL_LVL_2: + if(!IS_NPC(ch)) + GET_SPELL_LEVEL(ch, SPELL_LEVEL_2) += mod; + break; + + case APPLY_SPELL_LVL_3: + if(!IS_NPC(ch)) + GET_SPELL_LEVEL(ch, SPELL_LEVEL_3) += mod; + break; + + case APPLY_SPELL_LVL_4: + if(!IS_NPC(ch)) + GET_SPELL_LEVEL(ch, SPELL_LEVEL_4) += mod; + break; + + case APPLY_SPELL_LVL_5: + if(!IS_NPC(ch)) + GET_SPELL_LEVEL(ch, SPELL_LEVEL_5) += mod; + break; + + case APPLY_SPELL_LVL_6: + if(!IS_NPC(ch)) + GET_SPELL_LEVEL(ch, SPELL_LEVEL_6) += mod; + break; + + case APPLY_SPELL_LVL_7: + if(!IS_NPC(ch)) + GET_SPELL_LEVEL(ch, SPELL_LEVEL_7) += mod; + break; + + case APPLY_SPELL_LVL_8: + if(!IS_NPC(ch)) + GET_SPELL_LEVEL(ch, SPELL_LEVEL_8) += mod; + break; + default: log("SYSERR: Unknown apply adjust %d attempt (%s, affect_modify).", loc, __FILE__); break; @@ -876,6 +916,7 @@ void extract_char_final(struct char_data *ch) struct descriptor_data *d; struct obj_data *obj; int i; + struct cooldown_node *cd = NULL, *next_cd = NULL; if (IN_ROOM(ch) == NOWHERE) { log("SYSERR: NOWHERE extracting char %s. (%s, extract_char_final)", @@ -976,6 +1017,13 @@ void extract_char_final(struct char_data *ch) } else { save_char(ch); Crash_delete_crashfile(ch); + + if(ch->cooldown) { + for (cd = ch->cooldown; cd; cd = next_cd) { + next_cd = cd->next; + cooldown_remove(ch, cd); + } + } } /* If there's a descriptor, they're in the menu now. */ diff --git a/src/interpreter.c b/src/interpreter.c index 0dadad0..fb9dbf0 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -98,6 +98,7 @@ cpp_extern const struct command_info cmd_info[] = { { "autokey" , "autokey" , POS_DEAD , do_gen_tog , 0, SCMD_AUTOKEY }, { "autoloot" , "autoloot", POS_DEAD , do_gen_tog , 0, SCMD_AUTOLOOT }, { "automap" , "automap" , POS_DEAD , do_gen_tog , 0, SCMD_AUTOMAP }, + { "automem" , "autome" , POS_DEAD , do_gen_tog , 1, SCMD_AUTOMEM }, { "autosac" , "autosac" , POS_DEAD , do_gen_tog , 0, SCMD_AUTOSAC }, { "autosplit", "autospl" , POS_DEAD , do_gen_tog , 0, SCMD_AUTOSPLIT }, @@ -122,6 +123,7 @@ cpp_extern const struct command_info cmd_info[] = { { "consider" , "con" , POS_RESTING , do_consider , 0, 0 }, { "commands" , "com" , POS_DEAD , do_commands , 0, SCMD_COMMANDS }, { "compact" , "comp" , POS_DEAD , do_gen_tog , 0, SCMD_COMPACT }, + { "cooldowns", "coo" , POS_DEAD , do_cooldowns , 1, 0 }, { "copyover" , "copyover", POS_DEAD , do_copyover , LVL_GRGOD, 0 }, { "credits" , "cred" , POS_DEAD , do_gen_ps , 0, SCMD_CREDITS }, @@ -151,6 +153,7 @@ cpp_extern const struct command_info cmd_info[] = { { "file" , "file" , POS_SLEEPING, do_file , LVL_GOD, 0 }, { "flee" , "fl" , POS_FIGHTING, do_flee , 1, 0 }, { "follow" , "fol" , POS_RESTING , do_follow , 0, 0 }, + { "forget" , "for" , POS_RESTING , do_memorize , 1, SCMD_FORGET }, { "freeze" , "freeze" , POS_DEAD , do_wizutil , LVL_GRGOD, SCMD_FREEZE }, { "get" , "g" , POS_RESTING , do_get , 0, 0 }, @@ -207,6 +210,8 @@ cpp_extern const struct command_info cmd_info[] = { { "mail" , "mail" , POS_STANDING, do_not_here , 1, 0 }, { "map" , "map" , POS_STANDING, do_map , 1, 0 }, { "medit" , "med" , POS_DEAD , do_oasis_medit, LVL_BUILDER, 0 }, + { "memorize" , "mem" , POS_RESTING , do_memorize , 1, SCMD_MEMORIZE }, + { "memwhen" , "memwhe" , POS_RESTING , do_memorize , LVL_IMMORT, SCMD_WHEN_SLOT }, { "mlist" , "mlist" , POS_DEAD , do_oasis_list, LVL_BUILDER, SCMD_OASIS_MLIST }, { "mcopy" , "mcopy" , POS_DEAD , do_oasis_copy, LVL_GOD, CON_MEDIT }, { "msgedit" , "msgedit" , POS_DEAD , do_msgedit, LVL_GOD, 0 }, @@ -300,6 +305,7 @@ cpp_extern const struct command_info cmd_info[] = { { "socials" , "socials" , POS_DEAD , do_commands , 0, SCMD_SOCIALS }, { "split" , "split" , POS_SITTING , do_split , 1, 0 }, { "stand" , "st" , POS_RESTING , do_stand , 0, 0 }, + { "stop" , "sto" , POS_RESTING , do_memorize , 1, SCMD_STOP }, { "stat" , "stat" , POS_DEAD , do_stat , LVL_IMMORT, 0 }, { "steal" , "ste" , POS_STANDING, do_steal , 1, 0 }, { "switch" , "switch" , POS_DEAD , do_switch , LVL_GOD, 0 }, diff --git a/src/memorization.c b/src/memorization.c new file mode 100644 index 0000000..a0e64a5 --- /dev/null +++ b/src/memorization.c @@ -0,0 +1,1309 @@ +/********************************* +* Memorization of spells * +*********************************/ + +/*****************************************************************************+ + +A linked list takes care of the spells being memorized, then when it is +finished, it is saved using an array ch->player_specials->saved.spellmem[i]. + +Storage in playerfile: +ch->player_specials->saved.spellmem[i] + +macros in utils.h: + +GET_SPELLMEM(ch, i) returns the spell which is memorized in that slot. + +defined in structs.h: + +MAX_MEM is the total number of spell slots which can be held by a player. + +void update_mem(void) is called in comm.c every tick to update the time +until a spell is memorized. + +In spell_parser.c at the end of ACMD(do_cast), spell slots are checked when +a spell is cast, and the appropriate spell is removed from memory. + +The number of available spell slots is determined by level and wisdom, + +Expansion options: +Bard - compose +Priest - pray + +Originally coded for StrifeMud (strife.betterbox.net 4101) + +******************************************************************************/ + +#include "conf.h" +#include "sysdep.h" +#include "structs.h" +#include "utils.h" +#include "comm.h" +#include "db.h" +#include "interpreter.h" +#include "spells.h" +#include "handler.h" +#include "constants.h" +#include "modify.h" +#include "class.h" +#include "act.h" + +void update_mem(struct char_data *ch, bool mem_all); +int findslotnum(struct char_data *ch, int spelllvl); +int find_freeslot(struct char_data *ch, int spelllvl); +int find_memspeed(struct char_data *ch, bool display); +void memorize_remove(struct char_data * ch, struct memorize_node * mem); +void memorize_add(struct char_data * ch, int spellnum, int timer); +void displayslotnum(struct char_data *ch, int class); + +/* snprintf used with the len += snprintf(len + buf, sizeof(buf) - len, ...) can + stil cause a buffer overflow if you don't check len > sizeof(buf) + before offsetting the next snprintf. + I tested with a reduced buf size on the rewrite to try to force some + overflows without a real overflow so it should be safer now. +*/ +void do_mem_display(struct char_data *ch) +{ + const char *overflow = "\r\n**OVERFLOW**\r\n"; + char buf[MAX_STRING_LENGTH], spellbuf[MAX_STRING_LENGTH]; + int speedfx, count, i, sortpos, columns; + size_t len = 0, sbuflen; + struct memorize_node *mem, *next; + + len = snprintf(buf, sizeof(buf), "\tcSpells in memory:\r\n\tn\r\n"); + + columns = 3; + /* List the memorized spells */ + for(i = 1; i < (MAX_SPELL_LEVEL - 1); i++) + { + if((i >= 1) && (findslotnum(ch, i) < 1)) + break; + + count = 0, sbuflen = 0; + spellbuf[0] = '\0'; + + for(sortpos = 0; sortpos < GET_MEMCURSOR(ch); sortpos++) + { + if ((GET_SPELLMEM(ch, sortpos) != 0) && (spell_info[GET_SPELLMEM(ch, sortpos)].spell_level == i)) + { + count++; + sbuflen += snprintf(spellbuf + sbuflen, sizeof(spellbuf) - sbuflen, + "\ty%-22.22s\tn%s", spell_info[GET_SPELLMEM(ch,sortpos)].name, + ((count % columns) == 0) ? "\r\n" : ""); + if (sbuflen > sizeof(spellbuf)) + break; + } + } + if (sbuflen >= sizeof(spellbuf)) { + strlcpy(spellbuf + sizeof(spellbuf) - strlen(overflow) - 1, overflow, sizeof(spellbuf)); + break; + } + len += snprintf(buf + len, sizeof(buf) - len, + "\tc---\twLevel \tR%d \twSpells\tc---=============================\tc---\tw[\tR%d/%d\tw]\tc---\tn\r\n" + "%s\r\n", + i, count, findslotnum(ch, i), spellbuf); + + if (len >= sizeof(buf)) + break; + } + + /* here, list of spells being memorized and time till */ + /* memorization complete */ + speedfx = find_memspeed(ch, TRUE); + + sbuflen = 0; + sbuflen = snprintf(spellbuf, sizeof(spellbuf), + "\tc----------------------------------------------------------------\tn\r\n" + "\tcSpells being memorized:\tn\r\n"); + count = 0; + columns = 2; + int hours = 0; + for (mem = ch->memorized; mem; mem = next) { + next = mem->next; + /* round up partial hours/ticks */ + if ((mem->timer % speedfx) == 0) + hours = mem->timer/speedfx; + else + hours = (mem->timer/speedfx)+1; + + sbuflen += snprintf(spellbuf + sbuflen, sizeof(spellbuf) - sbuflen, + "\ty%-20.20s\tw(\tr%2dhr\tw)\tn %s", spell_info[mem->spell].name, + hours, ((++count % columns) == 0) ? "\r\n" : ""); + + if(sbuflen >= sizeof(spellbuf)) + break; + } + + if (sbuflen >= sizeof(spellbuf)) + strlcpy(spellbuf + sizeof(spellbuf) - strlen(overflow) - 1, overflow, sizeof(spellbuf)); + + len += snprintf(buf + len, sizeof(buf) - len, "%s%s%s", spellbuf, + (count % columns != 0) ? "\r\n" : "", + (count == 0) ? "\tw(\trNone\tw)\tn\r\n" : ""); + + if (len >= sizeof(buf)) + strlcpy(buf + sizeof(buf) - strlen(overflow) - 1, overflow, sizeof(buf)); + + page_string(ch->desc, buf, 1); +} + +/****************************************************************************** + + Memorization time for each spell is equal to the level of the spell + 2 + multiplied by 5 at POS_STANDING. A level one spell would take + (1+2)*5=15 hours(ticks) to memorize when standing. + + POS_SITTING and POS_RESTING simulate the reduction in time by multiplying + the number subtracted from the MEMTIME each tick by 5. + + A character who has 15 hours(ticks) to memorize a spell standing will see + this on his display. When he is sitting, he will have 15 hours in MEMTIME, + but the display will divide by the value returned in find_memspeed to show + a value of 15/5 --> 3 hours sitting time. + + If a tick occurs while sitting, update_mem will subtract 5 hours of + "standing time" which is one hour of "sitting time" from the timer. + +******************************************************************************/ +int find_memspeed(struct char_data *ch, bool display) +{ + int speedfx = 0; + + if (GET_POS(ch) < POS_RESTING || GET_POS(ch) == POS_FIGHTING) { + if(display) + return 1; + return speedfx; + } else { + speedfx = 45 + int_app[GET_INT(ch)].memspeed; + if (GET_COND(ch, DRUNK) > 10) + speedfx = speedfx - 10; + if (GET_COND(ch, HUNGER) == 0) + speedfx = speedfx - 10; + if (GET_COND(ch, THIRST) == 0) + speedfx = speedfx - 10; + if (GET_POS(ch) == POS_STANDING) + speedfx /= 3; + speedfx = MAX(speedfx, 0); + if(display) + speedfx = MAX(speedfx, 1); + return speedfx; + } +} + +/********************************************/ +/* called during a tick to count down till */ +/* memorized in comm.c. */ +/********************************************/ +void update_mem(struct char_data *ch, bool mem_all) +{ + struct memorize_node *mem, *next_mem; + struct descriptor_data *d; + struct char_data *i; + int speedfx = 0; + + for (d = descriptor_list; d; d = d->next) { + if(ch) + i = ch; + else if(d->original) + i = d->original; + else if(!(i = d->character)) + continue; + speedfx = find_memspeed(i, FALSE); + for (mem = i->memorized; mem; mem = next_mem) { + next_mem = mem->next; + if (speedfx < mem->timer && !mem_all) { + mem->timer -= speedfx; + } else { + send_to_char(i, "You have finished memorizing %s.\r\n", + spell_info[mem->spell].name); + + GET_SPELLMEM(i, GET_MEMCURSOR(i)) = mem->spell; + GET_MEMCURSOR(i)++; + + memorize_remove(i, mem); + } + } + if(ch) + return; + } +} + +/* remove a spell from a character's memorize(in progress) linked list */ +void memorize_remove(struct char_data * ch, struct memorize_node * mem) +{ + struct memorize_node *temp; + + if (ch->memorized == NULL) { + core_dump(); + return; + } + + REMOVE_FROM_LIST(mem, ch->memorized, next); + free(mem); +} + +/* add a spell to a character's memorize(in progress) linked list */ +void memorize_add(struct char_data * ch, int spellnum, int timer) +{ + struct memorize_node * mem; + + CREATE(mem, struct memorize_node, 1); + mem->timer = timer; + mem->spell = spellnum; + mem->next = ch->memorized; + ch->memorized = mem; +} + +/********************************************/ +/* type is forget, memorize, or stop */ +/* message 0 for no message, 1 for message */ +/********************************************/ +void do_mem_spell(struct char_data *ch, char *arg, int type, int message) +{ + char *s; + int spellnum, i; + struct memorize_node *mem, *next; + + if (message == 1) { + s = strtok(arg, "\0"); + if (s == NULL) { + if (type == SCMD_MEMORIZE) + send_to_char(ch, "Memorize what spell?!?\r\n"); + if (type == SCMD_STOP) + send_to_char(ch, "Stop memorizing what spell?!?\r\n"); + if (type == SCMD_FORGET) + send_to_char(ch, "Forget what spell?!?\r\n"); + return; + } + spellnum = find_skill_num(s); + } else + spellnum = atoi(arg); + + switch(type) { + +/************* SCMD_MEMORIZE *************/ + + case SCMD_MEMORIZE: + if ((spellnum < 1) || (spellnum > MAX_SONGS)) { + send_to_char(ch, "Memorize what?!?\r\n"); + return; + } + + if (GET_SKILL(ch, spellnum) <= 0) { + send_to_char(ch, "You are unfamiliar with that spell.\r\n"); + return; + } + + /*if spell is practiced and there is an open spell slot*/ + if (find_freeslot(ch, spell_info[spellnum].spell_level) >= 1) { + memorize_add(ch, spellnum, ((spell_info[spellnum].spell_level + 2) * 50)); + if (message == 1) { + send_to_char(ch, "You start memorizing %s.\r\n", spell_info[spellnum].name); + return; + } + } else { + if (message) + send_to_char(ch, "All of your level %d spell slots are currently filled\r\n", + spell_info[spellnum].spell_level); + else + /* if automem toggle is on */ + send_to_char(ch, "You cannot auto-rememorize because all of your level %d spell slots are currently filled.\r\n", + spell_info[spellnum].spell_level); + } + break; + +/************* SCMD_STOP *************/ + + case SCMD_STOP: + if ((spellnum < 1) || (spellnum > MAX_SONGS)) { + send_to_char(ch, "Stop memorizing what?!?\r\n"); + return; + } + for (mem = ch->memorized; mem; mem = next) { + if (mem->spell == spellnum) { + send_to_char(ch, "You stop memorizing %s.\r\n", spell_info[spellnum].name); + memorize_remove(ch, mem); + return; + } + next = mem->next; + } + + send_to_char(ch, "%s is not being memorized.\r\n", spell_info[spellnum].name); + break; + +/************* SCMD_FORGET *************/ + + case SCMD_FORGET: + if ((spellnum < 1) || (spellnum > MAX_SONGS)) { + send_to_char(ch, "Forget what?!?\r\n"); + return; + } + for (i = 0; i < GET_MEMCURSOR(ch); i++) { + if (GET_SPELLMEM(ch, i) == spellnum){ + GET_MEMCURSOR(ch)--; + GET_SPELLMEM(ch, i) = GET_SPELLMEM(ch, GET_MEMCURSOR(ch)); + if (message) + send_to_char(ch, "You forget the spell, %s.\r\n", spell_info[spellnum].name); + return; + } + } + send_to_char(ch, "%s is not memorized.\r\n", spell_info[spellnum].name); + break; + +/***********************************/ + + } +} + +/* returns the number of slots memorized if single is 0 + returns 1 at the first occurance of the spell if memorized + and single is 1 (true). */ +int is_memorized(struct char_data *ch, int spellnum, int single) +{ + int memcheck = 0, i; + for (i = 0; i < GET_MEMCURSOR(ch); i++){ + if (GET_SPELLMEM(ch, i) == spellnum){ + memcheck++; + if(single) + return 1; + } + } + return memcheck; +} + +/**************************************************/ +/* returns 1 if slot of spelllvl is open 0 if not */ +/**************************************************/ + +int find_freeslot(struct char_data *ch, int spelllvl) +{ + struct memorize_node *mem, *next; + int i, memcheck = 0; + + /* checked the memorized array */ + for (i = 0;i < GET_MEMCURSOR(ch); i++) { + if (spell_info[GET_SPELLMEM(ch, i)].spell_level == spelllvl) { + memcheck++; + } + } + + /* check the memorize linked list */ + for (mem = ch->memorized; mem; mem = next) { + if (spell_info[mem->spell].spell_level == spelllvl) { + memcheck++; + } + next = mem->next; + } + + if (memcheck < findslotnum(ch, spelllvl)) { + return (1); + } else { + return 0; + } +} + +ACMD(do_memorize) +{ + char arg[MAX_INPUT_LENGTH]; + + if(IS_NPC(ch)) + return; + + one_argument(argument, arg); + + switch (subcmd) { + case SCMD_MEMORIZE: + if (!*arg) { + do_mem_display(ch); + } else { + if(!*argument) + send_to_char(ch, "Memorize what spell?\r\n"); + else + do_mem_spell(ch, argument, SCMD_MEMORIZE, 1); + } + break; + case SCMD_STOP: + if(!*argument) + send_to_char(ch, "Stop memorizing what?!?\r\n"); + else + do_mem_spell(ch, argument, SCMD_STOP, 1); + break; + case SCMD_FORGET: + if(!*argument) + send_to_char(ch, "Forget what spell?\r\n"); + else + do_mem_spell(ch, argument, SCMD_FORGET, 1); + break; + case SCMD_WHEN_SLOT: + displayslotnum(ch, GET_CLASS(ch)); + break; + default: + log("SYSERR: Unknown subcmd %d passed to do_memorize (%s)", subcmd, __FILE__); + break; + } +} + +/*************************************/ +/* Spell Levels */ +/* 1 2 3 4 5 6 7 8 */ +/*************************************/ +int spellslots_base[(NUM_CASTER_CATEGORY * (LVL_IMMORT))][(MAX_SPELL_LEVEL - 1)] = { + + /* Very-High level (arcanist) */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 0 */ + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 0, 0, 0, 0, 0, 0, 0 }, + { 3, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 5 */ + { 3, 1, 0, 0, 0, 0, 0, 0 }, + { 3, 1, 0, 0, 0, 0, 0, 0 }, + { 3, 1, 0, 0, 0, 0, 0, 0 }, + { 3, 1, 0, 0, 0, 0, 0, 0 }, + { 3, 2, 0, 0, 0, 0, 0, 0 }, /* lvl 10 */ + { 3, 2, 0, 0, 0, 0, 0, 0 }, + { 3, 2, 0, 0, 0, 0, 0, 0 }, + { 3, 2, 0, 0, 0, 0, 0, 0 }, + { 3, 2, 1, 0, 0, 0, 0, 0 }, + { 3, 2, 1, 0, 0, 0, 0, 0 }, /* lvl 15 */ + { 3, 2, 1, 0, 0, 0, 0, 0 }, + { 3, 2, 1, 0, 0, 0, 0, 0 }, + { 3, 2, 2, 0, 0, 0, 0, 0 }, + { 3, 2, 2, 0, 0, 0, 0, 0 }, + { 3, 2, 2, 0, 0, 0, 0, 0 }, /* lvl 20 */ + { 4, 2, 2, 0, 0, 0, 0, 0 }, + { 4, 2, 2, 0, 0, 0, 0, 0 }, + { 4, 2, 2, 1, 0, 0, 0, 0 }, + { 4, 2, 2, 1, 0, 0, 0, 0 }, + { 4, 2, 2, 1, 0, 0, 0, 0 }, /* lvl 25 */ + { 4, 2, 2, 1, 0, 0, 0, 0 }, + { 4, 3, 2, 2, 0, 0, 0, 0 }, + { 4, 3, 2, 2, 0, 0, 0, 0 }, + { 4, 3, 2, 2, 0, 0, 0, 0 }, + { 4, 3, 2, 2, 0, 0, 0, 0 }, /* lvl 30 */ + /* { 4, 3, 2, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 2, 1, 0, 0, 0 }, */ + /* { 5, 3, 2, 2, 1, 0, 0, 0 }, */ + /* { 5, 3, 2, 2, 1, 0, 0, 0 }, */ + /* { 5, 3, 2, 2, 1, 0, 0, 0 }, */ /* lvl 35 */ + /* { 5, 3, 3, 2, 2, 0, 0, 0 }, */ + /* { 5, 3, 3, 2, 2, 0, 0, 0 }, */ + /* { 5, 3, 3, 2, 2, 0, 0, 0 }, */ + /* { 5, 4, 3, 2, 2, 0, 0, 0 }, */ + /* { 5, 4, 3, 2, 2, 0, 0, 0 }, */ /* lvl 40 */ + /* { 5, 4, 3, 2, 2, 1, 0, 0 }, */ + /* { 5, 4, 3, 2, 2, 1, 0, 0 }, */ + /* { 5, 4, 3, 2, 2, 1, 0, 0 }, */ + /* { 5, 4, 3, 2, 2, 1, 0, 0 }, */ + /* { 5, 4, 3, 3, 2, 1, 0, 0 }, */ /* lvl 45 */ + /* { 5, 4, 3, 3, 2, 1, 0, 0 }, */ + /* { 5, 4, 3, 3, 2, 1, 0, 0 }, */ + /* { 5, 4, 4, 3, 2, 1, 0, 0 }, */ + /* { 5, 4, 4, 3, 2, 1, 0, 0 }, */ + /* { 5, 4, 4, 3, 2, 2, 0, 0 }, */ /* lvl 50 */ + /* { 5, 4, 4, 3, 2, 2, 0, 0 }, */ + /* { 5, 4, 4, 3, 2, 2, 0, 0 }, */ + /* { 5, 4, 4, 3, 2, 2, 0, 0 }, */ + /* { 5, 5, 4, 3, 3, 2, 1, 0 }, */ + /* { 5, 5, 4, 3, 3, 2, 1, 0 }, */ /* lvl 55 */ + /* { 5, 5, 4, 3, 3, 2, 1, 0 }, */ + /* { 5, 5, 4, 4, 3, 2, 1, 0 }, */ + /* { 5, 5, 4, 4, 3, 2, 1, 0 }, */ + /* { 5, 5, 4, 4, 3, 2, 1, 0 }, */ + /* { 5, 5, 4, 4, 3, 2, 1, 0 }, */ /* lvl 60 */ + /* { 5, 5, 4, 4, 3, 2, 1, 0 }, */ + /* { 5, 5, 4, 4, 3, 2, 2, 0 }, */ + /* { 5, 5, 5, 4, 3, 2, 2, 0 }, */ + /* { 5, 5, 5, 4, 3, 2, 2, 0 }, */ + /* { 5, 5, 5, 4, 3, 2, 2, 0 }, */ /* lvl 65 */ + /* { 5, 5, 5, 4, 4, 2, 2, 0 }, */ + /* { 5, 5, 5, 4, 4, 2, 2, 0 }, */ + /* { 5, 5, 5, 4, 4, 2, 2, 0 }, */ + /* { 5, 5, 5, 4, 4, 2, 2, 0 }, */ + /* { 5, 5, 5, 4, 4, 2, 2, 1 }, */ /* lvl 70 */ + /* { 5, 5, 5, 4, 4, 2, 2, 1 }, */ + /* { 5, 5, 5, 5, 4, 3, 2, 1 }, */ + /* { 5, 5, 5, 5, 4, 3, 2, 1 }, */ + /* { 5, 5, 5, 5, 4, 3, 2, 1 }, */ + /* { 5, 5, 5, 5, 4, 3, 2, 1 }, */ /* lvl 75 */ + /* { 5, 5, 5, 5, 4, 3, 2, 1 }, */ + /* { 5, 5, 5, 5, 4, 3, 2, 1 }, */ + /* { 5, 5, 5, 5, 4, 3, 2, 2 }, */ + /* { 5, 5, 5, 5, 4, 3, 2, 2 }, */ + /* { 5, 5, 5, 5, 4, 3, 2, 2 }, */ /* lvl 80 */ + /* { 5, 5, 5, 5, 4, 3, 3, 2 }, */ + /* { 5, 5, 5, 5, 4, 3, 3, 2 }, */ + /* { 5, 5, 5, 5, 4, 3, 3, 2 }, */ + /* { 5, 5, 5, 5, 4, 3, 3, 2 }, */ + /* { 5, 5, 5, 5, 4, 3, 3, 2 }, */ /* lvl 85 */ + /* { 5, 5, 5, 5, 4, 3, 3, 2 }, */ + /* { 5, 5, 5, 5, 4, 3, 3, 2 }, */ + /* { 5, 5, 5, 5, 4, 3, 3, 2 }, */ + /* { 5, 5, 5, 5, 4, 3, 3, 2 }, */ + /* { 5, 5, 5, 5, 4, 3, 3, 2 }, */ /* lvl 90 */ + /* { 6, 5, 5, 5, 4, 3, 3, 2 }, */ + /* { 6, 5, 5, 5, 4, 3, 3, 2 }, */ + /* { 6, 5, 5, 5, 4, 3, 3, 2 }, */ + /* { 6, 6, 5, 5, 4, 3, 3, 2 }, */ + /* { 6, 6, 5, 5, 4, 3, 3, 2 }, */ /* lvl 95 */ + /* { 6, 6, 6, 5, 4, 3, 3, 2 }, */ + /* { 6, 6, 6, 5, 4, 4, 3, 2 }, */ + /* { 6, 6, 6, 5, 4, 4, 4, 2 }, */ + /* { 6, 6, 6, 6, 5, 4, 4, 3 }, */ + /* { 6, 6, 6, 6, 5, 4, 4, 3 }, */ /* lvl 100 */ + + /* High-level caster Druid/Cleric */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 0 */ + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 5 */ + { 2, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, /* lvl 10 */ + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 3, 2, 0, 0, 0, 0, 0, 0 }, + { 3, 2, 0, 0, 0, 0, 0, 0 }, /* lvl 15 */ + { 3, 2, 0, 0, 0, 0, 0, 0 }, + { 3, 2, 0, 0, 0, 0, 0, 0 }, + { 3, 2, 1, 0, 0, 0, 0, 0 }, + { 3, 2, 1, 0, 0, 0, 0, 0 }, + { 3, 2, 1, 0, 0, 0, 0, 0 }, /* lvl 20 */ + { 3, 2, 1, 0, 0, 0, 0, 0 }, + { 3, 2, 2, 0, 0, 0, 0, 0 }, + { 3, 3, 2, 0, 0, 0, 0, 0 }, + { 3, 3, 2, 0, 0, 0, 0, 0 }, + { 4, 3, 2, 0, 0, 0, 0, 0 }, /* lvl 25 */ + { 4, 3, 2, 0, 0, 0, 0, 0 }, + { 4, 3, 2, 0, 0, 0, 0, 0 }, + { 4, 3, 2, 0, 0, 0, 0, 0 }, + { 4, 3, 2, 0, 0, 0, 0, 0 }, + { 4, 3, 2, 1, 0, 0, 0, 0 }, /* lvl 30 */ + /* { 4, 3, 2, 1, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 1, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 1, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ /* lvl 35 */ + /* { 5, 3, 3, 2, 0, 0, 0, 0 }, */ + /* { 5, 4, 3, 2, 0, 0, 0, 0 }, */ + /* { 5, 4, 3, 2, 0, 0, 0, 0 }, */ + /* { 5, 4, 3, 2, 1, 0, 0, 0 }, */ + /* { 5, 4, 3, 2, 1, 0, 0, 0 }, */ /* lvl 40 */ + /* { 5, 4, 3, 2, 1, 0, 0, 0 }, */ + /* { 5, 4, 3, 2, 1, 0, 0, 0 }, */ + /* { 5, 4, 3, 3, 2, 0, 0, 0 }, */ + /* { 5, 4, 3, 3, 2, 0, 0, 0 }, */ + /* { 5, 4, 3, 3, 2, 0, 0, 0 }, */ /* lvl 45 */ + /* { 5, 4, 4, 3, 2, 0, 0, 0 }, */ + /* { 5, 4, 4, 3, 2, 0, 0, 0 }, */ + /* { 5, 4, 4, 3, 2, 1, 0, 0 }, */ + /* { 5, 4, 4, 3, 2, 1, 0, 0 }, */ + /* { 5, 4, 4, 3, 2, 1, 0, 0 }, */ /* lvl 50 */ + /* { 5, 4, 4, 3, 2, 1, 0, 0 }, */ + /* { 5, 4, 4, 3, 2, 2, 0, 0 }, */ + /* { 5, 5, 4, 3, 3, 2, 0, 0 }, */ + /* { 5, 5, 4, 3, 3, 2, 0, 0 }, */ + /* { 5, 5, 4, 3, 3, 2, 0, 0 }, */ /* lvl 55 */ + /* { 5, 5, 4, 4, 3, 2, 0, 0 }, */ + /* { 5, 5, 4, 4, 3, 2, 1, 0 }, */ + /* { 5, 5, 4, 4, 3, 2, 1, 0 }, */ + /* { 5, 5, 4, 4, 3, 2, 1, 0 }, */ + /* { 5, 5, 4, 4, 3, 2, 1, 0 }, */ /* lvl 60 */ + /* { 5, 5, 5, 4, 3, 2, 2, 0 }, */ + /* { 5, 5, 5, 4, 3, 3, 2, 0 }, */ + /* { 5, 5, 5, 4, 3, 3, 2, 0 }, */ + /* { 5, 5, 5, 4, 3, 3, 2, 0 }, */ + /* { 5, 5, 5, 4, 3, 3, 2, 0 }, */ /* lvl 65 */ + /* { 5, 5, 5, 4, 3, 3, 2, 0 }, */ + /* { 5, 5, 5, 4, 4, 3, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 3, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 3, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 3, 2, 0 }, */ /* lvl 70 */ + /* { 5, 5, 5, 5, 4, 3, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 3, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 3, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 4, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 4, 2, 0 }, */ /* lvl 75 */ + /* { 5, 5, 5, 5, 4, 4, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 4, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 4, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 4, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 4, 2, 0 }, */ /* lvl 80 */ + /* { 5, 5, 5, 5, 4, 4, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 4, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 4, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 4, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 4, 2, 0 }, */ /* lvl 85 */ + /* { 5, 5, 5, 5, 4, 4, 2, 0 }, */ + /* { 5, 5, 5, 5, 4, 4, 3, 0 }, */ + /* { 5, 5, 5, 5, 4, 4, 3, 0 }, */ + /* { 5, 5, 5, 5, 4, 4, 3, 0 }, */ + /* { 5, 5, 5, 5, 4, 4, 3, 0 }, */ /* lvl 90 */ + /* { 6, 5, 5, 5, 4, 4, 3, 0 }, */ + /* { 6, 5, 5, 5, 4, 4, 3, 0 }, */ + /* { 6, 5, 5, 5, 4, 4, 3, 0 }, */ + /* { 6, 6, 5, 5, 4, 4, 3, 0 }, */ + /* { 6, 6, 5, 5, 5, 4, 3, 0 }, */ /* lvl 95 */ + /* { 6, 6, 5, 5, 5, 4, 3, 0 }, */ + /* { 6, 6, 6, 5, 5, 4, 4, 0 }, */ + /* { 6, 6, 6, 5, 5, 5, 4, 0 }, */ + /* { 6, 6, 6, 6, 5, 5, 4, 0 }, */ + /* { 6, 6, 6, 6, 5, 5, 4, 0 }, */ /* lvl 100 */ + + /* Upper Middle - Vampire */ + + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 0 */ + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 5 */ + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 10 */ + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, /* lvl 15 */ + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, /* lvl 20 */ + { 2, 1, 1, 0, 0, 0, 0, 0 }, + { 2, 1, 1, 0, 0, 0, 0, 0 }, + { 2, 1, 1, 0, 0, 0, 0, 0 }, + { 2, 1, 1, 0, 0, 0, 0, 0 }, + { 2, 2, 1, 0, 0, 0, 0, 0 }, /* lvl 25 */ + { 2, 2, 1, 0, 0, 0, 0, 0 }, + { 2, 2, 1, 0, 0, 0, 0, 0 }, + { 2, 2, 1, 0, 0, 0, 0, 0 }, + { 2, 2, 1, 0, 0, 0, 0, 0 }, + { 3, 2, 1, 1, 0, 0, 0, 0 }, /* lvl 30 */ + /* { 3, 2, 1, 1, 0, 0, 0, 0 }, */ + /* { 3, 2, 1, 1, 0, 0, 0, 0 }, */ + /* { 3, 2, 1, 1, 0, 0, 0, 0 }, */ + /* { 3, 2, 1, 1, 0, 0, 0, 0 }, */ + /* { 3, 2, 1, 1, 0, 0, 0, 0 }, */ /* lvl 35 */ + /* { 3, 2, 1, 1, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 1, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 1, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 1, 1, 0, 0, 0 }, */ + /* { 3, 2, 2, 1, 1, 0, 0, 0 }, */ /* lvl 40 */ + /* { 3, 2, 2, 1, 1, 0, 0, 0 }, */ + /* { 3, 2, 2, 1, 1, 0, 0, 0 }, */ + /* { 3, 2, 2, 1, 1, 0, 0, 0 }, */ + /* { 3, 2, 2, 1, 1, 0, 0, 0 }, */ + /* { 3, 3, 2, 1, 1, 0, 0, 0 }, */ /* lvl 45 */ + /* { 3, 3, 2, 2, 1, 0, 0, 0 }, */ + /* { 3, 3, 2, 2, 1, 0, 0, 0 }, */ + /* { 4, 3, 2, 2, 1, 1, 0, 0 }, */ + /* { 4, 3, 2, 2, 1, 1, 0, 0 }, */ + /* { 4, 3, 2, 2, 1, 1, 0, 0 }, */ /* lvl 50 */ + /* { 4, 3, 2, 2, 1, 1, 0, 0 }, */ + /* { 4, 3, 2, 2, 1, 1, 0, 0 }, */ + /* { 4, 3, 2, 2, 1, 1, 0, 0 }, */ + /* { 4, 3, 2, 2, 1, 1, 0, 0 }, */ + /* { 4, 3, 2, 2, 2, 1, 0, 0 }, */ /* lvl 55 */ + /* { 4, 3, 2, 2, 2, 1, 0, 0 }, */ + /* { 4, 3, 3, 2, 2, 1, 1, 0 }, */ + /* { 4, 3, 3, 2, 2, 1, 1, 0 }, */ + /* { 4, 3, 3, 2, 2, 1, 1, 0 }, */ + /* { 4, 3, 3, 2, 2, 1, 1, 0 }, */ /* lvl 60 */ + /* { 4, 3, 3, 2, 2, 1, 1, 0 }, */ + /* { 4, 3, 3, 2, 2, 1, 1, 0 }, */ + /* { 4, 3, 3, 2, 2, 1, 1, 0 }, */ + /* { 4, 3, 3, 2, 2, 2, 1, 0 }, */ + /* { 4, 3, 3, 2, 2, 2, 1, 0 }, */ /* lvl 65 */ + /* { 4, 4, 3, 3, 2, 2, 1, 0 }, */ + /* { 4, 4, 3, 3, 2, 2, 1, 0 }, */ + /* { 4, 4, 3, 3, 2, 2, 1, 0 }, */ + /* { 4, 4, 3, 3, 2, 2, 1, 0 }, */ + /* { 4, 4, 3, 3, 2, 2, 1, 0 }, */ /* lvl 70 */ + /* { 4, 4, 3, 3, 2, 2, 1, 0 }, */ + /* { 4, 4, 3, 3, 2, 2, 1, 0 }, */ + /* { 4, 4, 3, 3, 2, 2, 1, 0 }, */ + /* { 4, 4, 3, 3, 2, 2, 1, 0 }, */ + /* { 4, 4, 4, 3, 3, 2, 1, 0 }, */ /* lvl 75 */ + /* { 4, 4, 4, 3, 3, 2, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 2, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 2, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 2, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 2, 2, 0 }, */ /* lvl 80 */ + /* { 4, 4, 4, 3, 3, 2, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 2, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 2, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 3, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 3, 2, 0 }, */ /* lvl 85 */ + /* { 4, 4, 4, 3, 3, 3, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 3, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 3, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 3, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 3, 2, 0 }, */ /* lvl 90 */ + /* { 4, 4, 4, 3, 3, 3, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 3, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 3, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 3, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 3, 2, 0 }, */ /* lvl 95 */ + /* { 4, 4, 4, 3, 3, 3, 2, 0 }, */ + /* { 4, 4, 4, 3, 3, 3, 2, 0 }, */ + /* { 5, 4, 4, 3, 3, 3, 2, 0 }, */ + /* { 5, 4, 4, 3, 3, 3, 2, 0 }, */ + /* { 5, 4, 4, 3, 3, 3, 2, 0 }, */ /* lvl 100 */ + + /* Middle Caster - Paladin/Deathknight */ + + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 0 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 5 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 10 */ + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 15 */ + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, /* lvl 20 */ + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, /* lvl 25 */ + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, /* lvl 30 */ + /* { 2, 2, 0, 0, 0, 0, 0, 0 }, */ + /* { 2, 2, 0, 0, 0, 0, 0, 0 }, */ + /* { 2, 2, 0, 0, 0, 0, 0, 0 }, */ + /* { 2, 2, 1, 0, 0, 0, 0, 0 }, */ + /* { 2, 2, 1, 0, 0, 0, 0, 0 }, */ /* lvl 35 */ + /* { 2, 2, 1, 0, 0, 0, 0, 0 }, */ + /* { 2, 2, 1, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 1, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 1, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ /* lvl 40 */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ /* lvl 45 */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ /* lvl 50 */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ /* lvl 55 */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 1, 0, 0, 0, 0 }, */ /* lvl 60 */ + /* { 3, 2, 2, 1, 0, 0, 0, 0 }, */ + /* { 4, 2, 2, 1, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 1, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 1, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 1, 0, 0, 0, 0 }, */ /* lvl 65 */ + /* { 4, 3, 2, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 2, 0, 0, 0, 0 }, */ /* lvl 70 */ + /* { 4, 3, 2, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ /* lvl 75 */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ /* lvl 80 */ + /* { 4, 4, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 4, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 4, 3, 3, 0, 0, 0, 0 }, */ + /* { 5, 4, 3, 3, 0, 0, 0, 0 }, */ + /* { 5, 4, 3, 3, 0, 0, 0, 0 }, */ /* lvl 85 */ + /* { 5, 4, 3, 3, 0, 0, 0, 0 }, */ + /* { 5, 4, 3, 3, 0, 0, 0, 0 }, */ + /* { 5, 4, 3, 3, 1, 0, 0, 0 }, */ + /* { 5, 4, 3, 3, 1, 0, 0, 0 }, */ + /* { 5, 4, 4, 3, 1, 0, 0, 0 }, */ /* lvl 90 */ + /* { 5, 4, 4, 3, 1, 0, 0, 0 }, */ + /* { 5, 5, 4, 3, 1, 0, 0, 0 }, */ + /* { 5, 5, 4, 3, 2, 0, 0, 0 }, */ + /* { 5, 5, 4, 3, 2, 0, 0, 0 }, */ + /* { 5, 5, 4, 3, 2, 0, 0, 0 }, */ /* lvl 95 */ + /* { 5, 5, 4, 3, 2, 0, 0, 0 }, */ + /* { 5, 5, 4, 3, 2, 0, 0, 0 }, */ + /* { 5, 5, 4, 4, 2, 0, 0, 0 }, */ + /* { 5, 5, 4, 4, 3, 0, 0, 0 }, */ + /* { 5, 5, 4, 4, 3, 0, 0, 0 }, */ /* lvl 100 */ + + /* Lower Middle - Ranger/Bard */ + + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 0 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 5 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 10 */ + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 15 */ + { 2, 0, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 1, 0, 0, 0, 0, 0, 0 }, /* lvl 20 */ + { 2, 1, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, /* lvl 25 */ + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, + { 2, 2, 0, 0, 0, 0, 0, 0 }, /* lvl 30 */ + /* { 2, 2, 0, 0, 0, 0, 0, 0 }, */ + /* { 2, 2, 0, 0, 0, 0, 0, 0 }, */ + /* { 2, 2, 0, 0, 0, 0, 0, 0 }, */ + /* { 2, 2, 0, 0, 0, 0, 0, 0 }, */ + /* { 2, 2, 0, 0, 0, 0, 0, 0 }, */ /* lvl 35 */ + /* { 2, 2, 1, 0, 0, 0, 0, 0 }, */ + /* { 2, 2, 1, 0, 0, 0, 0, 0 }, */ + /* { 2, 2, 1, 0, 0, 0, 0, 0 }, */ + /* { 2, 2, 1, 0, 0, 0, 0, 0 }, */ + /* { 2, 2, 1, 0, 0, 0, 0, 0 }, */ /* lvl 40 */ + /* { 2, 2, 1, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 1, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ /* lvl 45 */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ /* lvl 50 */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 3, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 4, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 4, 2, 2, 0, 0, 0, 0, 0 }, */ /* lvl 55 */ + /* { 4, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 4, 2, 2, 0, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 0, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 0, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 0, 0, 0, 0, 0 }, */ /* lvl 60 */ + /* { 4, 3, 2, 1, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 1, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 1, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 1, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 1, 0, 0, 0, 0 }, */ /* lvl 65 */ + /* { 4, 3, 2, 1, 0, 0, 0, 0 }, */ + /* { 4, 3, 2, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ /* lvl 70 */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 3, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 4, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 4, 3, 2, 0, 0, 0, 0 }, */ /* lvl 75 */ + /* { 4, 4, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 4, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 4, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 4, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 4, 3, 2, 0, 0, 0, 0 }, */ /* lvl 80 */ + /* { 4, 4, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 4, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 4, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 4, 3, 2, 0, 0, 0, 0 }, */ + /* { 4, 4, 4, 3, 0, 0, 0, 0 }, */ /* lvl 85 */ + /* { 4, 4, 4, 3, 0, 0, 0, 0 }, */ + /* { 4, 4, 4, 3, 0, 0, 0, 0 }, */ + /* { 4, 4, 4, 3, 0, 0, 0, 0 }, */ + /* { 4, 4, 4, 3, 0, 0, 0, 0 }, */ + /* { 4, 4, 4, 3, 0, 0, 0, 0 }, */ /* lvl 90 */ + /* { 4, 4, 4, 3, 0, 0, 0, 0 }, */ + /* { 4, 4, 4, 3, 0, 0, 0, 0 }, */ + /* { 4, 4, 4, 3, 0, 0, 0, 0 }, */ + /* { 5, 4, 4, 3, 0, 0, 0, 0 }, */ + /* { 5, 4, 4, 3, 0, 0, 0, 0 }, */ /* lvl 95 */ + /* { 5, 5, 4, 3, 0, 0, 0, 0 }, */ + /* { 5, 5, 4, 3, 0, 0, 0, 0 }, */ + /* { 5, 5, 4, 4, 0, 0, 0, 0 }, */ + /* { 5, 5, 4, 4, 0, 0, 0, 0 }, */ + /* { 5, 5, 4, 4, 0, 0, 0, 0 }, */ /* lvl 100 */ + + /* Lower - Assassin */ + + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 0 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 5 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 10 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 15 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 20 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 25 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 30 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 35 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 40 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 45 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 50 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 55 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 60 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 65 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 70 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 75 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 80 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 85 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 90 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 95 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 1, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 1, 1, 0, 0, 0, 0, 0, 0 }, */ + /* { 2, 1, 0, 0, 0, 0, 0, 0 }, */ + /* { 2, 2, 0, 0, 0, 0, 0, 0 }, */ /* lvl 100 */ + + /* No_cast - Rogue/Warrior */ + + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 0 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 5 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 10 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 15 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 20 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 25 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* lvl 30 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 35 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 40 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 45 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 50 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 55 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 60 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 65 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 70 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 75 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 80 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 85 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 90 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ /* lvl 95 */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 }, */ + /* { 0, 0, 0, 0, 0, 0, 0, 0 } */ /* lvl 100 */ +}; + +/********************************/ +/* bonus spells based on wisdom */ +/********************************/ +int spellslots_bonus[26][8] = { + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 0 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 1 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 2 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 3 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 4 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 5 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 6 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 7 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 8 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 9 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 10 */ + { 0, 0, 0, 0, 0, 0, 0, 0 }, /* 11 */ + { 1, 0, 0, 0, 0, 0, 0, 0 }, /* 12 */ + { 1, 1, 0, 0, 0, 0, 0, 0 }, /* 13 */ + { 1, 1, 1, 0, 0, 0, 0, 0 }, /* 14 */ + { 1, 1, 1, 1, 0, 0, 0, 0 }, /* 15 */ + { 2, 1, 1, 1, 1, 0, 0, 0 }, /* 16 */ + { 2, 2, 1, 1, 1, 1, 0, 0 }, /* 17 */ + { 2, 2, 2, 1, 1, 1, 1, 0 }, /* 18 MAX_HUMAN NATURAL */ + { 2, 2, 2, 2, 1, 1, 1, 1 }, /* 19 */ + { 2, 2, 2, 2, 2, 1, 1, 1 }, /* 20 */ + { 2, 2, 2, 2, 2, 2, 1, 1 }, /* 21 */ + { 3, 2, 2, 2, 2, 2, 2, 1 }, /* 22 */ + { 3, 3, 2, 2, 2, 2, 2, 2 }, /* 23 */ + { 3, 3, 3, 2, 2, 2, 2, 2 }, /* 24 MAX_MORT */ + { 3, 3, 3, 3, 2, 2, 2, 2 }, /* 25 IMM-ONLY */ +}; + +/*****************************************************************/ +/* Returns the number of spell slots for the character and spell */ +/* level requested */ +/*****************************************************************/ +int findslotnum(struct char_data *ch, int spell_level) +{ + int slots, spell_mod, stat_mod, slevel = 0, slot_category = 0; + + switch(GET_CLASS(ch)) { + case CLASS_MAGIC_USER: + slot_category = SLOT_TYPE_VERY_HIGH; + break; +// case CLASS_DRUID: + case CLASS_CLERIC: + slot_category = SLOT_TYPE_HIGH; + break; +/* + case CLASS_VAMPIRE: + slot_category = SLOT_TYPE_UPPER_MIDDLE; + break; + case CLASS_PALADIN: + case CLASS_DEATHKNIGHT: + slot_category = SLOT_TYPE_MIDDLE; + break; + case CLASS_RANGER: + case CLASS_BARD: + slot_category = SLOT_TYPE_LOWER_MIDDLE; + break; +*/ + case CLASS_WARRIOR: +// case CLASS_BARBARIAN: + case CLASS_THIEF: + slot_category = SLOT_TYPE_NO_CAST; + break; + default: + slot_category = SLOT_TYPE_NO_CAST; + break; + } +/* + if(IS_REMORT(ch) && GET_CLASS(ch) == CLASS_WARRIOR && GET_REMORT(ch) == REMORT_MONK) + slot_category = SLOT_TYPE_LOWER_MIDDLE; + else if(IS_REMORT(ch) && GET_REMORT(ch) == REMORT_CRUSADER) + slot_category = SLOT_TYPE_MIDDLE; + else if(IS_REMORT(ch) && GET_REMORT(ch) == REMORT_ASSASSIN && GET_CLASS(ch) == CLASS_THIEF) + slot_category = SLOT_TYPE_LOWER; + else if(IS_REMORT(ch) && (GET_REMORT(ch) == REMORT_CHOSEN || GET_REMORT(ch) == REMORT_ELDER_DRUID)) + slot_category = SLOT_TYPE_VERY_HIGH; +*/ + slevel = slot_category * (LVL_IMMORT) + MIN(GET_LEVEL(ch), (LVL_IMMORT - 1)); + + /* check wisdom for bonus spell slots */ + stat_mod = spellslots_bonus[GET_WIS(ch)][spell_level-1]; + + spell_mod = spellslots_base[slevel][spell_level-1]; + + slots = spell_mod + stat_mod; + + /* if they don't have a base slot, don't give a wis bonus slot */ + if (!stat_mod) + slots = 0; + + /* for APPLY_SPELL_LEVEL gear bonus */ + slots += GET_SPELL_LEVEL(ch, spell_level); + + return MAX(0, MIN(MAX_SPELLS_PER_SPELL_SLOT, slots)); +} + +void displayslotnum(struct char_data *ch, int class) +{ + char buf[MAX_INPUT_LENGTH]; + char slot_buf[MAX_STRING_LENGTH * 10]; + int i, j, slevel = 0; + + snprintf(slot_buf, sizeof(slot_buf), "test\r\n"); + + for(class = 0; class < NUM_CLASSES; class++) { + snprintf(buf, sizeof(buf), "\r\n/* %s */\r\n\r\n", pc_class_types[class]); + strcat(slot_buf, buf); + for(i = 0; i < LVL_IMMORT; i++) { + strcat(slot_buf, " { "); + slevel = i/3; + slevel = MIN(slevel, 30); + if (i > 0) + slevel = MAX(slevel, 1); + slevel += (class * 31); + for(j = 0; j < 8; j++) { + snprintf(buf, sizeof(buf), " %d%s ", spellslots_base[slevel][j], (j==7) ? "" : ","); + strcat(slot_buf, buf); + } + strcat(slot_buf, " },"); + if(i%5 == 0) { + snprintf(buf, sizeof(buf), " /* lvl %d */", i); + strcat(slot_buf, buf); + } + strcat(slot_buf, "\r\n"); + } + } + page_string(ch->desc, slot_buf, 1); +} diff --git a/src/players.c b/src/players.c index 1e76197..7634355 100644 --- a/src/players.c +++ b/src/players.c @@ -22,6 +22,7 @@ #include "config.h" /* for pclean_criteria[] */ #include "dg_scripts.h" /* To enable saving of player variables to disk */ #include "quest.h" +#include "act.h" #define LOAD_HIT 0 #define LOAD_MANA 1 @@ -227,7 +228,7 @@ char *get_name_by_id(long id) * if not. */ int load_char(const char *name, struct char_data *ch) { - int id, i; + int id, i, j, k; FILE *fl; char filename[40]; char buf[128], buf2[128], line[MAX_INPUT_LENGTH + 1], tag[6]; @@ -343,6 +344,16 @@ int load_char(const char *name, struct char_data *ch) if (!strcmp(tag, "Cha ")) ch->real_abils.cha = atoi(line); else if (!strcmp(tag, "Clas")) GET_CLASS(ch) = atoi(line); else if (!strcmp(tag, "Con ")) ch->real_abils.con = atoi(line); + else if (!strcmp(tag, "Cool")) { + i = 0; + do { + get_line(fl, line); + sscanf(line, "%d %d", &j, &k); + if(j != -1) + cooldown_add(ch, j, k); + i++; + } while (j != -1); + } break; case 'D': @@ -436,6 +447,24 @@ int load_char(const char *name, struct char_data *ch) if (!strcmp(tag, "Sex ")) GET_SEX(ch) = atoi(line); else if (!strcmp(tag, "ScrW")) GET_SCREEN_WIDTH(ch) = atoi(line); else if (!strcmp(tag, "Skil")) load_skills(fl, ch); + else if (!strcmp(tag, "Smem")) { + i = 0; + do { + get_line(fl, line); + sscanf(line, "%d %d", &j, &k); + if (j != -1) { + /* if memorized add to arrays */ + if(k == 0) { + GET_SPELLMEM(ch, GET_MEMCURSOR(ch)) = j; + GET_MEMCURSOR(ch)++; + /* otherwise add to in-progress linked-list */ + } else { + memorize_add(ch, j, k); + } + } + i++; + } while (j != -1); + } else if (!strcmp(tag, "Str ")) load_HMVS(ch, line, LOAD_STRENGTH); break; @@ -497,6 +526,8 @@ void save_char(struct char_data * ch) struct affected_type *aff, tmp_aff[MAX_AFFECT]; struct obj_data *char_eq[NUM_WEARS]; trig_data *t; + struct memorize_node *mem, *next; + struct cooldown_node *cd, *next_cd; if (IS_NPC(ch) || GET_PFILEPOS(ch) < 0) return; @@ -661,6 +692,28 @@ void save_char(struct char_data * ch) } if (GET_QUEST(ch) != PFDEF_CURRQUEST) fprintf(fl, "Qcur: %d\n", GET_QUEST(ch)); + /* Memorized spells */ + fprintf(fl, "Smem:\n"); + for(i = 0; i < GET_MEMCURSOR(ch); i++) { + if(GET_SPELLMEM(ch, i) > 0) + fprintf(fl, "%d %d\n", GET_SPELLMEM(ch, i), 0); + } + /* Spells being memorized */ + for (mem = ch->memorized; mem; mem = next) { + next = mem->next; + fprintf(fl, "%d %d\n", mem->spell, mem->timer); + } + fprintf(fl, "-1 0\n"); + + /* Cooldown timers (replaces/includes innate timers) + but timer is pulse based instead of tick based */ + fprintf(fl, "Cool:\n"); + for (cd = ch->cooldown; cd; cd = next_cd) { + next_cd = cd->next; + fprintf(fl, "%d %d\n", cd->spellnum, cd->timer); + } + fprintf(fl, "-1 0\n"); + if (SCRIPT(ch)) { for (t = TRIGGERS(SCRIPT(ch)); t; t = t->next) fprintf(fl, "Trig: %d\n",GET_TRIG_VNUM(t)); diff --git a/src/prefedit.c b/src/prefedit.c index 35356fb..dec741c 100755 --- a/src/prefedit.c +++ b/src/prefedit.c @@ -231,7 +231,8 @@ static void prefedit_disp_toggles_menu(struct descriptor_data *d) send_to_char(d->character, "%s7%s) Automap %s[%s%3s%s]\r\n" "%s8%s) Autokey %s[%s%3s%s]\r\n" - "%s9%s) Autodoor %s[%s%3s%s]\r\n", + "%s9%s) Autodoor %s[%s%3s%s]\r\n" + "%sS%s) Automem %s[%s%3s%s]\r\n", /* Line 7 - automap */ CBYEL(d->character, C_NRM), CCNRM(d->character, C_NRM), CCCYN(d->character, C_NRM), PREFEDIT_FLAGGED(PRF_AUTOMAP) ? CBGRN(d->character, C_NRM) : CBRED(d->character, C_NRM), ONOFF(PREFEDIT_FLAGGED(PRF_AUTOMAP)), CCCYN(d->character, C_NRM), @@ -240,7 +241,10 @@ static void prefedit_disp_toggles_menu(struct descriptor_data *d) ONOFF(PREFEDIT_FLAGGED(PRF_AUTOKEY)), CCCYN(d->character, C_NRM), /* Line 9 - autodoor */ CBYEL(d->character, C_NRM), CCNRM(d->character, C_NRM), CCCYN(d->character, C_NRM), PREFEDIT_FLAGGED(PRF_AUTODOOR) ? CBGRN(d->character, C_NRM) : CBRED(d->character, C_NRM), - ONOFF(PREFEDIT_FLAGGED(PRF_AUTODOOR)), CCCYN(d->character, C_NRM) + ONOFF(PREFEDIT_FLAGGED(PRF_AUTODOOR)), CCCYN(d->character, C_NRM), +/* Line 9 - automem */ + CBYEL(d->character, C_NRM), CCNRM(d->character, C_NRM), CCCYN(d->character, C_NRM), PREFEDIT_FLAGGED(PRF_AUTOMEM) ? CBGRN(d->character, C_NRM) : CBRED(d->character, C_NRM), + ONOFF(PREFEDIT_FLAGGED(PRF_AUTOMEM)), CCCYN(d->character, C_NRM) ); /* The bottom section of the toggles menu */ @@ -597,6 +601,11 @@ void prefedit_parse(struct descriptor_data * d, char *arg) TOGGLE_BIT_AR(PREFEDIT_GET_FLAGS, PRF_AUTODOOR); break; + case 's': + case 'S': + TOGGLE_BIT_AR(PREFEDIT_GET_FLAGS, PRF_AUTOMEM); + break; + case 'a': case 'A': TOGGLE_BIT_AR(PREFEDIT_GET_FLAGS, PRF_NOGOSS); diff --git a/src/spell_parser.c b/src/spell_parser.c index dd2f7f7..e4afde9 100644 --- a/src/spell_parser.c +++ b/src/spell_parser.c @@ -19,6 +19,7 @@ #include "db.h" #include "dg_scripts.h" #include "fight.h" /* for hit() */ +#include "act.h" #define SINFO spell_info[spellnum] @@ -31,8 +32,8 @@ const char *unused_spellname = "!UNUSED!"; /* So we can get &unused_spellname */ static void say_spell(struct char_data *ch, int spellnum, struct char_data *tch, struct obj_data *tobj); static void spello(int spl, const char *name, int max_mana, int min_mana, - int mana_change, int minpos, int targets, int violent, int routines, - const char *wearoff); + int mana_change, int minpos, int spell_level, int cooldown, int targets, int violent, + int routines, const char *wearoff); static int mag_manacost(struct char_data *ch, int spellnum); /* Local (File Scope) Variables */ @@ -506,7 +507,7 @@ ACMD(do_cast) { struct char_data *tch = NULL; struct obj_data *tobj = NULL; char *s, *t; - int number, mana, spellnum, i, target = 0; + int number, mana = 0, spellnum, i, target = 0, cd; if (IS_NPC(ch)) return; @@ -539,9 +540,11 @@ ACMD(do_cast) { send_to_char(ch, "You do not know that spell!\r\n"); return; } - if (GET_SKILL(ch, spellnum) == 0) { - send_to_char(ch, "You are unfamiliar with that spell.\r\n"); - return; + if (!is_innate(ch, spellnum)) { + if (GET_SKILL(ch, spellnum) <= 0) { + send_to_char(ch, "You are unfamiliar with that spell.\r\n"); + return; + } } /* Find the target */ if (t != NULL) { @@ -618,28 +621,57 @@ ACMD(do_cast) { send_to_char(ch, "Cannot find the target of your spell!\r\n"); return; } - mana = mag_manacost(ch, spellnum); - if ((mana > 0) && (GET_MANA(ch) < mana) && (GET_LEVEL(ch) < LVL_IMMORT)) { - send_to_char(ch, "You haven't the energy to cast that spell!\r\n"); - return; + + /* Cooldown will prevent innate, memorized, or mana based spells for now */ + if ((cd = get_cooldown_timer(ch, spellnum)) > 0) { + send_to_char(ch, "You must wait %d pulses before using %s\r\n", cd, SINFO.name); + return; + } + + if(!is_innate(ch, spellnum)) { + if(IS_MANA_USER(ch)) { + mana = mag_manacost(ch, spellnum); + if ((mana > 0) && (GET_MANA(ch) < mana) && (GET_LEVEL(ch) < LVL_IMMORT)) { + send_to_char(ch, "You haven't the energy to cast that spell!\r\n"); + return; + } + } else if (!is_memorized(ch, spellnum, TRUE)) { + send_to_char(ch, "You do not have that spell memorized!\r\n"); + return; + } } /* You throws the dice and you takes your chances.. 101% is total failure */ - if (rand_number(0, 101) > GET_SKILL(ch, spellnum)) { + if (!is_innate(ch, spellnum) && rand_number(0, 101) > GET_SKILL(ch, spellnum)) { + /* You get a c/d and a waitstate for missing */ WAIT_STATE(ch, PULSE_VIOLENCE); if (!tch || !skill_message(0, ch, tch, spellnum)) send_to_char(ch, "You lost your concentration!\r\n"); - if (mana > 0) - GET_MANA(ch) = MAX(0, MIN(GET_MAX_MANA(ch), GET_MANA(ch) - (mana / 2))); if (SINFO.violent && tch && IS_NPC(tch)) - hit(tch, ch, TYPE_UNDEFINED); + hit(tch, ch, TYPE_UNDEFINED); } else { /* cast spell returns 1 on success; subtract mana & set waitstate */ - if (cast_spell(ch, tch, tobj, spellnum)) { - WAIT_STATE(ch, PULSE_VIOLENCE); - if (mana > 0) + /* removed waitstate since you'll get a c/d on that spell */ + cast_spell(ch, tch, tobj, spellnum); + } + + /* innate spells don't use mana or a memorize slot */ + if (!is_innate(ch, spellnum)) { + if (IS_MANA_USER(ch)) { + /* removed half price mana for a miss */ + if(mana > 0) GET_MANA(ch) = MAX(0, MIN(GET_MAX_MANA(ch), GET_MANA(ch) - mana)); } + else { + char buffer[10]; + snprintf(buffer, sizeof(buffer), "%d", spellnum); + /* Take away the mem spell from memory, remem if automem is on */ + do_mem_spell(ch, buffer, SCMD_FORGET, 0); + if (PRF_FLAGGED(ch, PRF_AUTOMEM)) + do_mem_spell(ch, buffer, SCMD_MEMORIZE, 0); + } } + /* everyone gets a cooldown */ + add_cooldown_timer(ch, spellnum); } void spell_level(int spell, int chclass, int level) { @@ -669,8 +701,8 @@ void spell_level(int spell, int chclass, int level) { /* Assign the spells on boot up */ static void spello(int spl, const char *name, int max_mana, int min_mana, - int mana_change, int minpos, int targets, int violent, int routines, - const char *wearoff) { + int mana_change, int minpos, int spell_level, int cooldown, int targets, int violent, + int routines, const char *wearoff) { int i; for (i = 0; i < NUM_CLASSES; i++) @@ -679,6 +711,8 @@ static void spello(int spl, const char *name, int max_mana, int min_mana, spell_info[spl].mana_min = min_mana; spell_info[spl].mana_change = mana_change; spell_info[spl].min_position = minpos; + spell_info[spl].spell_level = spell_level; + spell_info[spl].cooldown = cooldown; spell_info[spl].targets = targets; spell_info[spl].violent = violent; spell_info[spl].routines = routines; @@ -695,13 +729,15 @@ void unused_spell(int spl) { spell_info[spl].mana_min = 0; spell_info[spl].mana_change = 0; spell_info[spl].min_position = 0; + spell_info[spl].spell_level = 0; + spell_info[spl].cooldown = 0; spell_info[spl].targets = 0; spell_info[spl].violent = 0; spell_info[spl].routines = 0; spell_info[spl].name = unused_spellname; } -#define skillo(skill, name) spello(skill, name, 0, 0, 0, 0, 0, 0, 0, NULL); +#define skillo(skill, name, cooldown) spello(skill, name, 0, 0, 0, 0, 0, cooldown, 0, 0, 0, NULL); /* Arguments for spello calls: * spellnum, maxmana, minmana, manachng, minpos, targets, violent?, routines. * spellnum: Number of the spell. Usually the symbolic name as defined in @@ -717,6 +753,8 @@ void unused_spell(int spl) { * minpos : Minimum position the caster must be in for the spell to work * (usually fighting or standing). targets : A "list" of the valid targets * for the spell, joined with bitwise OR ('|'). + * spell_level : spell level for classes that memorize spells + * cooldown : cooldown in pulses (violence) that a spell institutes. * violent : TRUE or FALSE, depending on if this is considered a violent * spell and should not be cast in PEACEFUL rooms or on yourself. Should be * set on any spell that inflicts damage, is considered aggressive (i.e. @@ -735,197 +773,197 @@ void mag_assign_spells(void) { /* Do not change the loop above. */ spello(SPELL_ANIMATE_DEAD, "animate dead", 35, 10, 3, POS_STANDING, - TAR_OBJ_ROOM, FALSE, MAG_SUMMONS, NULL); + 3, 3, TAR_OBJ_ROOM, FALSE, MAG_SUMMONS, NULL); spello(SPELL_ARMOR, "armor", 30, 15, 3, POS_FIGHTING, - TAR_CHAR_ROOM, FALSE, MAG_AFFECTS, "You feel less protected."); + 1, 1, TAR_CHAR_ROOM, FALSE, MAG_AFFECTS, "You feel less protected."); spello(SPELL_BLESS, "bless", 35, 5, 3, POS_STANDING, - TAR_CHAR_ROOM | TAR_OBJ_INV, FALSE, MAG_AFFECTS | MAG_ALTER_OBJS, + 2, 3, TAR_CHAR_ROOM | TAR_OBJ_INV, FALSE, MAG_AFFECTS | MAG_ALTER_OBJS, "You feel less righteous."); spello(SPELL_BLINDNESS, "blindness", 35, 25, 1, POS_STANDING, - TAR_CHAR_ROOM | TAR_NOT_SELF, FALSE, MAG_AFFECTS, + 2, 10, TAR_CHAR_ROOM | TAR_NOT_SELF, FALSE, MAG_AFFECTS, "You feel a cloak of blindness dissolve."); spello(SPELL_BURNING_HANDS, "burning hands", 30, 10, 3, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); + 2, 3, TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); spello(SPELL_CALL_LIGHTNING, "call lightning", 40, 25, 3, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); + 3, 3, TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); spello(SPELL_CHARM, "charm person", 75, 50, 2, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_NOT_SELF, TRUE, MAG_MANUAL, + 6, 2, TAR_CHAR_ROOM | TAR_NOT_SELF, TRUE, MAG_MANUAL, "You feel more self-confident."); spello(SPELL_CHILL_TOUCH, "chill touch", 30, 10, 3, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE | MAG_AFFECTS, + 2, 1, TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE | MAG_AFFECTS, "You feel your strength return."); spello(SPELL_CLONE, "clone", 80, 65, 5, POS_STANDING, - TAR_IGNORE, FALSE, MAG_SUMMONS, NULL); + 8, 3, TAR_IGNORE, FALSE, MAG_SUMMONS, NULL); spello(SPELL_COLOR_SPRAY, "color spray", 30, 15, 3, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); + 5, 3, TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); spello(SPELL_CONTROL_WEATHER, "control weather", 75, 25, 5, POS_STANDING, - TAR_IGNORE, FALSE, MAG_MANUAL, NULL); + 2, 2, TAR_IGNORE, FALSE, MAG_MANUAL, NULL); spello(SPELL_CREATE_FOOD, "create food", 30, 5, 4, POS_STANDING, - TAR_IGNORE, FALSE, MAG_CREATIONS, NULL); + 1, 1, TAR_IGNORE, FALSE, MAG_CREATIONS, NULL); spello(SPELL_CREATE_WATER, "create water", 30, 5, 4, POS_STANDING, - TAR_OBJ_INV | TAR_OBJ_EQUIP, FALSE, MAG_MANUAL, NULL); + 1, 1, TAR_OBJ_INV | TAR_OBJ_EQUIP, FALSE, MAG_MANUAL, NULL); spello(SPELL_CURE_BLIND, "cure blind", 30, 5, 2, POS_STANDING, - TAR_CHAR_ROOM, FALSE, MAG_UNAFFECTS, NULL); + 2, 1, TAR_CHAR_ROOM, FALSE, MAG_UNAFFECTS, NULL); spello(SPELL_CURE_CRITIC, "cure critic", 30, 10, 2, POS_FIGHTING, - TAR_CHAR_ROOM, FALSE, MAG_POINTS, NULL); + 4, 3, TAR_CHAR_ROOM, FALSE, MAG_POINTS, NULL); spello(SPELL_CURE_LIGHT, "cure light", 30, 10, 2, POS_FIGHTING, - TAR_CHAR_ROOM, FALSE, MAG_POINTS, NULL); + 1, 1, TAR_CHAR_ROOM, FALSE, MAG_POINTS, NULL); spello(SPELL_CURSE, "curse", 80, 50, 2, POS_STANDING, - TAR_CHAR_ROOM | TAR_OBJ_INV, TRUE, MAG_AFFECTS | MAG_ALTER_OBJS, + 2, 2, TAR_CHAR_ROOM | TAR_OBJ_INV, TRUE, MAG_AFFECTS | MAG_ALTER_OBJS, "You feel more optimistic."); spello(SPELL_DARKNESS, "darkness", 30, 5, 4, POS_STANDING, - TAR_IGNORE, FALSE, MAG_ROOMS, NULL); + 4, 2, TAR_IGNORE, FALSE, MAG_ROOMS, NULL); spello(SPELL_DETECT_ALIGN, "detect alignment", 20, 10, 2, POS_STANDING, - TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, "You feel less aware."); + 1, 1, TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, "You feel less aware."); spello(SPELL_DETECT_INVIS, "detect invisibility", 20, 10, 2, POS_STANDING, - TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, + 2, 2, TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, "Your eyes stop tingling."); spello(SPELL_DETECT_MAGIC, "detect magic", 20, 10, 2, POS_STANDING, - TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, + 1, 1, TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, "The detect magic wears off."); spello(SPELL_DETECT_POISON, "detect poison", 15, 5, 1, POS_STANDING, - TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, MAG_MANUAL, + 2, 1, TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, MAG_MANUAL, "The detect poison wears off."); spello(SPELL_DISPEL_EVIL, "dispel evil", 40, 25, 3, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); + 4, 2, TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); spello(SPELL_DISPEL_GOOD, "dispel good", 40, 25, 3, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); + 4, 2, TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); spello(SPELL_EARTHQUAKE, "earthquake", 40, 25, 3, POS_FIGHTING, - TAR_IGNORE, TRUE, MAG_AREAS, NULL); + 5, 2, TAR_IGNORE, TRUE, MAG_AREAS, NULL); spello(SPELL_ENCHANT_WEAPON, "enchant weapon", 150, 100, 10, POS_STANDING, - TAR_OBJ_INV, FALSE, MAG_MANUAL, NULL); + 6, 2, TAR_OBJ_INV, FALSE, MAG_MANUAL, NULL); spello(SPELL_ENERGY_DRAIN, "energy drain", 40, 25, 1, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE | MAG_MANUAL, NULL); + 5, 2, TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE | MAG_MANUAL, NULL); spello(SPELL_GROUP_ARMOR, "group armor", 50, 30, 2, POS_STANDING, - TAR_IGNORE, FALSE, MAG_GROUPS, NULL); + 5, 7, TAR_IGNORE, FALSE, MAG_GROUPS, NULL); spello(SPELL_FIREBALL, "fireball", 40, 30, 2, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); + 6, 5, TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); spello(SPELL_FLY, "fly", 40, 20, 2, POS_FIGHTING, - TAR_CHAR_ROOM, FALSE, MAG_AFFECTS, "You drift slowly to the ground."); + 6, 4, TAR_CHAR_ROOM, FALSE, MAG_AFFECTS, "You drift slowly to the ground."); spello(SPELL_GROUP_HEAL, "group heal", 80, 60, 5, POS_STANDING, - TAR_IGNORE, FALSE, MAG_GROUPS, NULL); + 7, 5, TAR_IGNORE, FALSE, MAG_GROUPS, NULL); spello(SPELL_HARM, "harm", 75, 45, 3, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); + 5, 4, TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); spello(SPELL_HEAL, "heal", 60, 40, 3, POS_FIGHTING, - TAR_CHAR_ROOM, FALSE, MAG_POINTS | MAG_UNAFFECTS, NULL); + 7, 5, TAR_CHAR_ROOM, FALSE, MAG_POINTS | MAG_UNAFFECTS, NULL); spello(SPELL_INFRAVISION, "infravision", 25, 10, 1, POS_STANDING, - TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, + 1, 2, TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, "Your night vision seems to fade."); spello(SPELL_INVISIBLE, "invisibility", 35, 25, 1, POS_STANDING, - TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, + 3, 2, TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, MAG_AFFECTS | MAG_ALTER_OBJS, "You feel yourself exposed."); spello(SPELL_LIGHTNING_BOLT, "lightning bolt", 30, 15, 1, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); + 4, 3, TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); spello(SPELL_LOCATE_OBJECT, "locate object", 25, 20, 1, POS_STANDING, - TAR_OBJ_WORLD, FALSE, MAG_MANUAL, NULL); + 5, 4, TAR_OBJ_WORLD, FALSE, MAG_MANUAL, NULL); spello(SPELL_MAGIC_MISSILE, "magic missile", 25, 10, 3, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); + 1, 2, TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); spello(SPELL_POISON, "poison", 50, 20, 3, POS_STANDING, - TAR_CHAR_ROOM | TAR_NOT_SELF | TAR_OBJ_INV, TRUE, + 3, 3, TAR_CHAR_ROOM | TAR_NOT_SELF | TAR_OBJ_INV, TRUE, MAG_AFFECTS | MAG_ALTER_OBJS, "You feel less sick."); spello(SPELL_PROT_FROM_EVIL, "protection from evil", 40, 10, 3, POS_STANDING, - TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, + 3, 3, TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, "You feel less protected."); spello(SPELL_REMOVE_CURSE, "remove curse", 45, 25, 5, POS_STANDING, - TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_EQUIP, FALSE, + 3, 3, TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_EQUIP, FALSE, MAG_UNAFFECTS | MAG_ALTER_OBJS, NULL); spello(SPELL_REMOVE_POISON, "remove poison", 40, 8, 4, POS_STANDING, - TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, + 3, 3, TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, MAG_UNAFFECTS | MAG_ALTER_OBJS, NULL); spello(SPELL_SANCTUARY, "sanctuary", 110, 85, 5, POS_STANDING, - TAR_CHAR_ROOM, FALSE, MAG_AFFECTS, "The white aura around your body fades."); + 6, 4, TAR_CHAR_ROOM, FALSE, MAG_AFFECTS, "The white aura around your body fades."); spello(SPELL_SENSE_LIFE, "sense life", 20, 10, 2, POS_STANDING, - TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, + 3, 3, TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, "You feel less aware of your surroundings."); spello(SPELL_SHOCKING_GRASP, "shocking grasp", 30, 15, 3, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); + 3, 2, TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); spello(SPELL_SLEEP, "sleep", 40, 25, 5, POS_STANDING, - TAR_CHAR_ROOM, TRUE, MAG_AFFECTS, "You feel less tired."); + 3, 4, TAR_CHAR_ROOM, TRUE, MAG_AFFECTS, "You feel less tired."); spello(SPELL_STRENGTH, "strength", 35, 30, 1, POS_STANDING, - TAR_CHAR_ROOM, FALSE, MAG_AFFECTS, "You feel weaker."); + 4, 3, TAR_CHAR_ROOM, FALSE, MAG_AFFECTS, "You feel weaker."); spello(SPELL_SUMMON, "summon", 75, 50, 3, POS_STANDING, - TAR_CHAR_WORLD | TAR_NOT_SELF, FALSE, MAG_MANUAL, NULL); + 4, 4, TAR_CHAR_WORLD | TAR_NOT_SELF, FALSE, MAG_MANUAL, NULL); spello(SPELL_TELEPORT, "teleport", 75, 50, 3, POS_STANDING, - TAR_CHAR_ROOM, FALSE, MAG_MANUAL, NULL); + 5, 2, TAR_CHAR_ROOM, FALSE, MAG_MANUAL, NULL); spello(SPELL_WATERWALK, "waterwalk", 40, 20, 2, POS_STANDING, - TAR_CHAR_ROOM, FALSE, MAG_AFFECTS, "Your feet seem less buoyant."); + 3, 3, TAR_CHAR_ROOM, FALSE, MAG_AFFECTS, "Your feet seem less buoyant."); spello(SPELL_WORD_OF_RECALL, "word of recall", 20, 10, 2, POS_FIGHTING, - TAR_CHAR_ROOM, FALSE, MAG_MANUAL, NULL); + 3, 3, TAR_CHAR_ROOM, FALSE, MAG_MANUAL, NULL); spello(SPELL_IDENTIFY, "identify", 50, 25, 5, POS_STANDING, - TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, MAG_MANUAL, NULL); + 4, 3, TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, MAG_MANUAL, NULL); /* NON-castable spells should appear below here. */ spello(SPELL_IDENTIFY, "identify", 0, 0, 0, 0, - TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, MAG_MANUAL, NULL); + 0, 0, TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, MAG_MANUAL, NULL); /* you might want to name this one something more fitting to your theme -Welcor*/ spello(SPELL_DG_AFFECT, "Script-inflicted", 0, 0, 0, POS_SITTING, - TAR_IGNORE, TRUE, 0, NULL); + 0, 0, TAR_IGNORE, TRUE, 0, NULL); /* Declaration of skills - this actually doesn't do anything except set it up * so that immortals can use these skills by default. The min level to use * the skill for other classes is set up in class.c. */ - skillo(SKILL_BACKSTAB, "backstab"); - skillo(SKILL_BASH, "bash"); - skillo(SKILL_HIDE, "hide"); - skillo(SKILL_KICK, "kick"); - skillo(SKILL_PICK_LOCK, "pick lock"); - skillo(SKILL_RESCUE, "rescue"); - skillo(SKILL_SNEAK, "sneak"); - skillo(SKILL_STEAL, "steal"); - skillo(SKILL_TRACK, "track"); - skillo(SKILL_WHIRLWIND, "whirlwind"); - skillo(SKILL_BANDAGE, "bandage"); + skillo(SKILL_BACKSTAB, "backstab", 10); + skillo(SKILL_BASH, "bash", 4); + skillo(SKILL_HIDE, "hide", 5); + skillo(SKILL_KICK, "kick", 4); + skillo(SKILL_PICK_LOCK, "pick lock", 2); + skillo(SKILL_RESCUE, "rescue", 2); + skillo(SKILL_SNEAK, "sneak", 4); + skillo(SKILL_STEAL, "steal", 5); + skillo(SKILL_TRACK, "track", 1); + skillo(SKILL_WHIRLWIND, "whirlwind", 3); + skillo(SKILL_BANDAGE, "bandage", 2); } diff --git a/src/spells.h b/src/spells.h index 4bcb8ec..e7796e7 100644 --- a/src/spells.h +++ b/src/spells.h @@ -99,6 +99,8 @@ /* Insert new spells here, up to MAX_SPELLS */ #define MAX_SPELLS 130 +#define MAX_SONGS (MAX_SPELLS + 1) + /* PLAYER SKILLS - Numbered from MAX_SPELLS+1 to MAX_SKILLS */ #define SKILL_BACKSTAB 131 /* Reserved Skill[] DO NOT CHANGE */ #define SKILL_BASH 132 /* Reserved Skill[] DO NOT CHANGE */ @@ -186,7 +188,8 @@ struct spell_info_type { int mana_min; /* Min amount of mana used by a spell (highest lev) */ int mana_max; /* Max amount of mana used by a spell (lowest lev) */ int mana_change; /* Change in mana used by spell from lev to lev */ - + int spell_level; /* Spell level for memorization (lowest lev) */ + int cooldown; int min_level[NUM_CLASSES]; int routines; byte violent; diff --git a/src/structs.h b/src/structs.h index 08e47db..963c865 100644 --- a/src/structs.h +++ b/src/structs.h @@ -263,8 +263,9 @@ #define PRF_AUTOKEY 32 /**< Automatically unlock locked doors when opening */ #define PRF_AUTODOOR 33 /**< Use the next available door */ #define PRF_ZONERESETS 34 +#define PRF_AUTOMEM 35 /** Total number of available PRF flags */ -#define NUM_PRF_FLAGS 35 +#define NUM_PRF_FLAGS 36 /* Affect bits: used in char_data.char_specials.saved.affected_by */ /* WARNING: In the world files, NEVER set the bits marked "R" ("Reserved") */ @@ -454,8 +455,17 @@ #define APPLY_SAVING_PETRI 22 /**< Apply to save throw: petrif */ #define APPLY_SAVING_BREATH 23 /**< Apply to save throw: breath */ #define APPLY_SAVING_SPELL 24 /**< Apply to save throw: spells */ +#define APPLY_SPELL_LVL_0 25 +#define APPLY_SPELL_LVL_1 26 +#define APPLY_SPELL_LVL_2 27 +#define APPLY_SPELL_LVL_3 28 +#define APPLY_SPELL_LVL_4 29 +#define APPLY_SPELL_LVL_5 30 +#define APPLY_SPELL_LVL_6 31 +#define APPLY_SPELL_LVL_7 32 +#define APPLY_SPELL_LVL_8 33 /** Total number of applies */ -#define NUM_APPLIES 25 +#define NUM_APPLIES 34 /* Equals the total number of SAVING_* defines in spells.h */ #define NUM_OF_SAVING_THROWS 5 @@ -521,6 +531,32 @@ #define EF_ARRAY_MAX 4 /**< # Bytes in Bit vector - Obj Extra Flags */ #define ZN_ARRAY_MAX 4 /**< # Bytes in Bit vector - Zone Flags */ +enum memorization_spell_levels +{ + SPELL_LEVEL_0 = 0, + SPELL_LEVEL_1, + SPELL_LEVEL_2, + SPELL_LEVEL_3, + SPELL_LEVEL_4, + SPELL_LEVEL_5, + SPELL_LEVEL_6, + SPELL_LEVEL_7, + SPELL_LEVEL_8, + MAX_SPELL_LEVEL +}; + +#define MAX_SPELLS_PER_SPELL_SLOT 12 +#define MAX_MEM (MAX_SPELL_LEVEL * MAX_SPELLS_PER_SPELL_SLOT) /* how many total spells */ + +#define SLOT_TYPE_VERY_HIGH 0 +#define SLOT_TYPE_HIGH 1 +#define SLOT_TYPE_UPPER_MIDDLE 2 +#define SLOT_TYPE_MIDDLE 3 +#define SLOT_TYPE_LOWER_MIDDLE 4 +#define SLOT_TYPE_LOWER 5 +#define SLOT_TYPE_NO_CAST 6 +#define NUM_CASTER_CATEGORY 7 + /* other #defined constants */ /* **DO**NOT** blindly change the number of levels in your MUD merely by * changing these numbers and without changing the rest of the code to match. @@ -961,6 +997,7 @@ struct player_special_data_saved int quest_counter; /**< Count of targets left to get */ time_t lastmotd; /**< Last time player read motd */ time_t lastnews; /**< Last time player read news */ + int spellmem[MAX_MEM]; /* for spell memorization */ }; /** Specials needed only by PCs, not NPCs. Space for this structure is @@ -978,6 +1015,8 @@ struct player_special_data int last_olc_mode; /**< ? Currently Unused ? */ char *host; /**< Resolved hostname, or ip, for player. */ int buildwalk_sector; /**< Default sector type for buildwalk */ + int spell_level[MAX_SPELL_LEVEL]; /* bonus to number of spells memorized */ + int memcursor; /* points to the next free slot in spellmem */ }; /** Special data used by NPCs, not PCs */ @@ -1002,6 +1041,21 @@ struct affected_type struct affected_type *next; /**< The next affect in the list of affects. */ }; +/* this can be used for skills that can be used per-day */ +struct memorize_node { + int timer; /* how many ticks left till memorized (standing) */ + int spell; /* the spell number */ + + struct memorize_node *next; /* link to the next node */ +}; + +struct cooldown_node { + int timer; + int spellnum; + + struct cooldown_node *next; +}; + /** The list element that makes up a list of characters following this * character. */ struct follow_type @@ -1048,8 +1102,11 @@ struct char_data struct group_data *group; /**< Character's Group */ long pref; /**< unique session id */ - + struct list_data * events; + + struct memorize_node *memorized; + struct cooldown_node *cooldown; }; /** descriptor-related structures */ @@ -1216,6 +1273,7 @@ struct wis_app_type struct int_app_type { byte learn; /**< how many % a player learns a spell/skill */ + sh_int memspeed; }; /** Describes the bonuses applied for a specific value of a diff --git a/src/utils.h b/src/utils.h index d02cd2b..1bc7128 100644 --- a/src/utils.h +++ b/src/utils.h @@ -619,6 +619,13 @@ do \ /** Copy the current skill level i of ch to pct. */ #define SET_SKILL(ch, i, pct) do { CHECK_PLAYER_SPECIAL((ch), (ch)->player_specials->saved.skills[i]) = pct; } while(0) +/* Memorization */ +#define GET_SPELLMEM(ch, i) ((ch->player_specials->saved.spellmem[i])) +#define GET_MEMCURSOR(ch) ((ch->player_specials->memcursor)) +/* returns the number of spells per slot */ +#define GET_SPELL_LEVEL(ch, i) ((ch)->player_specials->spell_level[i]) +#define IS_MANA_USER(ch) (GET_CLASS(ch) == CLASS_MAGIC_USER) ? TRUE : FALSE + /** The player's default sector type when buildwalking */ #define GET_BUILDWALK_SECTOR(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->buildwalk_sector))