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  */
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:4337
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:393
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_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1555
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:592
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:4051
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()
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
object_remove
void object_remove(object *op)
Definition: object.cpp:1828
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:693
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