Crossfire Server, Trunk  R20513
c_range.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 
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, 'i');
40 }
41 
50 void command_cast(object *op, const char *params) {
51  command_cast_spell(op, params, 'c');
52 }
53 
63 void command_prepare(object *op, const char *params) {
64  command_cast_spell(op, params, 'p');
65 }
66 
78 static void show_matching_spells(object *op, const char *params) {
79  char spell_sort[NROFREALSPELLS][MAX_BUF], tmp[MAX_BUF], *cp;
80  int num_found = 0, i;
81 
82  /* We go and see what spells the player has. We put them
83  * into the spell_sort array so that we can sort them -
84  * we prefix the skill in the name so that the sorting
85  * works better.
86  */
87  FOR_INV_PREPARE(op, spell) {
88  /* If it is a spell, and no params are passed, or they
89  * match the name, process this spell.
90  */
91  if (spell->type == SPELL
92  && (*params == '\0' || !strncmp(params, spell->name, strlen(params)))) {
93  if (spell->path_attuned&op->path_denied) {
94  snprintf(spell_sort[num_found++], sizeof(spell_sort[0]),
95  "%s:%-22s %3s %3s", spell->skill ? spell->skill : "generic",
96  spell->name, "den", "den");
97  } else {
98  snprintf(spell_sort[num_found++], sizeof(spell_sort[0]),
99  "%s:%-22s %3d %3d", spell->skill ? spell->skill : "generic",
100  spell->name, spell->level,
102  }
103  }
104  } FOR_INV_FINISH();
105  if (!num_found) {
106  if (*params != '\0')
108  "You know no spells like '%s'.", params);
109  else
111  "You know no spells.");
112 
113  return;
114  }
115 
116  if (*params != '\0')
118  "You know the following '%s' spells:", params);
119  else
121  "You know the following spells:");
122 
123  /* Note in the code below that we make some
124  * presumptions that there will be a colon in the
125  * string. given the code above, this is always
126  * the case.
127  */
128  qsort(spell_sort, num_found, MAX_BUF, (int (*)(const void *, const void *))strcmp);
129  strcpy(tmp, "asdfg"); /* Dummy string so initial compare fails */
130  for (i = 0; i < num_found; i++) {
131  /* Different skill name, so print banner */
132  if (strncmp(tmp, spell_sort[i], strlen(tmp))) {
133  strcpy(tmp, spell_sort[i]);
134  cp = strchr(tmp, ':');
135  *cp = '\0';
136 
138  "\n[fixed]%s spells %.*s <lvl> <sp>",
139  tmp, (int)(12-strlen(tmp)), " ");
140  }
142  "[fixed]%s",
143  strchr(spell_sort[i], ':')+1);
144  }
145 }
146 
159 void command_cast_spell(object *op, const char *params, char command) {
160  int castnow = 0;
161  char *cp, cpy[MAX_BUF];
162  object *spob;
163 
164  safe_strncpy(cpy, params, sizeof(cpy));
165 
166  if (command == 'i')
167  castnow = 1;
168 
169  if (*cpy != '\0') {
170  tag_t spellnumber = 0;
171  if ((spellnumber = atoi(cpy)) != 0)
172  spob = object_find_by_tag(op, spellnumber);
173  else
174  spob = lookup_spell_by_name(op, cpy);
175 
176  if (spob && spob->type == SPELL) {
177  /* Now grab any extra data, if there is any. Forward pass
178  * any 'of' delimiter
179  */
180  if (spellnumber) {
181  /* if we passed a number, the options start at the second word */
182  cp = strchr(cpy, ' ');
183  if (cp) {
184  cp++;
185  if (!strncmp(cp, "of ", 3))
186  cp += 3;
187  }
188  } else if (strlen(cpy) > strlen(spob->name)) {
189  cp = cpy+strlen(spob->name);
190  *cp = 0;
191  cp++;
192  if (!strncmp(cp, "of ", 3))
193  cp += 3;
194  } else
195  cp = NULL;
196 
197  if (spob->skill && !find_skill_by_name(op, spob->skill)) {
199  "You need the skill %s to cast %s!",
200  spob->skill, spob->name);
201  return;
202  }
203 
204  /* Remove control of the golem */
205  if (op->contr->ranges[range_golem] != NULL) {
206  if (op->contr->golem_count == op->contr->ranges[range_golem]->count) {
210  }
211  op->contr->ranges[range_golem] = NULL;
212  op->contr->golem_count = 0;
213  }
214 
215  /* This assignment is need for casting_time logic */
216  op->spell = spob;
217  if (castnow) {
218  cast_spell(op, op, op->facing, spob, cp);
219  } else {
221  sstring required = object_get_value(spob, "casting_requirements");
222  op->contr->ranges[range_magic] = spob;
223  op->contr->shoottype = range_magic;
224 
225  if (cp != NULL) {
226  strncpy(op->contr->spellparam, cp, MAX_BUF);
227  op->contr->spellparam[MAX_BUF-1] = '\0';
228  } else {
229  op->contr->spellparam[0] = '\0';
230  }
232  "You ready the spell %s%s%s",
233  spob->name, required ? " which consumes for each invocation " : "", required ? required : "");
234  }
235  return;
236  } /* else fall through to below and print spells */
237  } /* params supplied */
238 
239  /* We get here if cast was given without options or we could not find
240  * the requested spell. List all the spells the player knows.
241  */
242  show_matching_spells(op, cpy);
243 }
244 
245 /**************************************************************************/
246 
264 int legal_range(object *op, int r) {
265  switch (r) {
266  case range_none: /* "Nothing" is always legal */
267  return 1;
268 
269  case range_bow:
270  case range_misc:
271  case range_magic: /* cast spells */
272  if (op->contr->ranges[r])
273  return 1;
274  else
275  return 0;
276 
277  case range_golem: /* Use scrolls */
278  if (op->contr->ranges[range_golem]
279  && op->contr->ranges[range_golem]->count == op->contr->golem_count)
280  return 1;
281  else
282  return 0;
283 
284  case range_skill:
285  if (op->chosen_skill)
286  return 1;
287  else
288  return 0;
289  }
290  /* No match above, must not be valid */
291  return 0;
292 }
293 
302 static void change_spell(object *op, char k) {
303  char name[MAX_BUF];
304 
305  do {
306  op->contr->shoottype += ((k == '+') ? 1 : -1);
307  if (op->contr->shoottype >= range_size)
308  op->contr->shoottype = range_none;
309  else if (op->contr->shoottype <= range_bottom)
310  op->contr->shoottype = (rangetype)(range_size-1);
311  } while (!legal_range(op, op->contr->shoottype));
312 
313  /* Legal range has already checked that we have an appropriate item
314  * that uses the slot, so we don't need to be too careful about
315  * checking the status of the object.
316  */
317  switch (op->contr->shoottype) {
318  case range_none:
320  "No ranged attack chosen.");
321  break;
322 
323  case range_golem:
325  "You regain control of your golem.");
326  break;
327 
328  case range_bow:
329  query_name(op->contr->ranges[range_bow], name, MAX_BUF);
331  "Switched to %s and %s.",
332  name,
333  op->contr->ranges[range_bow]->race ? op->contr->ranges[range_bow]->race : "nothing");
334  break;
335 
336  case range_magic:
338  "Switched to spells (%s).",
339  op->contr->ranges[range_magic]->name);
340  break;
341 
342  case range_misc:
343  query_base_name(op->contr->ranges[range_misc], 0, name, MAX_BUF);
345  "Switched to %s.",
346  name);
347  break;
348 
349  case range_skill:
351  "Switched to skill: %s",
352  op->chosen_skill ? op->chosen_skill->name : "none");
353  break;
354 
355  default:
356  break;
357  }
358 }
359 
368 void command_rotateshoottype(object *op, const char *params) {
369  if (*params == '\0')
370  change_spell(op, '+');
371  else
372  change_spell(op, params[0]);
373 }
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
Use skill.
Definition: player.h:22
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.c:451
void command_cast_spell(object *op, const char *params, char command)
Sets up to cast a spell.
Definition: c_range.c:159
Spell-related defines: spellpath, subtypes, ...
const char * race
Human, goblin, dragon, etc.
Definition: object.h:318
void command_cast(object *op, const char *params)
&#39;cast&#39; command, prepares a spell for laster casting.
Definition: c_range.c:50
char spellparam[MAX_BUF]
What param to add to spells.
Definition: player.h:100
Defines various flags that both the new client and new server use.
void command_invoke(object *op, const char *params)
&#39;invoke&#39; command, fires a spell immediately.
Definition: c_range.c:38
No range selected.
Definition: player.h:17
void command_prepare(object *op, const char *params)
Equivalent to command_cast().
Definition: c_range.c:63
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.c:4246
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.c:722
rangetype shoottype
Which range-attack is being used by player.
Definition: player.h:99
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 MSG_TYPE_SKILL_MISSING
Don&#39;t have the skill.
Definition: newclient.h:582
object * ranges[range_size]
Object for each range.
Definition: player.h:103
int legal_range(object *op, int r)
Check for the validity of a player range.
Definition: c_range.c:264
Misc items.
Definition: player.h:20
void remove_friendly_object(object *op)
Removes the specified object from the linked list of friendly objects.
Definition: friend.c:56
Global type definitions and header inclusions.
#define safe_strncpy
Definition: compat.h:23
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
Minimum, exclusive, value.
Definition: player.h:16
#define NROFREALSPELLS
Number of spells.
Definition: spells.h:48
struct obj * chosen_skill
The skill chosen to use.
Definition: object.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.c:1368
#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
struct obj * spell
Spell that was being cast.
Definition: object.h:408
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:510
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can&#39;t use command.
Definition: newclient.h:509
static void change_spell(object *op, char k)
Rotate the selected range attack.
Definition: c_range.c:302
#define snprintf
Definition: win32.h:46
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:712
Control golem.
Definition: player.h:21
void command_rotateshoottype(object *op, const char *params)
&#39;rotateshoottype&#39; command, switch range attack.
Definition: c_range.c:368
const char * name
The name of the object, obviously...
Definition: object.h:311
struct pl * contr
Pointer to the player which control this object.
Definition: object.h:276
Defines and structures related to commands the player can send.
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:12
See Spell.
Definition: object.h:214
uint32_t golem_count
To track the golem.
Definition: player.h:106
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
const char * skill
Name of the skill this object uses/grants.
Definition: object.h:321
Skill-related defines, including subtypes.
object * object_find_by_tag(const object *who, tag_t tag)
Find object in inventory.
Definition: object.c:3951
const char * sstring
Strings that should be manipulated through add_string() and free_string().
Definition: global.h:40
Maximum, exclusive, value.
Definition: player.h:24
tag_t count
Unique object number for this object.
Definition: object.h:299
#define SPELL_HIGHEST
Definition: spells.h:60
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
rangetype
What range is currently selected by the player.
Definition: player.h:15
Bow.
Definition: player.h:18
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:383
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
static void show_matching_spells(object *op, const char *params)
Shows all spells that op knows.
Definition: c_range.c:78
Spells.
Definition: player.h:19
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.c:625
int8_t facing
Object is oriented/facing that way.
Definition: object.h:335
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.c:213
#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