Crossfire Server, Trunk  1.75.0
potion.cpp
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  if (cast_spell(applier, potion, applier->facing, potion->inv, NULL) == 0) {
149  // Failed to cast, so don't deduct a usage
150  return METHOD_OK;
151  }
152 
154  /* if youre dead, no point in doing this... */
155  if (!QUERY_FLAG(applier, FLAG_REMOVED))
156  fix_object(applier);
157  return METHOD_OK;
158  }
159 
160  /* Deal with protection potions */
161  force = NULL;
162  for (i = 0; i < NROFATTACKS; i++) {
163  if (potion->resist[i]) {
164  if (!force)
165  force = create_archetype(FORCE_NAME);
166  memcpy(force->resist, potion->resist, sizeof(potion->resist));
167  force->type = POTION_RESIST_EFFECT;
168  force->speed = MOVE_PER_SECOND;
169  force->duration = 60;
170  break; /* Only need to find one protection since we cappliery entire batch */
171  }
172  }
173  /* This is a protection potion */
174  if (force) {
175  char name[MAX_BUF];
176  int resist = i;
177 
178  /* cursed items last longer */
179  if (QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED)) {
180  draw_ext_info_format(NDI_RED|NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_CURSED, "The %s was cursed!", potion->name);
181  force->duration *= 10;
182  for (i = 0; i < NROFATTACKS; i++)
183  if (force->resist[i] > 0)
184  force->resist[i] = -force->resist[i]; /* prot => vuln */
185  }
186  force->speed_left = -1;
187  /* set name for expiry messages */
188  snprintf(name, MAX_BUF, "resistance to %s", change_resist_msg[resist]);
189  free_string(force->name);
190  force->name = add_string(name);
191  store_spell_expiry(force);
192  force = object_insert_in_ob(force, applier);
193  CLEAR_FLAG(potion, FLAG_APPLIED);
194  SET_FLAG(force, FLAG_APPLIED);
195  change_abil(applier, force);
197 
198  if (potion->other_arch != NULL && applier->map != NULL) {
199  object_insert_in_map_at(arch_to_object(potion->other_arch), applier->map, NULL, INS_ON_TOP, applier->x, applier->y);
200  }
201 
202  return METHOD_OK;
203  }
204 
205  /* Only thing left are the stat potions */
206  if (applier->type == PLAYER) { /* only for players */
207  if ((QUERY_FLAG(potion, FLAG_CURSED) || QUERY_FLAG(potion, FLAG_DAMNED))
208  && potion->value != 0)
209  CLEAR_FLAG(potion, FLAG_APPLIED);
210  else
211  SET_FLAG(potion, FLAG_APPLIED);
212  if (!change_abil(applier, potion))
214  "Nothing happened.");
215  }
216 
217  /* CLEAR_FLAG is so that if the character has other potions
218  * that were grouped with the one consumed, his
219  * stat will not be raised by them. fix_object just clears
220  * up all the stats.
221  */
222  CLEAR_FLAG(potion, FLAG_APPLIED);
223  fix_object(applier);
225  return METHOD_OK;
226 }
potion_type_apply
static method_ret potion_type_apply(object *potion, object *applier, int aflags)
Handles applying a potion, dust, balm, or figurine.
Definition: potion.cpp:44
PLAYER
@ PLAYER
Definition: object.h:112
global.h
SOUND_TYPE_ITEM
#define SOUND_TYPE_ITEM
Definition: newclient.h:339
living::maxhp
int16_t maxhp
Max hit points.
Definition: living.h:41
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:369
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:371
cast_spell
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Main dispatch when someone casts a spell.
Definition: spell_util.cpp:1424
register_apply
void register_apply(int ob_type, apply_func method)
Registers the apply method for the given type.
Definition: ob_types.cpp:62
object::speed
float speed
Frequency of object 'moves' relative to server tick rate.
Definition: object.h:337
METHOD_OK
#define METHOD_OK
Definition: ob_methods.h:15
object::x
int16_t x
Definition: object.h:335
object::speed_left
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
PREFER_LOW
#define PREFER_LOW
Definition: define.h:548
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
MSG_TYPE_APPLY_CURSED
#define MSG_TYPE_APPLY_CURSED
Applied a cursed object (BAD)
Definition: newclient.h:609
player::levhp
int8_t levhp[11]
What hp bonus the player gained on that level.
Definition: player.h:188
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,...) PRINTF_ARGS(6
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)
Plays a sound on a map.
Definition: sounds.cpp:113
player::levsp
int8_t levsp[11]
What sp bonus the player gained on that level.
Definition: player.h:189
fix_object
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.cpp:1132
NDI_RED
#define NDI_RED
Definition: newclient.h:249
POTION_RESIST_EFFECT
@ POTION_RESIST_EFFECT
A force, holding the effect of a resistance potion.
Definition: object.h:230
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:15
FLAG_CURSED
#define FLAG_CURSED
The object is cursed.
Definition: define.h:303
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2842
object::resist
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:351
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:219
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
store_spell_expiry
void store_spell_expiry(object *spell)
Stores in the spell when to warn player of expiration.
Definition: spell_util.cpp:1981
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
MSG_TYPE_APPLY_SUCCESS
#define MSG_TYPE_APPLY_SUCCESS
Was able to apply object.
Definition: newclient.h:607
POTION
@ POTION
Definition: object.h:116
EXPLODING_FIREBALL
#define EXPLODING_FIREBALL
This is used for fumbles - this arch is all set up to do the right just by inserting it.
Definition: spells.h:174
add_string
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
change_resist_msg
const char *const change_resist_msg[NROFATTACKS]
These are the descriptions of the resistances displayed when a player puts on/takes off an item.
Definition: init.cpp:70
object::value
int32_t value
How much money it is worth (or contains)
Definition: object.h:360
player::levgrace
int8_t levgrace[11]
What grace bonus the player gained on that level.
Definition: player.h:190
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
INS_ON_TOP
#define INS_ON_TOP
Always put object on top.
Definition: object.h:583
sproto.h
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.cpp:42
object::facing
int8_t facing
Object is oriented/facing that way.
Definition: object.h:345
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.cpp:2085
object::other_arch
struct archetype * other_arch
Pointer used for various things - mostly used for what this objects turns into or what this object cr...
Definition: object.h:425
AT_GODPOWER
#define AT_GODPOWER
Adds relevant god's attacktype (1048576) peterm@soda.berkeley.edu.
Definition: attack.h:98
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
create_archetype
object * create_archetype(const char *name)
Finds which archetype matches the given name, and returns a new object containing a copy of the arche...
Definition: arch.cpp:276
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:294
init_type_potion
void init_type_potion(void)
Initializer for the potion object type.
Definition: potion.cpp:33
FLAG_DAMNED
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:304
change_abil
int change_abil(object *op, object *tmp)
Permanently alters an object's stats/flags based on another object.
Definition: living.cpp:394
method_ret
char method_ret
Define some standard return values for callbacks which don't need to return any other results.
Definition: ob_methods.h:14
ob_types.h
sounds.h
object::dam_modifier
uint8_t dam_modifier
How going up in level affects damage.
Definition: object.h:419
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:266
apply_handle_yield
void apply_handle_yield(object *tmp)
This checks whether the object has a "on_use_yield" field, and if so generated and drops matching ite...
Definition: apply.cpp:122
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
drain_stat
void drain_stat(object *op)
Drains a random stat from op.
Definition: living.cpp:716
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:222
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:370
object::duration
int16_t duration
Number of moves (see 'speed') spell lasts.
Definition: object.h:415
arch_to_object
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
MSG_TYPE_APPLY_FAILURE
#define MSG_TYPE_APPLY_FAILURE
Apply OK, but no/bad result.
Definition: newclient.h:608
AT_DEPLETE
#define AT_DEPLETE
Lose one point from one stat, can be restored (65536) vick@bern.docs.uu.se.
Definition: attack.h:94
remove_depletion
int remove_depletion(object *op, int level)
Remove depletion from op, if present, and warn player of such restorations.
Definition: living.cpp:755
ob_methods.h
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Item is identifiable (e.g.
Definition: define.h:248
MSG_TYPE_APPLY
#define MSG_TYPE_APPLY
Applying objects.
Definition: newclient.h:412
object::attacktype
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:352
MOVE_PER_SECOND
static const float MOVE_PER_SECOND
Speed of an object that gives it one move per second, real time.
Definition: tod.h:54
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
identify
object * identify(object *op)
Identifies an item.
Definition: item.cpp:1446