Crossfire Server, Branch 1.12
R12190
|
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 }