Crossfire Server  1.75.0
rune.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 
20 #include "global.h"
21 
22 #include <string.h>
23 
24 #include "sproto.h"
25 #include "spells.h"
26 
27 #ifndef sqr
28 #define sqr(x) ((x)*(x))
29 #endif
30 
50 int write_rune(object *op, object *caster, object *spell, int dir, const char *runename) {
51  object *rune_spell, *rune;
52  char buf[MAX_BUF];
53  mapstruct *m;
54  int16_t nx, ny, gr;
55 
56  if (!dir) {
57  dir = 1;
58  }
59 
60  nx = op->x+freearr_x[dir];
61  ny = op->y+freearr_y[dir];
62  m = op->map;
63 
64  if (get_map_flags(m, &m, nx, ny, &nx, &ny)) {
66  "Can't make a rune there!");
67  return 0;
68  }
69  FOR_MAP_PREPARE(m, nx, ny, tmp)
70  if (tmp->type == RUNE) {
72  "You can't write a rune there.");
73  return 0;
74  }
76 
77  if (spell->other_arch) {
78  rune_spell = arch_to_object(spell->other_arch);
79  } else {
80  /* Player specified spell. The player has to know the spell, so
81  * lets just look through the players inventory see if they know it
82  * use the object_matches_string() for our typical matching method.
83  */
84  int bestmatch = 0, ms;
85 
86  if (!runename || *runename == 0) {
88  "Write a rune of what?");
89  return 0;
90  }
91 
92  rune_spell = NULL;
93  FOR_INV_PREPARE(op, tmp) {
94  if (tmp->type == SPELL) {
95  ms = object_matches_string(op, tmp, runename);
96  if (ms > bestmatch) {
97  bestmatch = ms;
98  rune_spell = tmp;
99  }
100  }
101  } FOR_INV_FINISH();
102  if (!rune_spell) {
105  "You don't know any spell named %s",
106  runename);
107  return 0;
108  }
109  if (rune_spell->skill != spell->skill) {
112  "You can't cast %s with %s",
113  rune_spell->name, spell->name);
114  return 0;
115  }
116  if (caster->path_denied&spell->path_attuned) {
118  "%s belongs to a spell path denied to you.",
119  rune_spell->name);
120  return 0;
121  }
122  if (caster_level(caster, rune_spell) < rune_spell->level) {
124  "%s is beyond your ability to cast!",
125  rune_spell->name);
126  return 0;
127  }
128  if (SP_level_spellpoint_cost(caster, rune_spell, SPELL_MANA) > op->stats.sp) {
130  "You don't have enough mana.");
131  return 0;
132  }
133  gr = SP_level_spellpoint_cost(caster, rune_spell, SPELL_GRACE);
134  if ((gr > 0) && (gr > op->stats.grace)) {
136  "You don't have enough grace.");
137  return 0;
138  }
139  op->stats.grace -= gr;
140  op->stats.sp -= SP_level_spellpoint_cost(caster, rune_spell, SPELL_MANA);
141  }
142  /* already proper rune. Note this should only be the case if other_arch was set */
143  if (rune_spell->type == RUNE) {
144  rune = rune_spell;
145  } else {
146  object *tmp;
147 
149  snprintf(buf, sizeof(buf), "You set off a rune of %s\n", rune_spell->name);
150  object_set_msg(rune, buf);
151  tmp = object_new();
152  object_copy(rune_spell, tmp);
153  object_insert_in_ob(tmp, rune);
154  // Try to find a rune of the given name (and a .111 suffix) and animation, and,
155  // if yes, override with the image *and* the animation.
156  // If either is missing, don't do it. Let's not make more edge cases for now :)
157  char buf[100];
158  snprintf(buf, 100, "%s.111", spell->name);
159  const Face *face_override = try_find_face(buf, NULL);
160  const Animations *anim_override = try_find_animation(spell->name);
161  if (face_override != NULL && anim_override != NULL) {
162  rune->face = face_override;
163  rune->animation = anim_override;
164  }
165  }
166  rune->level = caster_level(caster, spell);
167  rune->stats.Cha = rune->level/2; /* the invisibility parameter */
168  rune->direction = dir; /* where any spell will go upon detonation */
169  object_set_owner(rune, op); /* runes without need no owner */
170  set_spell_skill(op, caster, spell, rune);
171  object_insert_in_map_at(rune, m, op, 0, nx, ny);
172  return 1;
173 }
174 
184 static void rune_attack(object *op, object *victim) {
185  if (victim) {
186  tag_t tag = victim->count;
187  hit_player(victim, op->stats.dam, op, op->attacktype, 1);
188  if (object_was_destroyed(victim, tag))
189  return;
190  /* if there's a disease in the needle, put it in the player */
191  if (HAS_RANDOM_ITEMS(op))
192  create_treasure(op->randomitems, op, 0, (victim->map ? victim->map->difficulty : 1), 0);
193  if (op->inv && op->inv->type == DISEASE) {
194  object *disease = op->inv;
195 
196  infect_object(victim, disease, 1);
197  object_remove(disease);
199  }
200  } else
201  hit_map(op, 0, op->attacktype, 1);
202 }
203 
214 void spring_trap(object *trap, object *victim) {
215  object *env;
216  tag_t trap_tag = trap->count;
217  rv_vector rv;
218  int i, has_spell;
219 
220  /* Prevent recursion */
221  if (trap->stats.hp <= 0)
222  return;
223 
224  if (QUERY_FLAG(trap, FLAG_IS_LINKED))
225  use_trigger(trap);
226 
227  /* Check if this trap casts a spell */
228  has_spell = ((trap->inv && trap->inv->type == SPELL) || (trap->other_arch && trap->other_arch->clone.type == SPELL));
229 
230  env = object_get_env_recursive(trap);
231 
232  /* If the victim is not next to this trap, and the trap doesn't cast
233  * a spell, don't set it off.
234  */
235  if (!get_rangevector(env, victim, &rv, 0) || (rv.distance > 1 && !has_spell))
236  return;
237 
238  /* Only living objects can trigger runes that don't cast spells, as
239  * doing direct damage to a non-living object doesn't work anyway.
240  * Typical example is an arrow attacking a door.
241  */
242  if (!QUERY_FLAG(victim, FLAG_ALIVE) && !has_spell)
243  return;
244 
245  if (!QUERY_FLAG(trap, FLAG_LIFESAVE))
246  trap->stats.hp--; /*decrement detcount */
247 
248  if (victim->type == PLAYER && trap->msg != NULL && trap->msg[0] != '\0')
250  trap->msg);
251 
252  /* Flash an image of the trap on the map so the poor sod
253  * knows what hit him.
254  */
255  trap_show(trap, env);
256 
257  /* Only if it is a spell do we proceed here */
258  if (has_spell) {
259  object *spell;
260 
261  /* This is necessary if the trap is inside something else */
262  object_remove(trap);
263  object_insert_in_map_at(trap, victim->map, trap, 0, victim->x, victim->y);
264 
265  if (object_was_destroyed(trap, trap_tag))
266  return;
267 
268  for (i = 0; i < MAX(1, trap->stats.maxhp); i++) {
269  if (trap->inv)
270  cast_spell(trap, trap, trap->direction, trap->inv, NULL);
271  else {
272  spell = arch_to_object(trap->other_arch);
273  cast_spell(trap, trap, trap->direction, spell, NULL);
275  }
276  }
277  } else {
278  rune_attack(trap, victim);
279  if (object_was_destroyed(trap, trap_tag))
280  return;
281  }
282 
283  if (trap->stats.hp <= 0) {
284  trap->type = SIGN; /* make the trap impotent */
285  trap->stats.food = 20; /* make it stick around until its spells are gone */
286  SET_FLAG(trap, FLAG_IS_USED_UP);
287  }
288 }
289 
304 int dispel_rune(object *op, object *skill, int dir) {
305  object *rune;
306  int mflags;
307  int16_t x, y;
308  mapstruct *m;
309 
310  x = op->x+freearr_x[dir];
311  y = op->y+freearr_y[dir];
312  m = op->map;
313 
314  mflags = get_map_flags(m, &m, x, y, &x, &y);
315 
316  /* Should we perhaps not allow player to disable traps if a monster/
317  * player is standing on top?
318  */
319  if (mflags&P_OUT_OF_MAP) {
321  "There's nothing there!");
322  return 0;
323  }
324 
325  /* This can happen if a player does a 'magic rune of dispel'. Without
326  * any skill, chance of success is zero, and we don't know who to tell
327  * (as otherwise we would have a skill pointer). Plus, trap_disarm()
328  * presumes skill is not null and will crash if it is.
329  */
330  if (!skill)
331  return 0;
332 
333  rune = NULL;
334  FOR_MAP_PREPARE(m, x, y, tmp) {
335  object *tmp2;
336 
337  if (tmp->type == RUNE || tmp->type == TRAP) {
338  rune = tmp;
339  break;
340  }
341 
342  /* we could put a probability chance here, but since nothing happens
343  * if you fail, no point on that. I suppose we could do a level
344  * comparison so low level players can't erase high level players runes.
345  */
346  if (tmp->type == SIGN && !strcmp(tmp->arch->name, "rune_mark")) {
347  object_remove(tmp);
350  "You wipe out the rune of marking!");
351  return 1;
352  }
353 
354  /* now search tmp's inventory for traps
355  * This is for chests, where the rune is in the chests inventory.
356  */
357  tmp2 = object_find_by_type2(tmp, RUNE, TRAP);
358  if (tmp2 != NULL) {
359  rune = tmp2;
360  break;
361  }
362  } FOR_MAP_FINISH();
363 
364  /* no rune there. */
365  if (rune == NULL) {
367  "There's nothing there!");
368  return 0;
369  }
370  trap_disarm(op, rune, 0, skill);
371  return 1;
372 }
373 
385 int trap_see(object *op, object *trap) {
386  int chance;
387 
388  chance = random_roll(0, 99, op, PREFER_HIGH);
389 
390  /* decide if we see the rune or not */
391  if ((trap->stats.Cha == 1)
392  || (chance > MIN(95, MAX(5, ((int)((float)(op->map->difficulty+trap->level+trap->stats.Cha-op->level)/10.0*50.0)))))) {
394  "You spot a %s!",
395  trap->name);
396  return 1;
397  }
398  return 0;
399 }
400 
412 int trap_show(object *trap, object *where) {
413  object *tmp2;
414 
415  if (where == NULL)
416  return 0;
417  tmp2 = create_archetype("runedet");
418  // Custom-made traps can have no animation.
419  // The GET_ANIMATION macro does not handle this scenario
420  if (trap->animation || trap->temp_animation)
421  tmp2->face = GET_ANIMATION(trap, 0);
422  else
423  tmp2->face = trap->face;
424  object_insert_in_map_at(tmp2, where->map, NULL, 0, where->x, where->y);
425  return 1;
426 }
427 
442 int trap_disarm(object *disarmer, object *trap, int risk, object *skill) {
443  int trapworth; /* need to compute the experience worth of the trap
444  before we kill it */
445 
446  /* this formula awards a more reasonable amount of exp */
447  trapworth = MAX(1, trap->level)*disarmer->map->difficulty*
448  sqr(MAX(trap->stats.dam, trap->inv ? trap->inv->level : 1))/skill->level;
449 
450  if (!(random_roll(0, (MAX(2, MIN(20, trap->level-skill->level+5-disarmer->stats.Dex/2))-1), disarmer, PREFER_LOW))) {
451  object *owner;
452 
453  draw_ext_info_format(NDI_UNIQUE, 0, disarmer,
455  "You successfully disarm the %s!",
456  trap->name);
457  destroy_object(trap);
458  /* If it is your own trap, (or any players trap), don't you don't
459  * get exp for it.
460  */
461  owner = object_get_owner(trap);
462  if (owner != NULL && owner->type != PLAYER && risk)
463  return trapworth;
464  else
465  return 1; /* give minimal exp and say success */
466  } else {
467  draw_ext_info_format(NDI_UNIQUE, 0, disarmer,
469  "You fail to disarm the %s.",
470  trap->name);
471  if (!(random_roll(0, (MAX(2, skill->level-trap->level+disarmer->stats.Dex/2-6))-1, disarmer, PREFER_LOW))
472  && risk) {
473  draw_ext_info(NDI_UNIQUE, 0, disarmer,
475  "In fact, you set it off!");
476  spring_trap(trap, disarmer);
477  }
478  return 0;
479  }
480 }
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:303
Spell-related defines: spellpath, subtypes, ...
This is used by get_rangevector to determine where the other creature is.
Definition: map.h:375
This represents one animation.
Definition: face.h:25
int dispel_rune(object *op, object *skill, int dir)
Someone is trying to disarm a rune.
Definition: rune.cpp:304
int caster_level(const object *caster, const object *spell)
This function returns the effective level the spell is being cast at.
Definition: spell_util.cpp:194
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.cpp:789
int8_t direction
Means the object is moving that way.
Definition: object.h:344
#define MSG_TYPE_COMMAND_FAILURE
Failed result from command.
Definition: newclient.h:552
void use_trigger(object *op)
Toggles the state of specified button.
Definition: button.cpp:254
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
int16_t grace
Grace.
Definition: living.h:44
int write_rune(object *op, object *caster, object *spell, int dir, const char *runename)
Player is attempting to write a magical rune.
Definition: rune.cpp:50
#define MSG_TYPE_APPLY_TRAP
Have activated a trap.
Definition: newclient.h:642
int trap_disarm(object *disarmer, object *trap, int risk, object *skill)
Try to disarm a trap/rune.
Definition: rune.cpp:442
object * object_find_by_type2(const object *who, int type1, int type2)
Find object in inventory.
Definition: object.cpp:4022
void object_set_msg(object *op, const char *msg)
Set the message field of an object.
Definition: object.cpp:4796
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.cpp:1818
#define MSG_TYPE_SPELL
Spell related info.
Definition: newclient.h:428
New face structure - this enforces the notion that data is face by face only - you can not change the...
Definition: face.h:14
#define SPELL_GRACE
Definition: spells.h:59
#define MSG_TYPE_SPELL_FAILURE
Spell failure messages.
Definition: newclient.h:669
#define PREFER_LOW
Definition: define.h:585
See Rune.
Definition: object.h:245
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Scales the spellpoint cost of a spell by it&#39;s increased effectiveness.
Definition: spell_util.cpp:236
#define GET_ANIMATION(ob, anim)
Definition: global.h:165
int16_t y
Position in the map for this object.
Definition: object.h:335
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
void spring_trap(object *trap, object *victim)
This function generalizes attacks by runes/traps.
Definition: rune.cpp:214
#define MAX(x, y)
Definition: compat.h:24
void object_set_owner(object *op, object *owner)
Sets the owner and sets the skill and exp pointers to owner&#39;s current skill and experience objects...
Definition: object.cpp:825
int16_t x
Definition: object.h:335
Global type definitions and header inclusions.
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.cpp:308
#define MSG_TYPE_APPLY
Applying objects.
Definition: newclient.h:425
#define MIN(x, y)
Definition: compat.h:21
bool chance(int a, int b)
Return true with a probability of a/b.
Definition: treasure.cpp:890
static std::shared_ptr< inja::Environment > env
Rendering environment.
Definition: mapper.cpp:2222
#define FLAG_IS_USED_UP
When (–food<0) the object will exit.
Definition: define.h:247
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:290
See Trap.
Definition: object.h:246
int16_t level
Level of creature or object.
Definition: object.h:361
int object_matches_string(object *pl, object *op, const char *name)
This is a subset of the parse_id command.
Definition: object.cpp:4559
int16_t sp
Spell points.
Definition: living.h:42
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:420
See Sign & Magic Mouth.
Definition: object.h:216
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:217
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
This calls the appropriate treasure creation function.
Definition: treasure.cpp:287
#define MSG_TYPE_SPELL_SUCCESS
Spell succeeded messages.
Definition: newclient.h:671
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:551
int8_t Dex
Use
Definition: living.h:36
static void rune_attack(object *op, object *victim)
This function handles those runes which detonate but do not cast spells.
Definition: rune.cpp:184
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
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
#define SET_FLAG(xyz, p)
Definition: define.h:384
#define QUERY_FLAG(xyz, p)
Definition: define.h:386
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.cpp:1545
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.cpp:299
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:700
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
#define MSG_TYPE_SPELL_ERROR
Spell failure messages.
Definition: newclient.h:672
This is a game-map.
Definition: map.h:320
const Animations * animation
Animation of this item, NULL if not animated.
Definition: object.h:428
int hit_map(object *op, int dir, uint32_t type, int full_hit)
Attack a spot on the map.
Definition: attack.cpp:355
#define GENERIC_RUNE
Definition: spells.h:167
int infect_object(object *victim, object *disease, int force)
Try to infect something with a disease.
Definition: disease.cpp:317
const Face * face
Face with colors.
Definition: object.h:341
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:254
object * object_get_env_recursive(object *op)
Utility function.
Definition: object.cpp:575
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it...
Definition: object.cpp:1258
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.cpp:42
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
int16_t dam
How much damage this object does when hitting.
Definition: living.h:46
See Spell.
Definition: object.h:219
uint32_t path_denied
Paths the object is denied access to.
Definition: object.h:355
living stats
Str, Con, Dex, etc.
Definition: object.h:378
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
const Animations * temp_animation
A temporary animation.
Definition: object.h:431
int trap_see(object *op, object *trap)
Should op see trap?
Definition: rune.cpp:385
void object_copy(const object *src_ob, object *dest_ob)
Copy object first frees everything allocated by the second object, and then copies the contents of th...
Definition: object.cpp:1177
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.cpp:305
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:753
See Player.
Definition: object.h:112
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
struct treasurelist * randomitems
Items to be generated.
Definition: object.h:395
#define sqr(x)
Definition: rune.cpp:28
#define PREFER_HIGH
Definition: define.h:584
static event_registration m
Definition: citylife.cpp:424
Animations * try_find_animation(const char *name)
Definition: assets.cpp:282
sstring name
The name of the object, obviously...
Definition: object.h:319
void set_spell_skill(object *op, object *caster, object *spob, object *dest)
Utility function to assign the correct skill when casting.
Definition: spell_util.cpp:94
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_...
Definition: map.cpp:300
int8_t Cha
Use
Definition: living.h:36
void destroy_object(object *op)
Recursively object_free_drop_inventory() op and its inventory.
Definition: login.cpp:209
unsigned int distance
Distance, in squares.
Definition: map.h:376
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
int trap_show(object *trap, object *where)
Handles showing a trap/rune detonation.
Definition: rune.cpp:412
#define FLAG_LIFESAVE
Saves a players&#39; life once, then destr.
Definition: define.h:293
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
From map.c This is used by get_player to determine where the other creature is.
Definition: map.cpp:2522
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:352
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:270
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:746
int32_t food
How much food in stomach.
Definition: living.h:48
StringBuffer * buf
Definition: readable.cpp:1563
#define SPELL_MANA
Definition: spells.h:58
int16_t maxhp
Max hit points.
Definition: living.h:41
uint16_t difficulty
What level the player should be to play here.
Definition: map.h:338
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 * 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
tag_t count
Unique object number for this object.
Definition: object.h:307
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Object is attacked by something.
Definition: attack.cpp:1907
See Disease.
Definition: object.h:249
object clone
An object from which to do object_copy()
Definition: object.h:487
#define HAS_RANDOM_ITEMS(op)
This return TRUE if object has still randomitems which could be expanded.
Definition: define.h:184
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:693
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Main dispatch when someone casts a spell.
int16_t hp
Hit Points.
Definition: living.h:40
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:353