Crossfire Server  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:
303  query_name(op->contr->ranges[range_bow], name, MAX_BUF);
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:
318  query_base_name(op->contr->ranges[op->contr->shoottype], 0, name, MAX_BUF);
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  int dir = ((*params == '\0') || (params[0] == '+')) ? 1 : -1;
345 
346  /* Iterate through shoottypes in the given direction, until the first
347  * legal shoottype is found */
348  do {
349  op->contr->shoottype = static_cast<rangetype>((static_cast<int>(op->contr->shoottype) + dir));
350 
351  if (op->contr->shoottype >= range_size)
352  op->contr->shoottype = range_none;
353  else if (op->contr->shoottype <= range_bottom)
354  op->contr->shoottype = static_cast<rangetype>(range_size-1);
355  } while (!legal_range(op, op->contr->shoottype));
356 
358 }
359 
360 
369 void command_shoottype(object *op, const char *params) {
370  static struct {
371  const char *range;
372  rangetype shoottype;
373  } lookup[] = {
374  /* rangetypes from player.h */
375  { "none", range_none },
376  { "bow", range_bow },
377  { "magic", range_magic },
378  { "misc", range_misc },
379  { "golem", range_golem },
380  { "skill", range_skill },
381  { "builder", range_builder },
382 
383  /* aliases for rangetypes */
384  { "spell", range_magic },
385  { "wand", range_misc },
386  { "rod", range_misc },
387 
388  /* range_size indicates the end of lookups */
389  { "", range_size },
390  };
391 
392  int ix;
393 
394  /* No params, display current shoottype and return */
395  if (*params == '\0') {
396  for (ix = 0; lookup[ix].shoottype != range_size; ix++) {
397  if (op->contr->shoottype == lookup[ix].shoottype) {
399  "shoottype is set to %s", lookup[ix].range);
400  break;
401  }
402  }
403 
404  return;
405  }
406 
407  /* Set shoottype from params */
408  for (ix = 0; lookup[ix].shoottype != range_size; ix++) {
409  if (!strcmp(params, lookup[ix].range)) {
410  /* matching shoottype found, set if legal */
411  if (legal_range(op, lookup[ix].shoottype)) {
412  op->contr->shoottype = lookup[ix].shoottype;
414  } else {
416  "shoottype not readied: %s", lookup[ix].range);
417  }
418 
419  return;
420  }
421  }
422 
423  /* Invalid shoottype, notify client */
425  "shoottype: Unknown shoottype option %s", params);
426 }
Use skill.
Definition: player.h:35
object * lookup_spell_by_name(object *op, const char *spname)
Look at object &#39;op&#39; and see if they know the spell spname.
Definition: spell_util.cpp:410
object * ranges[range_size]
Object for each range.
Definition: player.h:118
Spell-related defines: spellpath, subtypes, ...
#define MSG_TYPE_COMMAND_CONFIG
bowmode, petmode, applymode
Definition: newclient.h:546
void command_shoottype(object *op, const char *params)
&#39;shoottype&#39; command, set range attack.
Definition: c_range.cpp:369
Defines various flags that both the new client and new server use.
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
No range selected.
Definition: player.h:30
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
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
void remove_friendly_object(object *op)
Removes the specified object from the linked list of friendly objects.
Definition: friend.cpp:52
#define MSG_TYPE_SKILL_MISSING
Don&#39;t have the skill.
Definition: newclient.h:623
Misc items.
Definition: player.h:33
void command_invoke(object *op, const char *params)
&#39;invoke&#39; command, fires a spell immediately.
Definition: c_range.cpp:38
object * chosen_skill
The skill chosen to use.
Definition: object.h:396
Global type definitions and header inclusions.
#define safe_strncpy
Definition: compat.h:27
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
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
Minimum, exclusive, value.
Definition: player.h:29
#define NROFREALSPELLS
Number of spells.
Definition: spells.h:48
rangetype shoottype
Which range-attack is being used by player.
Definition: player.h:114
object * spell
Spell that was being cast.
Definition: object.h:420
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:420
object * object_find_by_tag(const object *who, tag_t tag)
Find object in inventory.
Definition: object.cpp:4045
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:551
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can&#39;t use command.
Definition: newclient.h:550
void command_cast_spell(object *op, const char *params, int cast_now)
Sets up to cast a spell.
Definition: c_range.cpp:146
Map builder.
Definition: player.h:36
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:594
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
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:700
Control golem.
Definition: player.h:34
uint32_t golem_count
To track the golem.
Definition: player.h:121
sstring race
Human, goblin, dragon, etc.
Definition: object.h:326
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4331
char spellparam[MAX_BUF]
What param to add to spells.
Definition: player.h:115
Defines and structures related to commands the player can send.
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
See Spell.
Definition: object.h:219
uint32_t path_denied
Paths the object is denied access to.
Definition: object.h:355
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
Skill-related defines, including subtypes.
int8_t facing
Object is oriented/facing that way.
Definition: object.h:345
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.cpp:692
Maximum, exclusive, value.
Definition: player.h:37
int legal_range(object *op, int r)
Check for the validity of a player range.
Definition: c_range.cpp:247
sstring name
The name of the object, obviously...
Definition: object.h:319
#define SPELL_HIGHEST
Definition: spells.h:60
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
rangetype
What range is currently selected by the player.
Definition: player.h:28
Bow.
Definition: player.h:31
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
static void send_updated_shoottype(object *op)
Sends the updated range attack to the client.
Definition: c_range.cpp:284
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:424
static void show_matching_spells(object *op, const char *params)
Shows all spells that op knows.
Definition: c_range.cpp:65
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:270
Spells.
Definition: player.h:32
void command_rotateshoottype(object *op, const char *params)
&#39;rotateshoottype&#39; command, switch range attack.
Definition: c_range.cpp:343
void command_cast(object *op, const char *params)
&#39;cast&#39; command, prepares a spell for laster casting.
Definition: c_range.cpp:50
const char * sstring
Definition: sstring.h:2
tag_t count
Unique object number for this object.
Definition: object.h:307
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:209
#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.