Atrinik Server  4.0
book_spell.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
32 #include <global.h>
33 #include <arch.h>
34 #include <player.h>
35 #include <object.h>
36 #include <object_methods.h>
37 
39 
43 #define BOOK_SPELL_CHANCE_CURSED 10
44 
48 #define BOOK_SPELL_CHANCE_DAMNED 2
49 
51 static int
52 apply_func (object *op, object *applier, int aflags)
53 {
54  HARD_ASSERT(op != NULL);
55  HARD_ASSERT(applier != NULL);
56 
57  /* Monsters cannot learn spells from spell books. */
58  if (applier->type != PLAYER) {
59  return OBJECT_METHOD_OK;
60  }
61 
62  if (op->stats.sp < 0 || op->stats.sp >= NROFREALSPELLS) {
63  LOG(ERROR, "Spell book with an invalid ID (%d): %s",
64  op->stats.sp, object_get_str(op));
65  char *name = object_get_name_s(op, applier);
66  draw_info_format(COLOR_WHITE, applier,
67  "The symbols in the %s make no sense.", name);
68  efree(name);
69  return OBJECT_METHOD_OK;
70  }
71 
72  if (QUERY_FLAG(applier, FLAG_BLIND)) {
73  draw_info(COLOR_WHITE, applier, "You are unable to read while blind.");
74  return OBJECT_METHOD_OK;
75  }
76 
77  player *pl = CONTR(applier);
78 
79  if (pl->skill_ptr[SK_LITERACY] == NULL) {
80  draw_info(COLOR_WHITE, applier,
81  "You are unable to decipher the strange symbols.");
82  return OBJECT_METHOD_OK;
83  }
84 
85  if (pl->skill_ptr[SK_WIZARDRY_SPELLS] == NULL) {
86  draw_info(COLOR_WHITE, applier,
87  "The arcane symbols have no meaning to you.");
88  return OBJECT_METHOD_OK;
89  }
90 
91  spell_struct *spell = &spells[op->stats.sp];
92 
93  if (QUERY_FLAG(op, FLAG_CURSED) || QUERY_FLAG(op, FLAG_DAMNED)) {
94  char *name = object_get_base_name_s(op, applier);
95  draw_info_format(COLOR_RED, applier, "The %s was %s!",
96  name,
97  QUERY_FLAG(op, FLAG_DAMNED) ? "damned" : "cursed");
98  efree(name);
99  spell_failure(applier, (spell->at->clone.level +
100  pl->skill_ptr[SK_WIZARDRY_SPELLS]->level) / 2);
101 
102  /* Damned spell book, small chance to forget the spell. */
103  if (QUERY_FLAG(op, FLAG_DAMNED) && rndm_chance(15)) {
104  object *tmp = player_find_spell(applier, spell);
105  if (tmp != NULL) {
106  draw_info_format(COLOR_RED, applier,
107  "The wild magic burns the spell %s out of "
108  "your mind!",
109  tmp->name);
110  object_remove(tmp, 0);
111  object_destroy(tmp);
112  }
113  }
114 
115  op = object_decrease(op, 1);
116  if (op != NULL && !QUERY_FLAG(op, FLAG_IDENTIFIED)) {
117  identify(op);
118  }
119 
120  return OBJECT_METHOD_OK;
121  }
122 
123  if (spell->at->clone.level > pl->skill_ptr[SK_LITERACY]->level + 15) {
124  draw_info(COLOR_WHITE, applier,
125  "Try as hard as you might, you can't quite make sense "
126  "out of the symbols...");
127  return OBJECT_METHOD_OK;
128  }
129 
130  if (!QUERY_FLAG(op, FLAG_IDENTIFIED)) {
131  identify(op);
132  draw_info_format(COLOR_WHITE, applier,
133  "The spellbook contains the spell %s.",
134  spell->at->clone.name);
135  }
136 
137  if (player_find_spell(applier, spell) != NULL) {
138  draw_info(COLOR_WHITE, applier, "You already know that spell.");
139  return OBJECT_METHOD_OK;
140  }
141 
142  if (spell->at->clone.level > pl->skill_ptr[SK_WIZARDRY_SPELLS]->level) {
143  draw_info_format(COLOR_WHITE, applier,
144  "You need to be level %d in %s to learn this spell.",
145  spell->at->clone.level,
147  return OBJECT_METHOD_OK;
148  }
149 
150  if (QUERY_FLAG(applier, FLAG_CONFUSED)) {
151  draw_info(COLOR_RED, applier,
152  "In your confused state you mix up the wording "
153  "of the spell!");
154  spell_failure(applier, (spell->at->clone.level +
155  pl->skill_ptr[SK_WIZARDRY_SPELLS]->level) / 2);
156  } else {
157  object *tmp = object_insert_into(arch_to_object(spell->at), applier, 0);
158  if (tmp == NULL) {
159  LOG(ERROR, "Failed to insert spell, op: %s, applier: %s",
160  object_get_str(op), object_get_str(applier));
161  return OBJECT_METHOD_OK;
162  }
163 
164  draw_info_format(COLOR_WHITE, applier, "You succeed in learning %s.",
165  spell->at->clone.name);
166  }
167 
168  object_decrease(op, 1);
169 
170  return OBJECT_METHOD_OK;
171 }
172 
174 static int
176  object **ret,
177  int difficulty,
178  treasure_affinity_t *affinity,
179  int flags)
180 {
181  HARD_ASSERT(op != NULL);
182  HARD_ASSERT(difficulty > 0);
183 
184  /* Avoid processing if the item is already special. */
185  if (process_treasure_is_special(op)) {
187  }
188 
189  op->stats.sp = spell_get_random(difficulty, SPELL_USE_BOOK);
190  if (op->stats.sp == SP_NO_SPELL) {
191  log_error("Failed to generate a spell for spell book: %s",
192  object_get_str(op));
193  object_remove(op, 0);
194  object_destroy(op);
195  return OBJECT_METHOD_ERROR;
196  }
197 
199 
200  if (!(flags & GT_ONLY_GOOD) && rndm_chance(BOOK_SPELL_CHANCE_CURSED)) {
201  if (rndm_chance(BOOK_SPELL_CHANCE_DAMNED)) {
202  SET_FLAG(op, FLAG_DAMNED);
203  } else {
204  SET_FLAG(op, FLAG_CURSED);
205  }
206  }
207 
208  return OBJECT_METHOD_OK;
209 }
210 
215 {
216  OBJECT_METHODS(BOOK_SPELL)->apply_func = apply_func;
217  OBJECT_METHODS(BOOK_SPELL)->process_treasure_func = process_treasure_func;
218  OBJECT_METHODS(BOOK_SPELL)->override_treasure_processing = true;
219 }
#define GT_ONLY_GOOD
Definition: treasure.h:63
void object_destroy(object *ob)
Definition: object.c:1441
#define BOOK_SPELL_CHANCE_DAMNED
Definition: book_spell.c:48
#define FLAG_CURSED
Definition: define.h:1154
void spell_failure(object *caster, int level)
Definition: spell_util.c:1178
void identify(object *op)
Definition: item.c:1364
OBJECT_TYPE_INIT_DEFINE(book_spell)
Definition: book_spell.c:214
#define NROFREALSPELLS
Definition: define.h:664
#define OBJECT_METHOD_ERROR
#define FLAG_BLIND
Definition: define.h:884
static int apply_func(object *op, object *applier, int aflags)
Definition: book_spell.c:52
#define PLAYER
Definition: define.h:122
int16_t sp
Definition: living.h:78
object * skill_ptr[NROFSKILLS]
Definition: player.h:194
#define QUERY_FLAG(xyz, p)
Definition: define.h:761
void object_remove(object *op, int flags)
Definition: object.c:1623
char * object_get_name_s(const object *op, const object *caller)
Definition: item.c:398
#define FLAG_DAMNED
Definition: define.h:1158
const char * object_get_str(const object *op)
Definition: object.c:3151
char * object_get_base_name_s(const object *op, const object *caller)
Definition: item.c:534
object * object_insert_into(object *op, object *where, int flag)
Definition: object.c:2158
#define SP_NO_SPELL
Definition: spells.h:202
const char * name
Definition: object.h:168
object * object_decrease(object *op, uint32_t i)
Definition: object.c:2105
#define SET_FLAG(xyz, p)
Definition: define.h:741
struct archetype * at
Definition: spells.h:198
object * arch_to_object(archetype_t *at)
Definition: arch.c:446
#define BOOK_SPELL
Definition: define.h:373
#define BOOK_SPELL_CHANCE_CURSED
Definition: book_spell.c:43
#define OBJECT_METHOD_UNHANDLED
spell_struct spells[NROFREALSPELLS]
Definition: spellist.h:34
bool process_treasure_is_special(object *op)
living stats
Definition: object.h:481
uint8_t type
Definition: object.h:360
#define OBJECT_METHODS(type)
int spell_get_random(int level, int flags)
Definition: spell_util.c:1230
static int process_treasure_func(object *op, object **ret, int difficulty, treasure_affinity_t *affinity, int flags)
Definition: book_spell.c:175
#define OBJECT_METHOD_OK
#define FLAG_IS_MAGICAL
Definition: define.h:1129
#define FLAG_CONFUSED
Definition: define.h:872
int8_t level
Definition: object.h:347
object clone
An object from which to do object_copy().
Definition: arch.h:47
#define FLAG_IDENTIFIED
Definition: define.h:980