Crossfire Server, Branch 1.12  R12190
c_range.c
Go to the documentation of this file.
00001 /*
00002  * static char *rcsid_c_range_c =
00003  *   "$Id: c_range.c 11578 2009-02-23 22:02:27Z lalo $";
00004  */
00005 
00006 /*
00007     CrossFire, A Multiplayer game for X-windows
00008 
00009     Copyright (C) 2006 Mark Wedel & Crossfire Development Team
00010     Copyright (C) 1992 Frank Tore Johansen
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00025 
00026     The authors can be reached via e-mail at crossfire-devel@real-time.com
00027 */
00028 
00034 #include <global.h>
00035 #ifndef __CEXTRACT__
00036 #include <sproto.h>
00037 #endif
00038 #include <spells.h>
00039 #include <skills.h>
00040 #include <newclient.h>
00041 #include <commands.h>
00042 
00053 int command_invoke(object *op, char *params) {
00054     return command_cast_spell(op, params, 'i');
00055 }
00056 
00067 int command_cast(object *op, char *params) {
00068     return command_cast_spell(op, params, 'c');
00069 }
00070 
00082 int command_prepare(object *op, char *params) {
00083     return command_cast_spell(op, params, 'p');
00084 }
00085 
00097 static void show_matching_spells(object *op, char *params) {
00098     object *spell;
00099     char spell_sort[NROFREALSPELLS][MAX_BUF], tmp[MAX_BUF], *cp;
00100     int num_found = 0, i;
00101 
00102     /* We go and see what spells the player has.  We put them
00103      * into the spell_sort array so that we can sort them -
00104      * we prefix the skill in the name so that the sorting
00105      * works better.
00106      */
00107     for (spell = op->inv; spell != NULL; spell = spell->below) {
00108         /* If it is a spell, and no params are passed, or they
00109          * match the name, process this spell.
00110          */
00111         if (spell->type == SPELL
00112         && (!params || !strncmp(params, spell->name, strlen(params)))) {
00113             if (spell->path_attuned&op->path_denied) {
00114                 snprintf(spell_sort[num_found++], sizeof(spell_sort[0]),
00115                          "%s:%-22s %3s %3s", spell->skill ? spell->skill : "generic",
00116                          spell->name, "den", "den");
00117             } else {
00118                 snprintf(spell_sort[num_found++], sizeof(spell_sort[0]),
00119                          "%s:%-22s %3d %3d", spell->skill ? spell->skill : "generic",
00120                          spell->name, spell->level,
00121                          SP_level_spellpoint_cost(op, spell, SPELL_HIGHEST));
00122             }
00123         }
00124     }
00125     if (!num_found) {
00126         /* If a matching string was passed along, now try it without that
00127          * string.  It is odd to do something like 'cast trans',
00128          * and it say you have no spells, when really, you do, but just
00129          * nothing that matches.
00130          */
00131         if (params)
00132             show_matching_spells(op, NULL);
00133         else
00134             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR,
00135                           "You know no spells", NULL);
00136     } else {
00137         /* Note in the code below that we make some
00138          * presumptions that there will be a colon in the
00139          * string.  given the code above, this is always
00140          * the case.
00141          */
00142         qsort(spell_sort, num_found, MAX_BUF, (int (*)(const void *, const void *))strcmp);
00143         strcpy(tmp, "asdfg"); /* Dummy string so initial compare fails */
00144         for (i = 0; i < num_found; i++) {
00145             /* Different skill name, so print banner */
00146             if (strncmp(tmp, spell_sort[i], strlen(tmp))) {
00147                 strcpy(tmp, spell_sort[i]);
00148                 cp = strchr(tmp, ':');
00149                 *cp = '\0';
00150 
00151                 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS,
00152                                      "\n[fixed]%s spells %.*s <lvl> <sp>",
00153                                      "\n%s spells %.*s <lvl> <sp>",
00154                                      tmp, 12-strlen(tmp), "              ");
00155             }
00156             draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS,
00157                                  "[fixed]%s",
00158                                  "%s",
00159                                  strchr(spell_sort[i], ':')+1);
00160         }
00161     }
00162 }
00163 
00178 int command_cast_spell(object *op, char *params, char command) {
00179     int castnow = 0;
00180     char *cp;
00181     object *spob;
00182 
00183     if (command == 'i')
00184         castnow = 1;
00185 
00186     if (params != NULL) {
00187         tag_t spellnumber = 0;
00188         if ((spellnumber = atoi(params)) != 0)
00189             for (spob = op->inv; spob && spob->count != spellnumber; spob = spob->below)
00190                 ;
00191         else
00192             spob = lookup_spell_by_name(op, params);
00193 
00194         if (spob && spob->type == SPELL) {
00195             /* Now grab any extra data, if there is any.  Forward pass
00196              * any 'of' delimiter
00197              */
00198             if (spellnumber) {
00199                 /* if we passed a number, the options start at the second word */
00200                 cp = strchr(params, ' ');
00201                 if (cp) {
00202                     cp++;
00203                     if (!strncmp(cp, "of ", 3))
00204                         cp += 3;
00205                 }
00206             } else if (strlen(params) > strlen(spob->name)) {
00207                 cp = params+strlen(spob->name);
00208                 *cp = 0;
00209                 cp++;
00210                 if (!strncmp(cp, "of ", 3))
00211                     cp += 3;
00212             } else
00213                 cp = NULL;
00214 
00215             if (spob->skill && !find_skill_by_name(op, spob->skill)) {
00216                 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SKILL, MSG_TYPE_SKILL_MISSING,
00217                                      "You need the skill %s to cast %s!",
00218                                      "You need the skill %s to cast %s!",
00219                                      spob->skill, spob->name);
00220                 return 1;
00221             }
00222 
00223             /* Remove control of the golem */
00224             if (op->contr->ranges[range_golem] != NULL) {
00225                 if (op->contr->golem_count == op->contr->ranges[range_golem]->count) {
00226                     remove_friendly_object(op->contr->ranges[range_golem]);
00227                     remove_ob(op->contr->ranges[range_golem]);
00228                     free_object(op->contr->ranges[range_golem]);
00229                 }
00230                 op->contr->ranges[range_golem] = NULL;
00231                 op->contr->golem_count = 0;
00232             }
00233 
00234             if (castnow) {
00235                 cast_spell(op, op, op->facing, spob, cp);
00236             } else {
00237                 op->contr->ranges[range_magic] = spob;
00238                 op->contr->shoottype = range_magic;
00239                 if (cp != NULL) {
00240                     strncpy(op->contr->spellparam, cp, MAX_BUF);
00241                     op->contr->spellparam[MAX_BUF-1] = '\0';
00242                 } else {
00243                     op->contr->spellparam[0] = '\0';
00244                 }
00245                 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS,
00246                                      "You ready the spell %s",
00247                                      "You ready the spell %s",
00248                                      spob->name);
00249             }
00250             return 0;
00251         } /* else fall through to below and print spells */
00252     } /* params supplied */
00253 
00254     /* We get here if cast was given without options or we could not find
00255      * the requested spell.  List all the spells the player knows.
00256      */
00257     draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR,
00258                   "Cast what spell?  Choose one of:", NULL);
00259     show_matching_spells(op, params);
00260     return 1;
00261 }
00262 
00263 /**************************************************************************/
00264 
00282 int legal_range(object *op, int r) {
00283 
00284     switch (r) {
00285     case range_none: /* "Nothing" is always legal */
00286         return 1;
00287 
00288     case range_bow:
00289     case range_misc:
00290     case range_magic: /* cast spells */
00291         if (op->contr->ranges[r])
00292             return 1;
00293         else
00294             return 0;
00295 
00296     case range_golem: /* Use scrolls */
00297         if (op->contr->ranges[range_golem]
00298         && op->contr->ranges[range_golem]->count == op->contr->golem_count)
00299             return 1;
00300         else
00301             return 0;
00302 
00303     case range_skill:
00304         if (op->chosen_skill)
00305             return 1;
00306         else
00307             return 0;
00308     }
00309     /* No match above, must not be valid */
00310     return 0;
00311 }
00312 
00321 void change_spell(object *op, char k) {
00322 
00323     char name[MAX_BUF];
00324 
00325     do {
00326         op->contr->shoottype += ((k == '+') ? 1 : -1);
00327         if (op->contr->shoottype >= range_size)
00328             op->contr->shoottype = range_none;
00329         else if (op->contr->shoottype <= range_bottom)
00330             op->contr->shoottype = (rangetype)(range_size-1);
00331     } while (!legal_range(op, op->contr->shoottype));
00332 
00333     /* Legal range has already checked that we have an appropriate item
00334      * that uses the slot, so we don't need to be too careful about
00335      * checking the status of the object.
00336      */
00337     switch (op->contr->shoottype) {
00338     case range_none:
00339         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR,
00340                       "No ranged attack chosen.", NULL);
00341         break;
00342 
00343     case range_golem:
00344         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS,
00345                       "You regain control of your golem.", NULL);
00346         break;
00347 
00348     case range_bow:
00349         query_name(op->contr->ranges[range_bow], name, MAX_BUF);
00350         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS,
00351                              "Switched to %s and %s.",
00352                              "Switched to %s and %s.",
00353                              name,
00354                              op->contr->ranges[range_bow]->race ? op->contr->ranges[range_bow]->race : "nothing");
00355         break;
00356 
00357     case range_magic:
00358         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS,
00359                              "Switched to spells (%s).",
00360                              "Switched to spells (%s).",
00361                              op->contr->ranges[range_magic]->name);
00362         break;
00363 
00364     case range_misc:
00365         query_base_name(op->contr->ranges[range_misc], 0, name, MAX_BUF);
00366         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS,
00367                              "Switched to %s.",
00368                              "Switched to %s.",
00369                              name);
00370         break;
00371 
00372     case range_skill:
00373         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS,
00374                              "Switched to skill: %s",
00375                              "Switched to skill: %s",
00376                              op->chosen_skill ? op->chosen_skill->name : "none");
00377         break;
00378 
00379     default:
00380         break;
00381     }
00382 }
00383 
00394 int command_rotateshoottype(object *op, char *params) {
00395     if (!params)
00396         change_spell(op, '+');
00397     else
00398         change_spell(op, params[0]);
00399     return 0;
00400 }