Crossfire Server, Trunk  R22010
potion.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
19 #include "global.h"
20 
21 #include <string.h>
22 
23 #include "ob_methods.h"
24 #include "ob_types.h"
25 #include "sounds.h"
26 #include "sproto.h"
27 
28 static method_ret potion_type_apply(ob_methods *context, object *potion,
29  object *applier, int aflags);
30 
34 void init_type_potion(void) {
36 }
37 
46 static method_ret potion_type_apply(ob_methods *context, object *potion,
47  object *applier, int aflags) {
48  int got_one = 0, i;
49  object *force;
50 
51  if (applier->type == PLAYER) {
52  if (!QUERY_FLAG(potion, FLAG_IDENTIFIED))
53  potion = identify(potion);
54  }
55 
56  play_sound_map(SOUND_TYPE_ITEM, applier, 0, "drink");
57  apply_handle_yield(potion);
58 
59  /* Potion of restoration - only for players */
60  if (applier->type == PLAYER && (potion->attacktype&AT_DEPLETE)) {
61  if (QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED)) {
62  drain_stat(applier);
63  fix_object(applier);
65  return METHOD_OK;
66  }
67 
68  if (remove_depletion(applier, potion->level) == 0)
70  "Your potion had no effect.");
71 
73  return METHOD_OK;
74  }
75 
76  /* improvement potion - only for players */
77  if (applier->type == PLAYER && potion->attacktype&AT_GODPOWER) {
78  for (i = 1; i < MIN(11, applier->level); i++) {
79  if (QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED)) {
80  if (applier->contr->levhp[i] != 1) {
81  applier->contr->levhp[i] = 1;
82  break;
83  }
84  if (applier->contr->levsp[i] != 1) {
85  applier->contr->levsp[i] = 1;
86  break;
87  }
88  if (applier->contr->levgrace[i] != 1) {
89  applier->contr->levgrace[i] = 1;
90  break;
91  }
92  } else {
93  if (applier->contr->levhp[i] < 9) {
94  applier->contr->levhp[i] = 9;
95  break;
96  }
97  if (applier->contr->levsp[i] < 6) {
98  applier->contr->levsp[i] = 6;
99  break;
100  }
101  if (applier->contr->levgrace[i] < 3) {
102  applier->contr->levgrace[i] = 3;
103  break;
104  }
105  }
106  }
107  /* Just makes checking easier */
108  if (i < MIN(11, applier->level))
109  got_one = 1;
110  if (!QUERY_FLAG(potion, FLAG_CURSED) && !QUERY_FLAG(potion, FLAG_DAMNED)) {
111  if (got_one) {
112  fix_object(applier);
114  "The Gods smile upon you and remake you a little more in their image. "
115  "You feel a little more perfect.");
116  } else
118  "The potion had no effect - you are already perfect");
119  } else { /* cursed potion */
120  if (got_one) {
121  fix_object(applier);
123  "The Gods are angry and punish you.");
124  } else
126  "You are fortunate that you are so pathetic.");
127  }
129  return METHOD_OK;
130  }
131 
132  /* A potion that casts a spell. Healing, restore spellpoint
133  * (power potion) and heroism all fit into this category.
134  * Given the spell object code, there is no limit to the number
135  * of spells that potions can be cast, but direction is
136  * problematic to try and imbue fireball potions for example.
137  */
138  if (potion->inv) {
139  if (QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED)) {
140  object *fball;
141 
143  "Yech! Your lungs are on fire!");
144  /* Explodes a fireball centered at player */
146  fball->dam_modifier = random_roll(1, applier->level, applier, PREFER_LOW)/5+1;
147  fball->stats.maxhp = random_roll(1, applier->level, applier, PREFER_LOW)/10+2;
148  object_insert_in_map_at(fball, applier->map, NULL, 0, applier->x, applier->y);
149  } else
150  cast_spell(applier, potion, applier->facing, potion->inv, NULL);
151 
153  /* if youre dead, no point in doing this... */
154  if (!QUERY_FLAG(applier, FLAG_REMOVED))
155  fix_object(applier);
156  return METHOD_OK;
157  }
158 
159  /* Deal with protection potions */
160  force = NULL;
161  for (i = 0; i < NROFATTACKS; i++) {
162  if (potion->resist[i]) {
163  if (!force)
164  force = create_archetype(FORCE_NAME);
165  memcpy(force->resist, potion->resist, sizeof(potion->resist));
166  force->type = POTION_RESIST_EFFECT;
167  force->speed = MOVE_PER_SECOND;
168  force->duration = 60;
169  break; /* Only need to find one protection since we cappliery entire batch */
170  }
171  }
172  /* This is a protection potion */
173  if (force) {
174  char name[MAX_BUF];
175  int resist = i;
176 
177  /* cursed items last longer */
178  if (QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED)) {
179  draw_ext_info_format(NDI_RED|NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_CURSED, "The %s was cursed!", potion->name);
180  force->duration *= 10;
181  for (i = 0; i < NROFATTACKS; i++)
182  if (force->resist[i] > 0)
183  force->resist[i] = -force->resist[i]; /* prot => vuln */
184  }
185  force->speed_left = -1;
186  /* set name for expiry messages */
187  snprintf(name, MAX_BUF, "resistance to %s", change_resist_msg[resist]);
188  free_string(force->name);
189  force->name = add_string(name);
190  store_spell_expiry(force);
191  force = object_insert_in_ob(force, applier);
192  CLEAR_FLAG(potion, FLAG_APPLIED);
193  SET_FLAG(force, FLAG_APPLIED);
194  change_abil(applier, force);
196 
197  if (potion->other_arch != NULL && applier->map != NULL) {
198  object_insert_in_map_at(arch_to_object(potion->other_arch), applier->map, NULL, INS_ON_TOP, applier->x, applier->y);
199  }
200 
201  return METHOD_OK;
202  }
203 
204  /* Only thing left are the stat potions */
205  if (applier->type == PLAYER) { /* only for players */
206  if ((QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED))
207  && potion->value != 0)
208  CLEAR_FLAG(potion, FLAG_APPLIED);
209  else
210  SET_FLAG(potion, FLAG_APPLIED);
211  if (!change_abil(applier, potion))
213  "Nothing happened.");
214  }
215 
216  /* CLEAR_FLAG is so that if the character has other potions
217  * that were grouped with the one consumed, his
218  * stat will not be raised by them. fix_object just clears
219  * up all the stats.
220  */
221  CLEAR_FLAG(potion, FLAG_APPLIED);
222  fix_object(applier);
224  return METHOD_OK;
225 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:313
#define FLAG_DAMNED
Definition: define.h:318
void drain_stat(object *op)
Definition: living.c:717
#define AT_DEPLETE
Definition: attack.h:92
#define SET_FLAG(xyz, p)
Definition: define.h:223
#define MSG_TYPE_APPLY_FAILURE
Definition: newclient.h:599
void apply_handle_yield(object *tmp)
Definition: apply.c:122
static method_ret potion_type_apply(ob_methods *context, object *potion, object *applier, int aflags)
Definition: potion.c:46
#define EXPLODING_FIREBALL
Definition: spells.h:174
void free_string(sstring str)
Definition: shstr.c:280
#define PREFER_LOW
Definition: define.h:601
static const float MOVE_PER_SECOND
Definition: tod.h:50
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:308
#define MSG_TYPE_APPLY
Definition: newclient.h:384
#define MIN(x, y)
Definition: compat.h:17
#define FLAG_REMOVED
Definition: define.h:232
#define SOUND_TYPE_ITEM
Definition: newclient.h:310
char method_ret
Definition: ob_methods.h:14
int change_abil(object *op, object *tmp)
Definition: living.c:395
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:1849
#define NDI_RED
Definition: newclient.h:224
#define AT_GODPOWER
Definition: attack.h:96
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2602
object * arch_to_object(archetype *at)
Definition: arch.cpp:232
object * create_archetype(const char *name)
Definition: arch.cpp:281
#define METHOD_OK
Definition: ob_methods.h:15
#define snprintf
Definition: win32.h:46
#define FLAG_IDENTIFIED
Definition: define.h:261
EXTERN const char *const change_resist_msg[NROFATTACKS]
Definition: attack.h:135
void register_apply(int ob_type, apply_func method)
Definition: ob_types.c:62
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
#define MAX_BUF
Definition: define.h:35
#define FLAG_CURSED
Definition: define.h:317
void store_spell_expiry(object *spell)
Definition: spell_util.c:2017
const char * name
Definition: treasure.h:83
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:28
int remove_depletion(object *op, int level)
Definition: living.c:756
#define FLAG_APPLIED
Definition: define.h:235
#define NROFATTACKS
Definition: attack.h:17
#define MSG_TYPE_APPLY_SUCCESS
Definition: newclient.h:598
#define FORCE_NAME
Definition: spells.h:169
sstring add_string(const char *str)
Definition: shstr.c:124
object * identify(object *op)
Definition: item.c:1386
#define MSG_TYPE_APPLY_CURSED
Definition: newclient.h:600
#define NDI_UNIQUE
Definition: newclient.h:245
void play_sound_map(int8_t sound_type, object *emitter, int dir, const char *action)
Definition: sounds.c:107
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.c:42
void init_type_potion(void)
Definition: potion.c:34
void fix_object(object *op)
Definition: living.c:1124
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Definition: spell_util.c:1459