Crossfire Server, Trunk  1.75.0
c_range.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 <stdlib.h>
22 #include <string.h>
23 
24 #include "commands.h"
25 #include "shared/newclient.h"
26 #include "skills.h"
27 #include "spells.h"
28 #include "sproto.h"
29 
38 void command_invoke(object *op, const char *params) {
39  command_cast_spell(op, params, 1);
40 }
41 
50 void command_cast(object *op, const char *params) {
51  command_cast_spell(op, params, 0);
52 }
53 
65 static void show_matching_spells(object *op, const char *params) {
66  char spell_sort[NROFREALSPELLS][MAX_BUF], tmp[MAX_BUF], *cp;
67  int num_found = 0, i;
68 
69  /* We go and see what spells the player has. We put them
70  * into the spell_sort array so that we can sort them -
71  * we prefix the skill in the name so that the sorting
72  * works better.
73  */
74  FOR_INV_PREPARE(op, spell) {
75  /* If it is a spell, and no params are passed, or they
76  * match the name, process this spell.
77  */
78  if (spell->type == SPELL
79  && (*params == '\0' || !strncmp(params, spell->name, strlen(params)))) {
80  if (spell->path_attuned&op->path_denied) {
81  snprintf(spell_sort[num_found++], sizeof(spell_sort[0]),
82  "%s:%-30s %3s %3s", spell->skill ? spell->skill : "generic",
83  spell->name, "den", "den");
84  } else {
85  snprintf(spell_sort[num_found++], sizeof(spell_sort[0]),
86  "%s:%-30s %3d %3d", spell->skill ? spell->skill : "generic",
87  spell->name, spell->level,
89  }
90  }
91  } FOR_INV_FINISH();
92  if (!num_found) {
93  if (*params != '\0')
95  "You know no spells like '%s'.", params);
96  else
98  "You know no spells.");
99 
100  return;
101  }
102 
103  if (*params != '\0')
105  "You know the following '%s' spells:", params);
106  else
108  "You know the following spells:");
109 
110  /* Note in the code below that we make some
111  * presumptions that there will be a colon in the
112  * string. given the code above, this is always
113  * the case.
114  */
115  qsort(spell_sort, num_found, MAX_BUF, (int (*)(const void *, const void *))strcmp);
116  strcpy(tmp, "asdfg"); /* Dummy string so initial compare fails */
117  for (i = 0; i < num_found; i++) {
118  /* Different skill name, so print banner */
119  if (strncmp(tmp, spell_sort[i], strlen(tmp))) {
120  strcpy(tmp, spell_sort[i]);
121  cp = strchr(tmp, ':');
122  *cp = '\0';
123 
125  "\n[b][fixed]%s spells %.*s <lvl> <sp>",
126  tmp, (int)(20-strlen(tmp)), " ");
127  }
129  "[fixed]%s",
130  strchr(spell_sort[i], ':')+1);
131  }
132 }
133 
146 void command_cast_spell(object *op, const char *params, int cast_now) {
147  char *cp, cpy[MAX_BUF];
148  object *spob;
149 
150  safe_strncpy(cpy, params, sizeof(cpy));
151 
152  if (*cpy != '\0') {
153  tag_t spellnumber = 0;
154  if ((spellnumber = atoi(cpy)) != 0)
155  spob = object_find_by_tag(op, spellnumber);
156  else
157  spob = lookup_spell_by_name(op, cpy);
158 
159  if (spob && spob->type == SPELL) {
160  /* Now grab any extra data, if there is any. Forward pass
161  * any 'of' delimiter
162  */
163  if (spellnumber) {
164  /* if we passed a number, the options start at the second word */
165  cp = strchr(cpy, ' ');
166  if (cp) {
167  cp++;
168  if (!strncmp(cp, "of ", 3))
169  cp += 3;
170  }
171  } else if (strlen(cpy) > strlen(spob->name)) {
172  cp = cpy+strlen(spob->name);
173  *cp = 0;
174  cp++;
175  if (!strncmp(cp, "of ", 3))
176  cp += 3;
177  } else
178  cp = NULL;
179 
180  if (spob->skill && !find_skill_by_name(op, spob->skill)) {
182  "You need the skill %s to cast %s!",
183  spob->skill, spob->name);
184  return;
185  }
186 
187  /* Remove control of the golem */
188  if (op->contr->ranges[range_golem] != NULL) {
189  if (op->contr->golem_count == op->contr->ranges[range_golem]->count) {
193  }
194  op->contr->ranges[range_golem] = NULL;
195  op->contr->golem_count = 0;
196  }
197 
198  /* This assignment is need for casting_time logic */
199  op->spell = spob;
200  if (cast_now) {
201  cast_spell(op, op, op->facing, spob, cp);
202  } else {
204  sstring required = object_get_value(spob, "casting_requirements");
205  op->contr->ranges[range_magic] = spob;
206  op->contr->shoottype = range_magic;
207 
208  if (cp != NULL) {
209  strncpy(op->contr->spellparam, cp, MAX_BUF);
210  op->contr->spellparam[MAX_BUF-1] = '\0';
211  } else {
212  op->contr->spellparam[0] = '\0';
213  }
215  "You ready the spell %s%s%s",
216  spob->name, required ? " which consumes for each invocation " : "", required ? required : "");
217  }
218  return;
219  } /* else fall through to below and print spells */
220  } /* params supplied */
221 
222  /* We get here if cast was given without options or we could not find
223  * the requested spell. List all the spells the player knows.
224  */
225  show_matching_spells(op, cpy);
226 }
227 
228 /**************************************************************************/
229 
247 int legal_range(object *op, int r) {
248  switch (r) {
249  case range_none: /* "Nothing" is always legal */
250  return 1;
251 
252  case range_bow:
253  case range_misc:
254  case range_magic: /* cast spells */
255  case range_builder:
256  if (op->contr->ranges[r])
257  return 1;
258  else
259  return 0;
260 
261  case range_golem: /* Use scrolls */
262  if (op->contr->ranges[range_golem]
263  && op->contr->ranges[range_golem]->count == op->contr->golem_count)
264  return 1;
265  else
266  return 0;
267 
268  case range_skill:
269  if (op->chosen_skill)
270  return 1;
271  else
272  return 0;
273  }
274  /* No match above, must not be valid */
275  return 0;
276 }
277 
284 static void send_updated_shoottype(object *op) {
285  char name[MAX_BUF];
286 
287  /* Legal range has already checked that we have an appropriate item
288  * that uses the slot, so we don't need to be too careful about
289  * checking the status of the object.
290  */
291  switch (op->contr->shoottype) {
292  case range_none:
294  "No ranged attack chosen.");
295  break;
296 
297  case range_golem:
299  "You regain control of your golem.");
300  break;
301 
302  case range_bow:
305  "Switched to %s and %s.",
306  name,
307  op->contr->ranges[range_bow]->race ? op->contr->ranges[range_bow]->race : "nothing");
308  break;
309 
310  case range_magic:
312  "Switched to spells (%s).",
313  op->contr->ranges[range_magic]->name);
314  break;
315 
316  case range_misc:
317  case range_builder:
320  "Switched to %s.",
321  name);
322  break;
323 
324  case range_skill:
326  "Switched to skill: %s",
327  op->chosen_skill ? op->chosen_skill->name : "none");
328  break;
329 
330  default:
331  break;
332  }
333 }
334 
343 void command_rotateshoottype(object *op, const char *params) {
344  char name[MAX_BUF];
345  int dir = ((*params == '\0') || (params[0] == '+')) ? 1 : -1;
346 
347  /* Iterate through shoottypes in the given direction, until the first
348  * legal shoottype is found */
349  do {
350  op->contr->shoottype = static_cast<rangetype>((static_cast<int>(op->contr->shoottype) + dir));
351 
352  if (op->contr->shoottype >= range_size)
353  op->contr->shoottype = range_none;
354  else if (op->contr->shoottype <= range_bottom)
355  op->contr->shoottype = static_cast<rangetype>(range_size-1);
356  } while (!legal_range(op, op->contr->shoottype));
357 
359 }
360 
361 
370 void command_shoottype(object *op, const char *params) {
371  static struct {
372  const char *range;
373  rangetype shoottype;
374  } lookup[] = {
375  /* rangetypes from player.h */
376  { "none", range_none },
377  { "bow", range_bow },
378  { "magic", range_magic },
379  { "misc", range_misc },
380  { "golem", range_golem },
381  { "skill", range_skill },
382  { "builder", range_builder },
383 
384  /* aliases for rangetypes */
385  { "spell", range_magic },
386  { "wand", range_misc },
387  { "rod", range_misc },
388 
389  /* range_size indicates the end of lookups */
390  { "", range_size },
391  };
392 
393  int ix;
394 
395  /* No params, display current shoottype and return */
396  if (*params == '\0') {
397  for (ix = 0; lookup[ix].shoottype != range_size; ix++) {
398  if (op->contr->shoottype == lookup[ix].shoottype) {
400  "shoottype is set to %s", lookup[ix].range);
401  break;
402  }
403  }
404 
405  return;
406  }
407 
408  /* Set shoottype from params */
409  for (ix = 0; lookup[ix].shoottype != range_size; ix++) {
410  if (!strcmp(params, lookup[ix].range)) {
411  /* matching shoottype found, set if legal */
412  if (legal_range(op, lookup[ix].shoottype)) {
413  op->contr->shoottype = lookup[ix].shoottype;
415  } else {
417  "shoottype not readied: %s", lookup[ix].range);
418  }
419 
420  return;
421  }
422  }
423 
424  /* Invalid shoottype, notify client */
426  "shoottype: Unknown shoottype option %s", params);
427 }
global.h
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
remove_friendly_object
void remove_friendly_object(object *op)
Removes the specified object from the linked list of friendly objects.
Definition: friend.cpp:52
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:533
NROFREALSPELLS
#define NROFREALSPELLS
Number of spells.
Definition: spells.h:48
range_bow
@ range_bow
Bow.
Definition: player.h:31
player::golem_count
uint32_t golem_count
To track the golem.
Definition: player.h:119
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:410
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
range_none
@ range_none
No range selected.
Definition: player.h:30
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
object::count
tag_t count
Unique object number for this object.
Definition: object.h:307
skills.h
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can't use command.
Definition: newclient.h:532
range_golem
@ range_golem
Control golem.
Definition: player.h:34
object_get_value
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4346
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:407
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
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
object::path_denied
uint32_t path_denied
Paths the object is denied access to.
Definition: object.h:355
range_builder
@ range_builder
Map builder.
Definition: player.h:36
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1560
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
show_matching_spells
static void show_matching_spells(object *op, const char *params)
Shows all spells that op knows.
Definition: c_range.cpp:65
command_cast_spell
void command_cast_spell(object *op, const char *params, int cast_now)
Sets up to cast a spell.
Definition: c_range.cpp:146
object::chosen_skill
object * chosen_skill
The skill chosen to use.
Definition: object.h:396
range_size
@ range_size
Maximum, exclusive, value.
Definition: player.h:37
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:588
player::ranges
object * ranges[range_size]
Object for each range.
Definition: player.h:116
object::spell
object * spell
Spell that was being cast.
Definition: object.h:420
range_magic
@ range_magic
Spells.
Definition: player.h:32
send_updated_shoottype
static void send_updated_shoottype(object *op)
Sends the updated range attack to the client.
Definition: c_range.cpp:284
lookup_spell_by_name
object * lookup_spell_by_name(object *op, const char *spname)
Look at object 'op' and see if they know the spell spname.
Definition: spell_util.cpp:410
SPELL_HIGHEST
#define SPELL_HIGHEST
Definition: spells.h:60
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
object_find_by_tag
object * object_find_by_tag(const object *who, tag_t tag)
Find object in inventory.
Definition: object.cpp:4060
spell
with a maximum of six This is not so if you are wearing plate you receive no benefit Armour is additive with all the supplementry forms of which means that it lasts until the next semi permanent spell effect is cast upon the character spell
Definition: tome-of-magic.txt:44
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:671
MSG_TYPE_SKILL_MISSING
#define MSG_TYPE_SKILL_MISSING
Don't have the skill.
Definition: newclient.h:590
range_bottom
@ range_bottom
Minimum, exclusive, value.
Definition: player.h:29
rangetype
rangetype
What range is currently selected by the player.
Definition: player.h:28
tag_t
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
player::shoottype
rangetype shoottype
Which range-attack is being used by player.
Definition: player.h:112
sproto.h
SP_level_spellpoint_cost
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Scales the spellpoint cost of a spell by it's increased effectiveness.
Definition: spell_util.cpp:236
object::race
sstring race
Human, goblin, dragon, etc.
Definition: object.h:326
object::facing
int8_t facing
Object is oriented/facing that way.
Definition: object.h:345
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
This returns the skill pointer of the given name (the one that accumulates exp, has the level,...
Definition: skill_util.cpp:211
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
legal_range
int legal_range(object *op, int r)
Check for the validity of a player range.
Definition: c_range.cpp:247
range_misc
@ range_misc
Misc items.
Definition: player.h:33
command_invoke
void command_invoke(object *op, const char *params)
'invoke' command, fires a spell immediately.
Definition: c_range.cpp:38
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:265
spells.h
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
sstring
const typedef char * sstring
Definition: sstring.h:2
object::skill
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
MSG_TYPE_COMMAND_CONFIG
#define MSG_TYPE_COMMAND_CONFIG
bowmode, petmode, applymode
Definition: newclient.h:528
newclient.h
command_shoottype
void command_shoottype(object *op, const char *params)
'shoottype' command, set range attack.
Definition: c_range.cpp:370
object_remove
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:1833
commands.h
command_cast
void command_cast(object *op, const char *params)
'cast' command, prepares a spell for laster casting.
Definition: c_range.cpp:50
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.cpp:689
range_skill
@ range_skill
Use skill.
Definition: player.h:35
command_rotateshoottype
void command_rotateshoottype(object *op, const char *params)
'rotateshoottype' command, switch range attack.
Definition: c_range.cpp:343
SPELL
@ SPELL
Definition: object.h:219
player::spellparam
char spellparam[MAX_BUF]
What param to add to spells.
Definition: player.h:113
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:664