Crossfire Server, Trunk
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(object *potion, object *applier, int aflags);
29 
33 void init_type_potion(void) {
35 }
36 
44 static method_ret potion_type_apply(object *potion, object *applier, int aflags) {
45  int got_one = 0, i;
46  object *force;
47  (void)aflags;
48 
49  if (applier->type == PLAYER) {
50  if (!QUERY_FLAG(potion, FLAG_IDENTIFIED))
51  potion = identify(potion);
52  }
53 
54  play_sound_map(SOUND_TYPE_ITEM, applier, 0, "drink");
55  apply_handle_yield(potion);
56 
57  /* Potion of restoration - only for players */
58  if (applier->type == PLAYER && (potion->attacktype&AT_DEPLETE)) {
59  if (QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED)) {
60  drain_stat(applier);
61  fix_object(applier);
63  return METHOD_OK;
64  }
65 
66  if (remove_depletion(applier, potion->level) == 0)
68  "Your potion had no effect.");
69 
71  return METHOD_OK;
72  }
73 
74  /* improvement potion - only for players */
75  if (applier->type == PLAYER && potion->attacktype&AT_GODPOWER) {
76  for (i = 1; i < MIN(11, applier->level); i++) {
77  if (QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED)) {
78  if (applier->contr->levhp[i] != 1) {
79  applier->contr->levhp[i] = 1;
80  break;
81  }
82  if (applier->contr->levsp[i] != 1) {
83  applier->contr->levsp[i] = 1;
84  break;
85  }
86  if (applier->contr->levgrace[i] != 1) {
87  applier->contr->levgrace[i] = 1;
88  break;
89  }
90  } else {
91  if (applier->contr->levhp[i] < 9) {
92  applier->contr->levhp[i] = 9;
93  break;
94  }
95  if (applier->contr->levsp[i] < 6) {
96  applier->contr->levsp[i] = 6;
97  break;
98  }
99  if (applier->contr->levgrace[i] < 3) {
100  applier->contr->levgrace[i] = 3;
101  break;
102  }
103  }
104  }
105  /* Just makes checking easier */
106  if (i < MIN(11, applier->level))
107  got_one = 1;
108  if (!QUERY_FLAG(potion, FLAG_CURSED) && !QUERY_FLAG(potion, FLAG_DAMNED)) {
109  if (got_one) {
110  fix_object(applier);
112  "The Gods smile upon you and remake you a little more in their image. "
113  "You feel a little more perfect.");
114  } else
116  "The potion had no effect - you are already perfect");
117  } else { /* cursed potion */
118  if (got_one) {
119  fix_object(applier);
121  "The Gods are angry and punish you.");
122  } else
124  "You are fortunate that you are so pathetic.");
125  }
127  return METHOD_OK;
128  }
129 
130  /* A potion that casts a spell. Healing, restore spellpoint
131  * (power potion) and heroism all fit into this category.
132  * Given the spell object code, there is no limit to the number
133  * of spells that potions can be cast, but direction is
134  * problematic to try and imbue fireball potions for example.
135  */
136  if (potion->inv) {
137  if (QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED)) {
138  object *fball;
139 
141  "Yech! Your lungs are on fire!");
142  /* Explodes a fireball centered at player */
144  fball->dam_modifier = random_roll(1, applier->level, applier, PREFER_LOW)/5+1;
145  fball->stats.maxhp = random_roll(1, applier->level, applier, PREFER_LOW)/10+2;
146  object_insert_in_map_at(fball, applier->map, NULL, 0, applier->x, applier->y);
147  } else
148  cast_spell(applier, potion, applier->facing, potion->inv, NULL);
149 
151  /* if youre dead, no point in doing this... */
152  if (!QUERY_FLAG(applier, FLAG_REMOVED))
153  fix_object(applier);
154  return METHOD_OK;
155  }
156 
157  /* Deal with protection potions */
158  force = NULL;
159  for (i = 0; i < NROFATTACKS; i++) {
160  if (potion->resist[i]) {
161  if (!force)
163  memcpy(force->resist, potion->resist, sizeof(potion->resist));
164  force->type = POTION_RESIST_EFFECT;
165  force->speed = MOVE_PER_SECOND;
166  force->duration = 60;
167  break; /* Only need to find one protection since we cappliery entire batch */
168  }
169  }
170  /* This is a protection potion */
171  if (force) {
172  char name[MAX_BUF];
173  int resist = i;
174 
175  /* cursed items last longer */
176  if (QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED)) {
177  draw_ext_info_format(NDI_RED|NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_CURSED, "The %s was cursed!", potion->name);
178  force->duration *= 10;
179  for (i = 0; i < NROFATTACKS; i++)
180  if (force->resist[i] > 0)
181  force->resist[i] = -force->resist[i]; /* prot => vuln */
182  }
183  force->speed_left = -1;
184  /* set name for expiry messages */
185  snprintf(name, MAX_BUF, "resistance to %s", change_resist_msg[resist]);
186  free_string(force->name);
187  force->name = add_string(name);
189  force = object_insert_in_ob(force, applier);
190  CLEAR_FLAG(potion, FLAG_APPLIED);
192  change_abil(applier, force);
194 
195  if (potion->other_arch != NULL && applier->map != NULL) {
196  object_insert_in_map_at(arch_to_object(potion->other_arch), applier->map, NULL, INS_ON_TOP, applier->x, applier->y);
197  }
198 
199  return METHOD_OK;
200  }
201 
202  /* Only thing left are the stat potions */
203  if (applier->type == PLAYER) { /* only for players */
204  if ((QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED))
205  && potion->value != 0)
206  CLEAR_FLAG(potion, FLAG_APPLIED);
207  else
208  SET_FLAG(potion, FLAG_APPLIED);
209  if (!change_abil(applier, potion))
211  "Nothing happened.");
212  }
213 
214  /* CLEAR_FLAG is so that if the character has other potions
215  * that were grouped with the one consumed, his
216  * stat will not be raised by them. fix_object just clears
217  * up all the stats.
218  */
219  CLEAR_FLAG(potion, FLAG_APPLIED);
220  fix_object(applier);
222  return METHOD_OK;
223 }
PLAYER
@ PLAYER
Definition: object.h:107
global.h
SOUND_TYPE_ITEM
#define SOUND_TYPE_ITEM
Definition: newclient.h:335
add_string
sstring add_string(const char *str)
Definition: shstr.c:124
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
obj::map
struct mapdef * map
Definition: object.h:300
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
obj::value
int32_t value
Definition: object.h:355
cast_spell
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Definition: spell_util.c:1420
liv::maxhp
int16_t maxhp
Definition: living.h:41
METHOD_OK
#define METHOD_OK
Definition: ob_methods.h:15
PREFER_LOW
#define PREFER_LOW
Definition: define.h:564
MSG_TYPE_APPLY_CURSED
#define MSG_TYPE_APPLY_CURSED
Definition: newclient.h:605
MIN
#define MIN(x, y)
Definition: compat.h:21
play_sound_map
void play_sound_map(int8_t sound_type, object *emitter, int dir, const char *action)
Definition: sounds.c:113
NDI_RED
#define NDI_RED
Definition: newclient.h:245
POTION_RESIST_EFFECT
@ POTION_RESIST_EFFECT
Definition: object.h:225
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
pl::levsp
int8_t levsp[11]
Definition: player.h:186
store_spell_expiry
void store_spell_expiry(object *spell)
Definition: spell_util.c:1977
identify
object * identify(object *op)
Definition: item.c:1409
free_string
void free_string(sstring str)
Definition: shstr.c:280
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
obj::name
sstring name
Definition: object.h:314
MSG_TYPE_APPLY_SUCCESS
#define MSG_TYPE_APPLY_SUCCESS
Definition: newclient.h:603
POTION
@ POTION
Definition: object.h:111
EXPLODING_FIREBALL
#define EXPLODING_FIREBALL
Definition: spells.h:174
remove_depletion
int remove_depletion(object *op, int level)
Definition: living.c:756
obj::x
int16_t x
Definition: object.h:330
FLAG_DAMNED
#define FLAG_DAMNED
Definition: define.h:317
fix_object
void fix_object(object *op)
Definition: living.c:1126
pl::levgrace
int8_t levgrace[11]
Definition: player.h:187
obj::other_arch
struct archt * other_arch
Definition: object.h:418
potion_type_apply
static method_ret potion_type_apply(object *potion, object *applier, int aflags)
Definition: potion.c:44
sproto.h
init_type_potion
void init_type_potion(void)
Definition: potion.c:33
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
MAX_BUF
#define MAX_BUF
Definition: define.h:35
INS_ON_TOP
#define INS_ON_TOP
Definition: object.h:569
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:281
pl::levhp
int8_t levhp[11]
Definition: player.h:185
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.c:42
obj::y
int16_t y
Definition: object.h:330
register_apply
void register_apply(int ob_type, apply_func method)
Definition: ob_types.c:62
method_ret
char method_ret
Definition: ob_methods.h:14
ob_types.h
sounds.h
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
obj::type
uint8_t type
Definition: object.h:343
change_resist_msg
const EXTERN char *const change_resist_msg[NROFATTACKS]
Definition: attack.h:135
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
apply_handle_yield
void apply_handle_yield(object *tmp)
Definition: apply.c:122
obj::stats
living stats
Definition: object.h:373
obj::contr
struct pl * contr
Definition: object.h:279
obj::facing
int8_t facing
Definition: object.h:340
AT_DEPLETE
#define AT_DEPLETE
Definition: attack.h:92
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2833
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:232
MSG_TYPE_APPLY_FAILURE
#define MSG_TYPE_APPLY_FAILURE
Definition: newclient.h:604
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:2080
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:309
AT_GODPOWER
#define AT_GODPOWER
Definition: attack.h:96
ob_methods.h
obj::attacktype
uint32_t attacktype
Definition: object.h:347
drain_stat
void drain_stat(object *op)
Definition: living.c:717
change_abil
int change_abil(object *op, object *tmp)
Definition: living.c:395
MSG_TYPE_APPLY
#define MSG_TYPE_APPLY
Definition: newclient.h:408
FLAG_CURSED
#define FLAG_CURSED
Definition: define.h:316
MOVE_PER_SECOND
static const float MOVE_PER_SECOND
Definition: tod.h:54
obj::resist
int16_t resist[NROFATTACKS]
Definition: object.h:346
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:319
obj::level
int16_t level
Definition: object.h:356
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
obj::inv
struct obj * inv
Definition: object.h:293
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Definition: define.h:261
give.name
name
Definition: give.py:27
obj::dam_modifier
uint8_t dam_modifier
Definition: object.h:412
dragon_attune.force
force
Definition: dragon_attune.py:45