Crossfire Server, Trunk  R20513
rune.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 
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  if (spell->face != blank_face)
155  rune->face = spell->face;
156  }
157  rune->level = caster_level(caster, spell);
158  rune->stats.Cha = rune->level/2; /* the invisibility parameter */
159  rune->direction = dir; /* where any spell will go upon detonation */
160  object_set_owner(rune, op); /* runes without need no owner */
161  set_spell_skill(op, caster, spell, rune);
162  object_insert_in_map_at(rune, m, op, 0, nx, ny);
163  return 1;
164 }
165 
175 static void rune_attack(object *op, object *victim) {
176  if (victim) {
177  tag_t tag = victim->count;
178  hit_player(victim, op->stats.dam, op, op->attacktype, 1);
179  if (object_was_destroyed(victim, tag))
180  return;
181  /* if there's a disease in the needle, put it in the player */
182  if (HAS_RANDOM_ITEMS(op))
183  create_treasure(op->randomitems, op, 0, (victim->map ? victim->map->difficulty : 1), 0);
184  if (op->inv && op->inv->type == DISEASE) {
185  object *disease = op->inv;
186 
187  infect_object(victim, disease, 1);
188  object_remove(disease);
190  }
191  } else
192  hit_map(op, 0, op->attacktype, 1);
193 }
194 
205 void spring_trap(object *trap, object *victim) {
206  object *env;
207  tag_t trap_tag = trap->count;
208  rv_vector rv;
209  int i, has_spell;
210 
211  /* Prevent recursion */
212  if (trap->stats.hp <= 0)
213  return;
214 
215  if (QUERY_FLAG(trap, FLAG_IS_LINKED))
216  use_trigger(trap);
217 
218  /* Check if this trap casts a spell */
219  has_spell = ((trap->inv && trap->inv->type == SPELL) || (trap->other_arch && trap->other_arch->clone.type == SPELL));
220 
221  env = object_get_env_recursive(trap);
222 
223  /* If the victim is not next to this trap, and the trap doesn't cast
224  * a spell, don't set it off.
225  */
226  if (!get_rangevector(env, victim, &rv, 0) || (rv.distance > 1 && !has_spell))
227  return;
228 
229  /* Only living objects can trigger runes that don't cast spells, as
230  * doing direct damage to a non-living object doesn't work anyway.
231  * Typical example is an arrow attacking a door.
232  */
233  if (!QUERY_FLAG(victim, FLAG_ALIVE) && !has_spell)
234  return;
235 
236  if (!QUERY_FLAG(trap, FLAG_LIFESAVE))
237  trap->stats.hp--; /*decrement detcount */
238 
239  if (victim && victim->type == PLAYER && trap->msg != NULL && trap->msg[0] != '\0')
241  trap->msg);
242 
243  /* Flash an image of the trap on the map so the poor sod
244  * knows what hit him.
245  */
246  trap_show(trap, env);
247 
248  /* Only if it is a spell do we proceed here */
249  if (has_spell) {
250  object *spell;
251 
252  /* This is necessary if the trap is inside something else */
253  object_remove(trap);
254  object_insert_in_map_at(trap, victim->map, trap, 0, victim->x, victim->y);
255 
256  if (object_was_destroyed(trap, trap_tag))
257  return;
258 
259  for (i = 0; i < MAX(1, trap->stats.maxhp); i++) {
260  if (trap->inv)
261  cast_spell(trap, trap, trap->direction, trap->inv, NULL);
262  else {
263  spell = arch_to_object(trap->other_arch);
264  cast_spell(trap, trap, trap->direction, spell, NULL);
266  }
267  }
268  } else {
269  rune_attack(trap, victim);
270  if (object_was_destroyed(trap, trap_tag))
271  return;
272  }
273 
274  if (trap->stats.hp <= 0) {
275  trap->type = SIGN; /* make the trap impotent */
276  trap->stats.food = 20; /* make it stick around until its spells are gone */
277  SET_FLAG(trap, FLAG_IS_USED_UP);
278  }
279 }
280 
299 int dispel_rune(object *op, object *caster, object *spell, object *skill, int dir) {
300  object *rune;
301  int mflags;
302  int16_t x, y;
303  mapstruct *m;
304 
305  x = op->x+freearr_x[dir];
306  y = op->y+freearr_y[dir];
307  m = op->map;
308 
309  mflags = get_map_flags(m, &m, x, y, &x, &y);
310 
311  /* Should we perhaps not allow player to disable traps if a monster/
312  * player is standing on top?
313  */
314  if (mflags&P_OUT_OF_MAP) {
316  "There's nothing there!");
317  return 0;
318  }
319 
320  /* This can happen if a player does a 'magic rune of dispel'. Without
321  * any skill, chance of success is zero, and we don't know who to tell
322  * (as otherwise we would have a skill pointer). Plus, trap_disarm()
323  * presumes skill is not null and will crash if it is.
324  */
325  if (!skill)
326  return 0;
327 
328  rune = NULL;
329  FOR_MAP_PREPARE(m, x, y, tmp) {
330  object *tmp2;
331 
332  if (tmp->type == RUNE || tmp->type == TRAP) {
333  rune = tmp;
334  break;
335  }
336 
337  /* we could put a probability chance here, but since nothing happens
338  * if you fail, no point on that. I suppose we could do a level
339  * comparison so low level players can't erase high level players runes.
340  */
341  if (tmp->type == SIGN && !strcmp(tmp->arch->name, "rune_mark")) {
342  object_remove(tmp);
345  "You wipe out the rune of marking!");
346  return 1;
347  }
348 
349  /* now search tmp's inventory for traps
350  * This is for chests, where the rune is in the chests inventory.
351  */
352  tmp2 = object_find_by_type2(tmp, RUNE, TRAP);
353  if (tmp2 != NULL) {
354  rune = tmp2;
355  break;
356  }
357  } FOR_MAP_FINISH();
358 
359  /* no rune there. */
360  if (rune == NULL) {
362  "There's nothing there!");
363  return 0;
364  }
365  trap_disarm(op, rune, 0, skill);
366  return 1;
367 }
368 
380 int trap_see(object *op, object *trap) {
381  int chance;
382 
383  chance = random_roll(0, 99, op, PREFER_HIGH);
384 
385  /* decide if we see the rune or not */
386  if ((trap->stats.Cha == 1)
387  || (chance > MIN(95, MAX(5, ((int)((float)(op->map->difficulty+trap->level+trap->stats.Cha-op->level)/10.0*50.0)))))) {
389  "You spot a %s!",
390  trap->name);
391  return 1;
392  }
393  return 0;
394 }
395 
407 int trap_show(object *trap, object *where) {
408  object *tmp2;
409 
410  if (where == NULL)
411  return 0;
412  tmp2 = create_archetype("runedet");
413  tmp2->face = GET_ANIMATION(trap, 0);
414  object_insert_in_map_at(tmp2, where->map, NULL, 0, where->x, where->y);
415  return 1;
416 }
417 
432 int trap_disarm(object *disarmer, object *trap, int risk, object *skill) {
433  int trapworth; /* need to compute the experience worth of the trap
434  before we kill it */
435 
436  /* this formula awards a more reasonable amount of exp */
437  trapworth = MAX(1, trap->level)*disarmer->map->difficulty*
438  sqr(MAX(trap->stats.dam, trap->inv ? trap->inv->level : 1))/skill->level;
439 
440  if (!(random_roll(0, (MAX(2, MIN(20, trap->level-skill->level+5-disarmer->stats.Dex/2))-1), disarmer, PREFER_LOW))) {
441  object *owner;
442 
443  draw_ext_info_format(NDI_UNIQUE, 0, disarmer,
445  "You successfully disarm the %s!",
446  trap->name);
447  destroy_object(trap);
448  /* If it is your own trap, (or any players trap), don't you don't
449  * get exp for it.
450  */
451  owner = object_get_owner(trap);
452  if (owner != NULL && owner->type != PLAYER && risk)
453  return trapworth;
454  else
455  return 1; /* give minimal exp and say success */
456  } else {
457  draw_ext_info_format(NDI_UNIQUE, 0, disarmer,
459  "You fail to disarm the %s.",
460  trap->name);
461  if (!(random_roll(0, (MAX(2, skill->level-trap->level+disarmer->stats.Dex/2-6))-1, disarmer, PREFER_LOW))
462  && risk) {
463  draw_ext_info(NDI_UNIQUE, 0, disarmer,
465  "In fact, you set it off!");
466  spring_trap(trap, disarmer);
467  }
468  return 0;
469  }
470 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Sends message to player(s).
Definition: main.c:315
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:316
Spell-related defines: spellpath, subtypes, ...
This is used by get_rangevector to determine where the other creature is.
Definition: map.h:380
int caster_level(const object *caster, const object *spell)
This function returns the effective level the spell is being cast at.
Definition: spell_util.c:233
#define SET_FLAG(xyz, p)
Definition: define.h:223
#define MSG_TYPE_COMMAND_FAILURE
Failed result from command.
Definition: newclient.h:511
#define FLAG_IS_USED_UP
When (–food<0) the object will exit.
Definition: define.h:260
object * object_get_env_recursive(object *op)
Utility function.
Definition: object.c:333
#define MSG_TYPE_APPLY_TRAP
Have activated a trap.
Definition: newclient.h:601
#define MSG_TYPE_SPELL
Spell related info.
Definition: newclient.h:387
#define SPELL_GRACE
Definition: spells.h:59
#define sqr(x)
Definition: rune.c:28
#define MSG_TYPE_SPELL_FAILURE
Spell failure messages.
Definition: newclient.h:628
struct treasureliststruct * randomitems
Items to be generated.
Definition: object.h:385
object clone
An object from which to do object_copy()
Definition: object.h:470
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.c:65
#define PREFER_LOW
Definition: define.h:600
See Rune.
Definition: object.h:240
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.c:277
#define GET_ANIMATION(ob, anim)
Definition: global.h:172
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:68
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:343
#define MAX(x, y)
Definition: compat.h:20
int16_t sp
Spell points.
Definition: living.h:41
Global type definitions and header inclusions.
struct archt * other_arch
Pointer used for various things - mostly used for what this objects turns into or what this object cr...
Definition: object.h:413
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.c:310
#define MSG_TYPE_APPLY
Applying objects.
Definition: newclient.h:384
#define MIN(x, y)
Definition: compat.h:17
int16_t hp
Hit Points.
Definition: living.h:39
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.c:71
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
This calls the appropriate treasure creation function.
Definition: treasure.c:490
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.c:601
See Trap.
Definition: object.h:241
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.c:1368
int16_t y
Position in the map for this object.
Definition: object.h:326
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.c:1921
int16_t maxhp
Max hit points.
Definition: living.h:40
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:379
uint32_t path_denied
Paths the object is denied access to.
Definition: object.h:345
See Sign & Magic Mouth.
Definition: object.h:211
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it...
Definition: object.c:1037
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.c:620
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.c:2690
#define MSG_TYPE_SPELL_SUCCESS
Spell succeeded messages.
Definition: newclient.h:630
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:510
signed short int16_t
Definition: win32.h:160
struct mapdef * map
Pointer to the map in which this object is present.
Definition: object.h:297
#define snprintf
Definition: win32.h:46
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:712
int16_t dam
How much damage this object does when hitting.
Definition: living.h:45
#define MSG_TYPE_SPELL_ERROR
Spell failure messages.
Definition: newclient.h:631
const char * name
The name of the object, obviously...
Definition: object.h:311
int trap_disarm(object *disarmer, object *trap, int risk, object *skill)
Try to disarm a trap/rune.
Definition: rune.c:432
int hit_map(object *op, int dir, uint32_t type, int full_hit)
Attack a spot on the map.
Definition: attack.c:320
#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.c:317
int8_t direction
Means the object is moving that way.
Definition: object.h:334
int8_t Cha
Definition: living.h:35
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:251
void use_trigger(object *op)
Toggles the state of specified button.
Definition: button.c:259
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:12
See Spell.
Definition: object.h:214
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
int write_rune(object *op, object *caster, object *spell, int dir, const char *runename)
Player is attempting to write a magical rune.
Definition: rune.c:50
void spring_trap(object *trap, object *victim)
This function generalizes attacks by runes/traps.
Definition: rune.c:205
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
int16_t x
Definition: object.h:326
const char * skill
Name of the skill this object uses/grants.
Definition: object.h:321
uint16_t difficulty
What level the player should be to play here.
Definition: map.h:343
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:765
See Player.
Definition: object.h:107
int dispel_rune(object *op, object *caster, object *spell, object *skill, int dir)
Someone is trying to disarm a rune.
Definition: rune.c:299
#define PREFER_HIGH
Definition: define.h:599
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:342
int16_t grace
Grace.
Definition: living.h:43
New_Face * blank_face
Following can just as easily be pointers, but it is easier to keep them like this.
Definition: image.c:39
tag_t count
Unique object number for this object.
Definition: object.h:299
living stats
Str, Con, Dex, etc.
Definition: object.h:368
int8_t Dex
Definition: living.h:35
void set_spell_skill(object *op, object *caster, object *spob, object *dest)
Utility function to assign the correct skill when casting.
Definition: spell_util.c:94
void destroy_object(object *op)
Recursively object_free_drop_inventory() op and its inventory.
Definition: login.c:190
unsigned int distance
Distance, in squares.
Definition: map.h:381
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
#define FLAG_LIFESAVE
Saves a players&#39; life once, then destr.
Definition: define.h:306
const char * msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:322
int object_matches_string(object *pl, object *op, const char *name)
This is a subset of the parse_id command.
Definition: object.c:4453
static void rune_attack(object *op, object *victim)
This function handles those runes which detonate but do not cast spells.
Definition: rune.c:175
int trap_see(object *op, object *trap)
Should op see trap?
Definition: rune.c:380
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.c:838
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.c:302
struct obj * inv
Pointer to the first object in the inventory.
Definition: object.h:290
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:758
void object_set_msg(object *op, const char *msg)
Set the message field of an object.
Definition: object.c:4695
int trap_show(object *trap, object *where)
Handles showing a trap/rune detonation.
Definition: rune.c:407
#define SPELL_MANA
Definition: spells.h:58
This is a game-map.
Definition: map.h:325
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.c:42
const New_Face * face
Face with colors.
Definition: object.h:332
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Object is attacked by something.
Definition: attack.c:1861
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.c:2516
int16_t level
Level of creature or object.
Definition: object.h:351
See Disease.
Definition: object.h:244
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.c:571
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.c:559
#define HAS_RANDOM_ITEMS(op)
This return TRUE if object has still randomitems which could be expanded.
Definition: define.h:183
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:705
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Main dispatch when someone casts a spell.
Definition: spell_util.c:1471
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.c:1654
object * object_find_by_type2(const object *who, int type1, int type2)
Find object in inventory.
Definition: object.c:3928
int32_t food
How much food in stomach.
Definition: living.h:47