Crossfire Server, Branches 1.12  R18729
spellbook.c
Go to the documentation of this file.
1 /*
2  CrossFire, A Multiplayer game for X-windows
3 
4  Copyright (C) 2007 Crossfire Development Team
5  Copyright (C) 1992 Frank Tore Johansen
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21  The authors can be reached via e-mail at crossfire-devel@real-time.com
22 */
23 
28 #include <global.h>
29 #include <ob_methods.h>
30 #include <ob_types.h>
31 #include <sounds.h>
32 #include <sproto.h>
33 
34 static method_ret spellbook_type_apply(ob_methods *context, object *lighter, object *applier, int aflags);
35 
39 void init_type_spellbook(void) {
41 }
42 
64 static method_ret spellbook_type_apply(ob_methods *context, object *book, object *applier, int aflags) {
65  object *skapplier, *spell, *spell_skill;
66  int read_level;
67  char level[100];
68 
69  /* Must be applied by a player. */
70  if (applier->type == PLAYER) {
71  if (QUERY_FLAG(applier, FLAG_BLIND)&&!QUERY_FLAG(applier, FLAG_WIZ)) {
73  "You are unable to read while blind.", NULL);
74  return METHOD_OK;
75  }
76 
77  skapplier = find_skill_by_name(applier, book->skill);
78 
79  /* need a literacy skill to learn spells. Also, having a literacy level
80  * lower than the spell will make learning the spell more difficult */
81  if (!skapplier) {
83  "You can't read! Your attempt fails.", NULL);
84  return METHOD_OK;
85  }
86  read_level = skapplier->level;
87 
88  spell = book->inv;
89  if (!spell) {
90  LOG(llevError, "apply_spellbook: Book %s has no spell in it!\n", book->name);
92  "The spellbook symbols make no sense.", NULL);
93  return METHOD_OK;
94  }
95 
96  if (QUERY_FLAG(book, FLAG_CURSED) || QUERY_FLAG(book, FLAG_DAMNED)) {
97  char name[MAX_BUF];
98  /* Player made a mistake, let's shake her/him :) */
99  int failure = -35;
100 
102  failure = -rndm(35, 100);
103  query_name(book, name, MAX_BUF);
105  "The %s was %s!",
106  "The %s was %s!",
107  name, QUERY_FLAG(book, FLAG_DAMNED) ? "damned" : "cursed");
108  scroll_failure(applier, failure, (spell->level+4)*7);
109  if (QUERY_FLAG(book, FLAG_DAMNED)
110  && check_spell_known(applier, spell->name)
111  && die_roll(1, 10, applier, 1) < 2)
112  /* Really unlucky player, better luck next time */
113  do_forget_spell(applier, spell->name);
114  book = decrease_ob(book);
115  if (book && (!QUERY_FLAG(book, FLAG_IDENTIFIED))) {
116  /* Well, not everything is lost, player now knows the
117  * book is cursed/damned. */
118  identify(book);
119  if (book->env)
120  esrv_update_item(UPD_FLAGS|UPD_NAME, applier, book);
121  else
122  applier->contr->socket.update_look = 1;
123  }
124  return METHOD_OK;
125  }
126 
127  if (QUERY_FLAG(book, FLAG_BLESSED))
128  read_level += 5;
129 
130  if (spell->level > (read_level+10)) {
132  "You are unable to decipher the strange symbols.", NULL);
133  return METHOD_OK;
134  }
135 
136  get_levelnumber(spell->level, level, sizeof(level));
138  "The spellbook contains the %s level spell %s.",
139  "The spellbook contains the %s level spell %s.",
140  level, spell->name);
141 
142  if (!QUERY_FLAG(book, FLAG_IDENTIFIED)) {
143  identify(book);
144  if (book->env)
145  esrv_update_item(UPD_FLAGS|UPD_NAME, applier, book);
146  else
147  applier->contr->socket.update_look = 1;
148  }
149 
150  /* I removed the check for special_prayer_mark here - it didn't make
151  * a lot of sense - special prayers are not found in spellbooks, and
152  * if the player doesn't know the spell, doesn't make a lot of sense
153  * that they would have a special prayer mark.
154  */
155  if (check_spell_known(applier, spell->name)) {
157  "You already know that spell.\n", NULL);
158  return METHOD_OK;
159  }
160 
161  if (spell->skill) {
162  spell_skill = find_skill_by_name(applier, spell->skill);
163  if (!spell_skill) {
164  draw_ext_info_format(NDI_UNIQUE, 0, applier,
166  "You lack the skill %s to use this spell",
167  "You lack the skill %s to use this spell",
168  spell->skill);
169  return METHOD_OK;
170  }
171  if (spell_skill->level < spell->level) {
172  draw_ext_info_format(NDI_UNIQUE, 0, applier,
174  "You need to be level %d in %s to learn this spell.",
175  "You need to be level %d in %s to learn this spell.",
176  spell->level, spell->skill);
177  return METHOD_OK;
178  }
179  }
180 
181  /* Logic as follows
182  *
183  * 1- MU spells use Int to learn, Cleric spells use Wisdom
184  *
185  * 2- The learner's skill level in literacy adjusts the chance
186  * to learn a spell.
187  *
188  * 3 -Automatically fail to learn if you read while confused
189  *
190  * Overall, chances are the same but a player will find having a high
191  * literacy rate very useful! -b.t.
192  */
193  if (QUERY_FLAG(applier, FLAG_CONFUSED)) {
195  "In your confused state you flub the wording of the text!", NULL);
196  scroll_failure(applier, 0-random_roll(0, spell->level, applier, PREFER_LOW), MAX(spell->stats.sp, spell->stats.grace));
197  } else if (QUERY_FLAG(book, FLAG_STARTEQUIP)
198  || (random_roll(0, 100, applier, PREFER_LOW)-(5*read_level)) < learn_spell[spell->stats.grace ? applier->stats.Wis : applier->stats.Int]) {
200  "You succeed in learning the spell!", NULL);
201  do_learn_spell(applier, spell, 0);
202 
203  /* xp gain to literacy for spell learning */
204  if (!QUERY_FLAG(book, FLAG_STARTEQUIP))
205  change_exp(applier, calc_skill_exp(applier, book, skapplier), skapplier->skill, 0);
206  } else {
207  play_sound_player_only(applier->contr, SOUND_TYPE_SPELL, book, 0, "fumble");
209  "You fail to learn the spell.\n", NULL);
210  }
211  decrease_ob(book);
212  }
213  return METHOD_OK;
214 }
#define UPD_FLAGS
Definition: newclient.h:255
sint8 Int
Definition: living.h:78
#define FLAG_DAMNED
Definition: define.h:614
void change_exp(object *op, sint64 exp, const char *skill_name, int flag)
Definition: living.c:2015
object * check_spell_known(object *op, const char *name)
Definition: spell_util.c:408
void do_forget_spell(object *op, const char *spell)
Definition: apply.c:440
#define MSG_TYPE_APPLY_FAILURE
Definition: newclient.h:519
void get_levelnumber(int i, char *buf, size_t size)
Definition: item.c:444
#define UPD_NAME
Definition: newclient.h:258
void esrv_update_item(int flags, object *pl, object *op)
Definition: standalone.c:200
socket_struct socket
Definition: player.h:148
#define PREFER_LOW
Definition: define.h:909
void draw_ext_info(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *message, const char *oldmessage)
Definition: standalone.c:171
#define FLAG_CONFUSED
Definition: define.h:608
sint16 sp
Definition: living.h:83
static method_ret spellbook_type_apply(ob_methods *context, object *lighter, object *applier, int aflags)
Definition: spellbook.c:64
void draw_ext_info_format(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *new_format, const char *old_format,...)
Definition: standalone.c:175
#define PLAYER
Definition: define.h:113
char method_ret
Definition: ob_methods.h:41
int rndm(int min, int max)
Definition: utils.c:174
uint8 spell_failure_effects
Definition: global.h:357
#define METHOD_OK
Definition: ob_methods.h:42
sint8 Wis
Definition: living.h:78
#define FLAG_IDENTIFIED
Definition: define.h:557
void identify(object *op)
Definition: item.c:1447
sint64 calc_skill_exp(object *who, object *op, object *skill)
Definition: skill_util.c:599
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.c:134
const char * name
Definition: object.h:167
struct obj * env
Definition: object.h:151
#define TRUE
Definition: exp.c:41
void do_learn_spell(object *op, object *spell, int special_prayer)
Definition: apply.c:398
void register_apply(int ob_type, apply_func method)
Definition: ob_types.c:79
struct pl * contr
Definition: object.h:134
#define MAX(x, y)
Definition: define.h:70
#define QUERY_FLAG(xyz, p)
Definition: define.h:514
#define MSG_TYPE_APPLY
Definition: newclient.h:330
#define FLAG_WIZ
Definition: define.h:527
#define MAX_BUF
Definition: define.h:81
const char * skill
Definition: object.h:174
#define FLAG_CURSED
Definition: define.h:613
#define decrease_ob(xyz)
Definition: global.h:276
#define MSG_TYPE_APPLY_SUCCESS
Definition: newclient.h:518
#define FLAG_BLIND
Definition: define.h:633
uint32 update_look
Definition: newserver.h:131
sint16 grace
Definition: living.h:85
living stats
Definition: object.h:219
struct Settings settings
Definition: init.c:48
void scroll_failure(object *op, int failure, int power)
Definition: apply.c:1708
#define MSG_TYPE_APPLY_ERROR
Definition: newclient.h:516
#define FLAG_STARTEQUIP
Definition: define.h:564
void play_sound_player_only(player *pl, sint8 sound_type, object *emitter, int dir, const char *action)
Definition: sounds.c:40
struct obj * inv
Definition: object.h:148
#define NDI_UNIQUE
Definition: newclient.h:219
#define SPELLBOOK
Definition: define.h:266
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
const int learn_spell[MAX_STAT+1]
Definition: living.c:154
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:628
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.c:51
#define FLAG_BLESSED
Definition: define.h:674
sint16 level
Definition: object.h:202
#define SOUND_TYPE_SPELL
Definition: sounds.h:36
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.c:207
uint8 type
Definition: object.h:189
void init_type_spellbook(void)
Definition: spellbook.c:39