Crossfire Server, Branch 1.12  R12190
spellbook.c
Go to the documentation of this file.
00001 /*
00002     CrossFire, A Multiplayer game for X-windows
00003 
00004     Copyright (C) 2007 Crossfire Development Team
00005     Copyright (C) 1992 Frank Tore Johansen
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 
00021     The authors can be reached via e-mail at crossfire-devel@real-time.com
00022 */
00023 
00028 #include <global.h>
00029 #include <ob_methods.h>
00030 #include <ob_types.h>
00031 #include <sounds.h>
00032 #include <sproto.h>
00033 
00034 static method_ret spellbook_type_apply(ob_methods *context, object *lighter, object *applier, int aflags);
00035 
00039 void init_type_spellbook(void) {
00040     register_apply(SPELLBOOK, spellbook_type_apply);
00041 }
00042 
00064 static method_ret spellbook_type_apply(ob_methods *context, object *book, object *applier, int aflags) {
00065     object *skapplier, *spell, *spell_skill;
00066     int read_level;
00067     char level[100];
00068 
00069     /* Must be applied by a player. */
00070     if (applier->type == PLAYER) {
00071         if (QUERY_FLAG(applier, FLAG_BLIND)&&!QUERY_FLAG(applier, FLAG_WIZ)) {
00072             draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00073                 "You are unable to read while blind.", NULL);
00074             return METHOD_OK;
00075         }
00076 
00077         skapplier = find_skill_by_name(applier, book->skill);
00078 
00079         /* need a literacy skill to learn spells. Also, having a literacy level
00080          * lower than the spell will make learning the spell more difficult */
00081         if (!skapplier) {
00082             draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00083                 "You can't read! Your attempt fails.", NULL);
00084             return METHOD_OK;
00085         }
00086         read_level = skapplier->level;
00087 
00088         spell = book->inv;
00089         if (!spell) {
00090             LOG(llevError, "apply_spellbook: Book %s has no spell in it!\n", book->name);
00091             draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
00092                 "The spellbook symbols make no sense.", NULL);
00093             return METHOD_OK;
00094         }
00095 
00096         if (QUERY_FLAG(book, FLAG_CURSED) || QUERY_FLAG(book, FLAG_DAMNED)) {
00097             char name[MAX_BUF];
00098             /* Player made a mistake, let's shake her/him :) */
00099             int failure = -35;
00100 
00101             if (settings.spell_failure_effects == TRUE)
00102                 failure = -rndm(35, 100);
00103             query_name(book, name, MAX_BUF);
00104             draw_ext_info_format(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00105                 "The %s was %s!",
00106                 "The %s was %s!",
00107                 name, QUERY_FLAG(book, FLAG_DAMNED) ? "damned" : "cursed");
00108             scroll_failure(applier, failure, (spell->level+4)*7);
00109             if (QUERY_FLAG(book, FLAG_DAMNED)
00110             && check_spell_known(applier, spell->name)
00111             && die_roll(1, 10, applier, 1) < 2)
00112                 /* Really unlucky player, better luck next time */
00113                 do_forget_spell(applier, spell->name);
00114             book = decrease_ob(book);
00115             if (book && (!QUERY_FLAG(book, FLAG_IDENTIFIED))) {
00116                 /* Well, not everything is lost, player now knows the
00117                  * book is cursed/damned. */
00118                 identify(book);
00119                 if (book->env)
00120                     esrv_update_item(UPD_FLAGS|UPD_NAME, applier, book);
00121                 else
00122                     applier->contr->socket.update_look = 1;
00123             }
00124             return METHOD_OK;
00125         }
00126 
00127         if (QUERY_FLAG(book, FLAG_BLESSED))
00128             read_level += 5;
00129 
00130         if (spell->level > (read_level+10)) {
00131             draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
00132                 "You are unable to decipher the strange symbols.", NULL);
00133             return METHOD_OK;
00134         }
00135 
00136         get_levelnumber(spell->level, level, sizeof(level));
00137         draw_ext_info_format(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00138             "The spellbook contains the %s level spell %s.",
00139             "The spellbook contains the %s level spell %s.",
00140             level, spell->name);
00141 
00142         if (!QUERY_FLAG(book, FLAG_IDENTIFIED)) {
00143             identify(book);
00144             if (book->env)
00145                 esrv_update_item(UPD_FLAGS|UPD_NAME, applier, book);
00146             else
00147                 applier->contr->socket.update_look = 1;
00148         }
00149 
00150         /* I removed the check for special_prayer_mark here - it didn't make
00151          * a lot of sense - special prayers are not found in spellbooks, and
00152          * if the player doesn't know the spell, doesn't make a lot of sense
00153          * that they would have a special prayer mark.
00154          */
00155         if (check_spell_known(applier, spell->name)) {
00156             draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
00157                 "You already know that spell.\n", NULL);
00158             return METHOD_OK;
00159         }
00160 
00161         if (spell->skill) {
00162             spell_skill = find_skill_by_name(applier, spell->skill);
00163             if (!spell_skill) {
00164                 draw_ext_info_format(NDI_UNIQUE, 0, applier,
00165                     MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00166                     "You lack the skill %s to use this spell",
00167                     "You lack the skill %s to use this spell",
00168                     spell->skill);
00169                 return METHOD_OK;
00170             }
00171             if (spell_skill->level < spell->level) {
00172                 draw_ext_info_format(NDI_UNIQUE, 0, applier,
00173                     MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00174                     "You need to be level %d in %s to learn this spell.",
00175                     "You need to be level %d in %s to learn this spell.",
00176                     spell->level, spell->skill);
00177                 return METHOD_OK;
00178             }
00179         }
00180 
00181         /* Logic as follows
00182          *
00183          *  1- MU spells use Int to learn, Cleric spells use Wisdom
00184          *
00185          *  2- The learner's skill level in literacy adjusts the chance
00186          *        to learn a spell.
00187          *
00188          *  3 -Automatically fail to learn if you read while confused
00189          *
00190          * Overall, chances are the same but a player will find having a high
00191          * literacy rate very useful!  -b.t.
00192          */
00193         if (QUERY_FLAG(applier, FLAG_CONFUSED)) {
00194             draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
00195                 "In your confused state you flub the wording of the text!", NULL);
00196             scroll_failure(applier, 0-random_roll(0, spell->level, applier, PREFER_LOW), MAX(spell->stats.sp, spell->stats.grace));
00197         } else if (QUERY_FLAG(book, FLAG_STARTEQUIP)
00198         || (random_roll(0, 100, applier, PREFER_LOW)-(5*read_level)) < learn_spell[spell->stats.grace ? applier->stats.Wis : applier->stats.Int]) {
00199             draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00200                 "You succeed in learning the spell!", NULL);
00201             do_learn_spell(applier, spell, 0);
00202 
00203             /* xp gain to literacy for spell learning */
00204             if (!QUERY_FLAG(book, FLAG_STARTEQUIP))
00205                 change_exp(applier, calc_skill_exp(applier, book, skapplier), skapplier->skill, 0);
00206         } else {
00207             play_sound_player_only(applier->contr, SOUND_TYPE_SPELL, book, 0, "fumble");
00208             draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_FAILURE,
00209                 "You fail to learn the spell.\n", NULL);
00210         }
00211         decrease_ob(book);
00212     }
00213     return METHOD_OK;
00214 }