Crossfire Server, Trunk
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) {
40 }
41 
50 void command_cast(object *op, const char *params) {
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) {
190  remove_friendly_object(op->contr->ranges[range_golem]);
191  object_remove(op->contr->ranges[range_golem]);
192  object_free_drop_inventory(op->contr->ranges[range_golem]);
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  if (op->contr->ranges[r])
256  return 1;
257  else
258  return 0;
259 
260  case range_golem: /* Use scrolls */
261  if (op->contr->ranges[range_golem]
262  && op->contr->ranges[range_golem]->count == op->contr->golem_count)
263  return 1;
264  else
265  return 0;
266 
267  case range_skill:
268  if (op->chosen_skill)
269  return 1;
270  else
271  return 0;
272  }
273  /* No match above, must not be valid */
274  return 0;
275 }
276 
285 static void change_spell(object *op, char k) {
286  char name[MAX_BUF];
287 
288  do {
289  op->contr->shoottype = static_cast<rangetype>((static_cast<int>(op->contr->shoottype) + ((k == '+') ? 1 : -1)));
290  if (op->contr->shoottype >= range_size)
291  op->contr->shoottype = range_none;
292  else if (op->contr->shoottype <= range_bottom)
293  op->contr->shoottype = (rangetype)(range_size-1);
294  } while (!legal_range(op, op->contr->shoottype));
295 
296  /* Legal range has already checked that we have an appropriate item
297  * that uses the slot, so we don't need to be too careful about
298  * checking the status of the object.
299  */
300  switch (op->contr->shoottype) {
301  case range_none:
303  "No ranged attack chosen.");
304  break;
305 
306  case range_golem:
308  "You regain control of your golem.");
309  break;
310 
311  case range_bow:
312  query_name(op->contr->ranges[range_bow], name, MAX_BUF);
314  "Switched to %s and %s.",
315  name,
316  op->contr->ranges[range_bow]->race ? op->contr->ranges[range_bow]->race : "nothing");
317  break;
318 
319  case range_magic:
321  "Switched to spells (%s).",
322  op->contr->ranges[range_magic]->name);
323  break;
324 
325  case range_misc:
326  query_base_name(op->contr->ranges[range_misc], 0, name, MAX_BUF);
328  "Switched to %s.",
329  name);
330  break;
331 
332  case range_skill:
334  "Switched to skill: %s",
335  op->chosen_skill ? op->chosen_skill->name : "none");
336  break;
337 
338  default:
339  break;
340  }
341 }
342 
351 void command_rotateshoottype(object *op, const char *params) {
352  if (*params == '\0')
353  change_spell(op, '+');
354  else
355  change_spell(op, params[0]);
356 }
global.h
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
remove_friendly_object
void remove_friendly_object(object *op)
Definition: friend.cpp:52
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:519
NROFREALSPELLS
#define NROFREALSPELLS
Definition: spells.h:48
range_bow
@ range_bow
Definition: player.h:31
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Definition: newclient.h:396
cast_spell
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Definition: spell_util.cpp:1424
range_none
@ range_none
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
Ice.tmp
int tmp
Definition: Ice.py:207
skills.h
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:518
range_golem
@ range_golem
Definition: player.h:34
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4342
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:393
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1560
show_matching_spells
static void show_matching_spells(object *op, const char *params)
Definition: c_range.cpp:65
command_cast_spell
void command_cast_spell(object *op, const char *params, int cast_now)
Definition: c_range.cpp:146
range_size
@ range_size
Definition: player.h:37
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.cpp:588
range_magic
@ range_magic
Definition: player.h:32
lookup_spell_by_name
object * lookup_spell_by_name(object *op, const char *spname)
Definition: spell_util.cpp:410
SPELL_HIGHEST
#define SPELL_HIGHEST
Definition: spells.h:60
object::type
uint8_t type
Definition: object.h:348
object_find_by_tag
object * object_find_by_tag(const object *who, tag_t tag)
Definition: object.cpp:4056
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
MSG_TYPE_SKILL_MISSING
#define MSG_TYPE_SKILL_MISSING
Definition: newclient.h:576
range_bottom
@ range_bottom
Definition: player.h:29
rangetype
rangetype
Definition: player.h:28
tag_t
uint32_t tag_t
Definition: object.h:14
sproto.h
SP_level_spellpoint_cost
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Definition: spell_util.cpp:236
make_face_from_files.required
required
Definition: make_face_from_files.py:31
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.cpp:211
MAX_BUF
#define MAX_BUF
Definition: define.h:35
legal_range
int legal_range(object *op, int r)
Definition: c_range.cpp:247
range_misc
@ range_misc
Definition: player.h:33
command_invoke
void command_invoke(object *op, const char *params)
Definition: c_range.cpp:38
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:251
spells.h
object::name
sstring name
Definition: object.h:319
sstring
const typedef char * sstring
Definition: sstring.h:2
give.op
op
Definition: give.py:33
object::skill
sstring skill
Definition: object.h:329
roll-o-matic.params
params
Definition: roll-o-matic.py:193
newclient.h
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.cpp:308
object_remove
void object_remove(object *op)
Definition: object.cpp:1833
commands.h
command_cast
void command_cast(object *op, const char *params)
Definition: c_range.cpp:50
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.cpp:689
range_skill
@ range_skill
Definition: player.h:35
command_rotateshoottype
void command_rotateshoottype(object *op, const char *params)
Definition: c_range.cpp:351
SPELL
@ SPELL
Definition: object.h:219
change_spell
static void change_spell(object *op, char k)
Definition: c_range.cpp:285
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
ring_occidental_mages.r
r
Definition: ring_occidental_mages.py:6
give.name
name
Definition: give.py:27