|
Atrinik Server 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00030 #include <global.h> 00031 00035 archetype *spellarch[NROFREALSPELLS]; 00036 00039 void init_spells() 00040 { 00041 static int init_spells_done = 0; 00042 int i; 00043 FILE *fp; 00044 char filename[MAX_BUF]; 00045 00046 if (init_spells_done) 00047 { 00048 return; 00049 } 00050 00051 LOG(llevDebug, "Initializing spells... "); 00052 init_spells_done = 1; 00053 00054 snprintf(filename, sizeof(filename), "%s/%s", settings.localdir, SRV_FILE_SPELLS_FILENAME); 00055 fp = fopen(filename, "w"); 00056 00057 if (!fp) 00058 { 00059 LOG(llevError, "Cannot open file '%s' for writing.\n", filename); 00060 } 00061 00062 for (i = 0; i < NROFREALSPELLS; i++) 00063 { 00064 char spellname[MAX_BUF], tmpresult[MAX_BUF]; 00065 archetype *at; 00066 00067 replace(spells[i].name, " ", "_", tmpresult, sizeof(spellname)); 00068 snprintf(spellname, sizeof(spellname), "spell_%s", tmpresult); 00069 00070 if ((at = find_archetype(spellname))) 00071 { 00072 object *tmp = arch_to_object(at); 00073 const char *value; 00074 00075 if ((value = object_get_value(tmp, "spell_type"))) 00076 { 00077 spells[i].type = !strcmp(value, "wizard") ? SPELL_TYPE_WIZARD : SPELL_TYPE_PRIEST; 00078 } 00079 00080 if ((value = object_get_value(tmp, "spell_level"))) 00081 { 00082 spells[i].level = atoi(value); 00083 } 00084 00085 if ((value = object_get_value(tmp, "spell_cost"))) 00086 { 00087 spells[i].sp = atoi(value); 00088 } 00089 00090 if ((value = object_get_value(tmp, "spell_time"))) 00091 { 00092 spells[i].time = atoi(value); 00093 } 00094 00095 if ((value = object_get_value(tmp, "spell_range"))) 00096 { 00097 spells[i].range = atoi(value); 00098 } 00099 00100 if ((value = object_get_value(tmp, "spell_bdam"))) 00101 { 00102 spells[i].bdam = atoi(value); 00103 } 00104 00105 if ((value = object_get_value(tmp, "spell_bdur"))) 00106 { 00107 spells[i].bdur = atoi(value); 00108 } 00109 00110 if ((value = object_get_value(tmp, "spell_ldam"))) 00111 { 00112 spells[i].ldam = atoi(value); 00113 } 00114 00115 if ((value = object_get_value(tmp, "spell_ldur"))) 00116 { 00117 spells[i].ldur = atoi(value); 00118 } 00119 00120 if ((value = object_get_value(tmp, "spell_spl"))) 00121 { 00122 spells[i].spl = atoi(value); 00123 } 00124 00125 if ((value = object_get_value(tmp, "spell_archname"))) 00126 { 00127 spells[i].archname = strdup_local(value); 00128 } 00129 } 00130 00131 if (spells[i].archname) 00132 { 00133 if ((spellarch[i] = find_archetype(spells[i].archname)) == NULL) 00134 { 00135 LOG(llevError, "Spell %s needs arch %s, your archetypes file is out of date.\n", spells[i].name, spells[i].archname); 00136 } 00137 } 00138 else 00139 { 00140 spellarch[i] = NULL; 00141 } 00142 00143 if (spells[i].icon) 00144 { 00145 if (!find_face(spells[i].icon, 0)) 00146 { 00147 LOG(llevError, "Spell '%s' needs face '%s', but it could not be found.\n", spells[i].name, spells[i].icon); 00148 } 00149 } 00150 00151 if (spells[i].icon && spells[i].description) 00152 { 00153 int j; 00154 00155 for (j = 0; j < NRSPELLPATHS; j++) 00156 { 00157 if (spells[i].path & (1 << j)) 00158 { 00159 fprintf(fp, "%s\n%d\n%d\n%s\n%s\nend\n", spells[i].name, spells[i].type, j, spells[i].icon, spells[i].description); 00160 break; 00161 } 00162 } 00163 } 00164 } 00165 00166 fclose(fp); 00167 LOG(llevDebug, "done.\n"); 00168 } 00169 00172 void dump_spells() 00173 { 00174 int i; 00175 00176 for (i = 0; i < NROFREALSPELLS; i++) 00177 { 00178 if (!settings.dumparg) 00179 { 00180 const char *name1 = NULL, *name2 = NULL; 00181 00182 if (spellarch[i]) 00183 { 00184 name1 = spellarch[i]->name; 00185 00186 if (spellarch[i]->clone.other_arch) 00187 { 00188 name2 = spellarch[i]->clone.other_arch->name; 00189 } 00190 } 00191 00192 LOG(llevInfo, "%d: %s: %s: %s\n", i, spells[i].name, (name1 ? name1 : "null"), (name2 ? name2 : "null")); 00193 } 00194 else if (!strcmp(settings.dumparg, "all") || !strcmp(settings.dumparg, spells[i].name)) 00195 { 00196 int j; 00197 object *caster, *tmp = NULL; 00198 00199 LOG(llevInfo, "Information about '%s' (ID: %d):\n", spells[i].name, i); 00200 caster = get_object(); 00201 00202 if (spellarch[i]) 00203 { 00204 tmp = arch_to_object(spellarch[i]); 00205 } 00206 00207 for (j = 1; j <= MAXLEVEL; j++) 00208 { 00209 caster->level = j; 00210 LOG(llevInfo, " Level: %3d, Mana: %4d, Dam: %4d, Dam2: %4d\n", j, SP_level_spellpoint_cost(caster, i, -1), SP_level_dam_adjust(caster, i, -1, 1), tmp ? SP_level_dam_adjust(caster, i, tmp->stats.dam, 1) : 0); 00211 } 00212 00213 if (strcmp(settings.dumparg, "all")) 00214 { 00215 exit(0); 00216 } 00217 } 00218 } 00219 } 00220 00229 int insert_spell_effect(char *archname, mapstruct *m, int x, int y) 00230 { 00231 archetype *effect_arch; 00232 object *effect_ob; 00233 00234 if (!archname || !m) 00235 { 00236 LOG(llevBug, "insert_spell_effect(): archname or map NULL.\n"); 00237 return 1; 00238 } 00239 00240 if (!(effect_arch = find_archetype(archname))) 00241 { 00242 LOG(llevBug, "insert_spell_effect(): Couldn't find effect arch (%s).\n", archname); 00243 return 1; 00244 } 00245 00246 /* Prepare effect */ 00247 effect_ob = arch_to_object(effect_arch); 00248 effect_ob->map = m; 00249 effect_ob->x = x; 00250 effect_ob->y = y; 00251 00252 if (!insert_ob_in_map(effect_ob, m, NULL, 0)) 00253 { 00254 LOG(llevBug, "insert_spell_effect(): effect arch (%s) out of map (%s) (%d,%d) or failed insertion.\n", archname, effect_ob->map->name, x, y); 00255 00256 /* Something is wrong - kill object */ 00257 if (!QUERY_FLAG(effect_ob, FLAG_REMOVED)) 00258 { 00259 remove_ob(effect_ob); 00260 check_walk_off(effect_ob, NULL, MOVE_APPLY_VANISHED); 00261 } 00262 00263 return 1; 00264 } 00265 00266 return 0; 00267 } 00268 00273 spell_struct *find_spell(int spelltype) 00274 { 00275 if (spelltype < 0 || spelltype >= NROFREALSPELLS) 00276 { 00277 return NULL; 00278 } 00279 00280 return &spells[spelltype]; 00281 } 00282 00288 int check_spell_known(object *op, int spell_type) 00289 { 00290 int i; 00291 00292 for (i = 0; i < CONTR(op)->nrofknownspells; i++) 00293 { 00294 if (CONTR(op)->known_spells[i] == spell_type) 00295 { 00296 return 1; 00297 } 00298 } 00299 00300 return 0; 00301 } 00302 00317 int cast_spell(object *op, object *caster, int dir, int type, int ability, int item, const char *stringarg) 00318 { 00319 spell_struct *s = find_spell(type); 00320 shstr *godname = NULL; 00321 object *target = NULL; 00322 int success = 0, duration, spell_cost = 0; 00323 00324 if (!s) 00325 { 00326 LOG(llevBug, "cast_spell(): Unknown spell: %d\n", type); 00327 return 0; 00328 } 00329 00330 /* Get the base duration */ 00331 duration = spells[type].bdur; 00332 00333 if (!op) 00334 { 00335 op = caster; 00336 } 00337 00338 /* Script NPCs can ALWAYS cast - even in no spell areas! */ 00339 if (item == CAST_NPC) 00340 { 00341 /* If CAST_NPC, this usually comes from a script, 00342 * and caster is the NPC and op the target. */ 00343 target = op; 00344 op = caster; 00345 } 00346 else 00347 { 00348 /* It looks like the only properties we ever care about from the casting 00349 * object (caster) is spell paths and level. */ 00350 object *cast_op = op; 00351 MapSpace *msp; 00352 00353 if (!caster) 00354 { 00355 if (item == CAST_NORMAL) 00356 { 00357 caster = op; 00358 } 00359 } 00360 else 00361 { 00362 /* Caster has a map? Then we use caster */ 00363 if (caster->map) 00364 { 00365 cast_op = caster; 00366 } 00367 } 00368 00369 /* No magic and not a prayer. */ 00370 if (MAP_NOMAGIC(cast_op->map) && spells[type].type == SPELL_TYPE_WIZARD) 00371 { 00372 new_draw_info(0, COLOR_WHITE, op, "Powerful countermagic cancels all spellcasting here!"); 00373 return 0; 00374 } 00375 00376 /* No prayer and a prayer. */ 00377 if (MAP_NOPRIEST(cast_op->map) && spells[type].type == SPELL_TYPE_PRIEST) 00378 { 00379 new_draw_info(0, COLOR_WHITE, op, "Powerful countermagic cancels all prayer spells here!"); 00380 return 0; 00381 } 00382 00383 msp = GET_MAP_SPACE_PTR(cast_op->map, cast_op->x, cast_op->y); 00384 00385 /* No harm spell and not town safe. */ 00386 if ((MAP_NOHARM(cast_op->map) || (msp->extra_flags & MSP_EXTRA_NO_HARM)) && !(MAP_NOHARM(cast_op->map) && (msp->extra_flags & MSP_EXTRA_NO_HARM)) && !(spells[type].flags & SPELL_DESC_TOWN)) 00387 { 00388 new_draw_info(0, COLOR_WHITE, op, "Powerful countermagic cancels all harmful magic here!"); 00389 return 0; 00390 } 00391 00392 if (op->type == PLAYER) 00393 { 00394 CONTR(op)->praying = 0; 00395 00396 /* Cancel player spells which are denied, but only real spells (not 00397 * potions, wands, etc). */ 00398 if (item == CAST_NORMAL) 00399 { 00400 if (caster->path_denied & s->path) 00401 { 00402 new_draw_info(0, COLOR_WHITE, op, "It is denied for you to cast that spell."); 00403 return 0; 00404 } 00405 00406 if (!(QUERY_FLAG(op, FLAG_WIZ))) 00407 { 00408 if (spells[type].type == SPELL_TYPE_WIZARD && op->stats.sp < SP_level_spellpoint_cost(caster, type, -1)) 00409 { 00410 new_draw_info(0, COLOR_WHITE, op, "You don't have enough mana."); 00411 return 0; 00412 } 00413 00414 if (spells[type].type == SPELL_TYPE_PRIEST && op->stats.grace < SP_level_spellpoint_cost(caster, type, -1)) 00415 { 00416 new_draw_info(0, COLOR_WHITE, op, "You don't have enough grace."); 00417 return 0; 00418 } 00419 } 00420 } 00421 00422 /* If it a prayer, grab the player's god - if we have none, we 00423 * can't cast, except for potions. */ 00424 if (spells[type].type == SPELL_TYPE_PRIEST && item != CAST_POTION) 00425 { 00426 if ((godname = determine_god(op)) == shstr_cons.none) 00427 { 00428 new_draw_info(0, COLOR_WHITE, op, "You need a deity to cast a prayer!"); 00429 return 0; 00430 } 00431 } 00432 } 00433 00434 /* If it is an ability, assume that the designer of the archetype 00435 * knows what they are doing. */ 00436 if (item == CAST_NORMAL && !ability && SK_level(caster) < s->level && !QUERY_FLAG(op, FLAG_WIZ)) 00437 { 00438 new_draw_info(0, COLOR_WHITE, op, "You lack enough skill to cast that spell."); 00439 return 0; 00440 } 00441 00442 if (item == CAST_POTION) 00443 { 00444 /* If the potion casts a self spell, don't use the facing 00445 * direction. */ 00446 if (spells[type].flags & SPELL_DESC_SELF) 00447 { 00448 target = op; 00449 dir = 0; 00450 } 00451 } 00452 else if (find_target_for_spell(op, &target, spells[type].flags) == 0) 00453 { 00454 new_draw_info_format(0, COLOR_WHITE, op, "You can't cast that spell on %s!", target ? target->name : "yourself"); 00455 return 0; 00456 } 00457 00458 /* If valid target is not in range for selected spell, skip casting. */ 00459 if (target) 00460 { 00461 rv_vector rv; 00462 00463 if (!get_rangevector_from_mapcoords(op->map, op->x, op->y, target->map, target->x, target->y, &rv, RV_DIAGONAL_DISTANCE) || rv.distance > (unsigned int) spells[type].range) 00464 { 00465 new_draw_info(0, COLOR_WHITE, op, "Your target is out of range!"); 00466 return 0; 00467 } 00468 } 00469 00470 if (op->type == PLAYER && target == op && CONTR(op)->target_object != op) 00471 { 00472 new_draw_info(0, COLOR_WHITE, op, "You auto-target yourself with this spell!"); 00473 } 00474 00475 if (!ability && ((s->type == SPELL_TYPE_WIZARD && blocks_magic(op->map, op->x, op->y)) || (s->type == SPELL_TYPE_PRIEST && blocks_cleric(op->map, op->x, op->y)))) 00476 { 00477 if (op->type != PLAYER) 00478 { 00479 return 0; 00480 } 00481 00482 if (s->type == SPELL_TYPE_PRIEST) 00483 { 00484 new_draw_info_format(0, COLOR_WHITE, op, "This ground is unholy! %s ignores you.", godname); 00485 } 00486 else 00487 { 00488 switch (CONTR(op)->shoottype) 00489 { 00490 case range_magic: 00491 new_draw_info(0, COLOR_WHITE, op, "Something blocks your spellcasting."); 00492 break; 00493 00494 case range_wand: 00495 new_draw_info(0, COLOR_WHITE, op, "Something blocks the magic of your wand."); 00496 break; 00497 00498 case range_rod: 00499 new_draw_info(0, COLOR_WHITE, op, "Something blocks the magic of your rod."); 00500 break; 00501 00502 case range_horn: 00503 new_draw_info(0, COLOR_WHITE, op, "Something blocks the magic of your horn."); 00504 break; 00505 00506 case range_scroll: 00507 new_draw_info(0, COLOR_WHITE, op, "Something blocks the magic of your scroll."); 00508 break; 00509 00510 default: 00511 break; 00512 } 00513 } 00514 00515 return 0; 00516 } 00517 00518 if (item == CAST_NORMAL && op->type == PLAYER) 00519 { 00520 /* Chance to fumble the spell by too low wisdom. */ 00521 if (s->type == SPELL_TYPE_PRIEST && rndm(0, 99) < s->level / (float) MAX(1, op->chosen_skill->level) * cleric_chance[op->stats.Wis]) 00522 { 00523 play_sound_player_only(CONTR(op), CMD_SOUND_EFFECT, "missspell.ogg", 0, 0, 0, 0); 00524 new_draw_info(0, COLOR_WHITE, op, "You fumble the prayer because your wisdom is low."); 00525 00526 /* Shouldn't happen... */ 00527 if (s->sp == 0) 00528 { 00529 return 0; 00530 } 00531 00532 return rndm(1, SP_level_spellpoint_cost(caster, type, -1)); 00533 } 00534 00535 if (s->type == SPELL_TYPE_WIZARD) 00536 { 00537 int failure = rndm(0, 199) - CONTR(op)->encumbrance + op->chosen_skill->level - s->level + 35; 00538 00539 if (failure < 0) 00540 { 00541 new_draw_info(0, COLOR_WHITE, op, "You bungle the spell because you have too much heavy equipment in use."); 00542 return rndm(0, SP_level_spellpoint_cost(caster, type, -1)); 00543 } 00544 } 00545 } 00546 00547 /* Now let's talk about action/shooting speed */ 00548 if (op->type == PLAYER) 00549 { 00550 switch (CONTR(op)->shoottype) 00551 { 00552 case range_wand: 00553 case range_rod: 00554 case range_horn: 00555 op->chosen_skill->stats.maxsp = caster->last_grace; 00556 break; 00557 00558 default: 00559 break; 00560 } 00561 } 00562 } 00563 00564 /* A last sanity check: are caster and target *really* valid? */ 00565 if ((caster && !OBJECT_ACTIVE(caster)) || (target && !OBJECT_ACTIVE(target))) 00566 { 00567 return 0; 00568 } 00569 00570 /* Trigger the map-wide spell event. */ 00571 if (op->map && op->map->events) 00572 { 00573 int retval = trigger_map_event(MEVENT_SPELL_CAST, op->map, op, caster, NULL, stringarg, type); 00574 00575 /* So the plugin's return value can affect the returned value. */ 00576 if (retval) 00577 { 00578 return retval - 1; 00579 } 00580 } 00581 00582 if (caster->type == PLAYER) 00583 { 00584 if (s->type == SPELL_TYPE_WIZARD) 00585 { 00586 CONTR(caster)->stat_spells_cast++; 00587 } 00588 else 00589 { 00590 CONTR(caster)->stat_prayers_cast++; 00591 } 00592 } 00593 00594 /* We need to calculate the spell point cost before the spell actually 00595 * does something, otherwise the following can happen (example): 00596 * Player has 7 mana left, kills a monster with magic bullet (which costs 7 00597 * mana) while standing right next to it, magic bullet kills the monster before 00598 * we reach the return here, player levels up, cost of magic bullet increases 00599 * from 7 to 8. So the function would return 8 instead of 7, resulting in the 00600 * player's mana being -1. */ 00601 if (item != CAST_NPC) 00602 { 00603 spell_cost = SP_level_spellpoint_cost(caster, type, -1); 00604 } 00605 00606 switch ((enum spellnrs) type) 00607 { 00608 case SP_RESTORATION: 00609 case SP_CURE_CONFUSION: 00610 case SP_MINOR_HEAL: 00611 case SP_GREATER_HEAL: 00612 case SP_CURE_POISON: 00613 case SP_CURE_DISEASE: 00614 success = cast_heal(op, SK_level(caster), target, type); 00615 break; 00616 00617 case SP_REMOVE_DEPLETION: 00618 success = remove_depletion(op, target); 00619 break; 00620 00621 case SP_REMOVE_CURSE: 00622 case SP_REMOVE_DAMNATION: 00623 success = remove_curse(op, target, type, item); 00624 break; 00625 00626 case SP_STRENGTH: 00627 case SP_PROT_COLD: 00628 case SP_PROT_FIRE: 00629 case SP_PROT_ELEC: 00630 case SP_PROT_POISON: 00631 success = cast_change_attr(op, caster, target, type); 00632 break; 00633 00634 case SP_IDENTIFY: 00635 success = cast_identify(target, SK_level(caster), NULL, IDENTIFY_NORMAL); 00636 break; 00637 00638 /* Spells after this use direction and not a target */ 00639 case SP_ICESTORM: 00640 case SP_FIRESTORM: 00641 case SP_HOLYWORD: 00642 success = cast_cone(op, caster, dir, duration, type, spellarch[type]); 00643 break; 00644 00645 case SP_PROBE: 00646 if (!dir) 00647 { 00648 examine(op, op); 00649 success = 1; 00650 } 00651 else 00652 { 00653 success = fire_arch_from_position(op, caster, op->x, op->y, dir, spellarch[type], type, NULL); 00654 } 00655 00656 break; 00657 00658 case SP_BULLET: 00659 case SP_CAUSE_LIGHT: 00660 case SP_MAGIC_MISSILE: 00661 success = fire_arch_from_position(op, caster, op->x, op->y, dir, spellarch[type], type, target); 00662 break; 00663 00664 case SP_TOWN_PORTAL: 00665 success = cast_create_town_portal(op); 00666 break; 00667 00668 case SP_WOR: 00669 success = cast_wor(op, caster); 00670 break; 00671 00672 case SP_CREATE_FOOD: 00673 success = cast_create_food(op, caster, dir, stringarg); 00674 break; 00675 00676 case SP_CHARGING: 00677 success = recharge(op); 00678 break; 00679 00680 case SP_CONSECRATE: 00681 success = cast_consecrate(op); 00682 break; 00683 00684 case SP_CAUSE_COLD: 00685 case SP_CAUSE_FLU: 00686 case SP_CAUSE_LEPROSY: 00687 case SP_CAUSE_SMALLPOX: 00688 case SP_CAUSE_PNEUMONIC_PLAGUE: 00689 success = cast_cause_disease(op, caster, dir, spellarch[type], type); 00690 break; 00691 00692 case SP_FINGER_DEATH: 00693 success = finger_of_death(op, target); 00694 break; 00695 00696 case SP_POISON_FOG: 00697 case SP_METEOR: 00698 case SP_ASTEROID: 00699 success = fire_arch_from_position(op, caster, op->x, op->y, dir, spellarch[type], type, NULL); 00700 break; 00701 00702 case SP_METEOR_SWARM: 00703 success = 1; 00704 fire_swarm(op, caster, dir, spellarch[type], SP_METEOR, 3, 0); 00705 break; 00706 00707 case SP_FROST_NOVA: 00708 success = 1; 00709 fire_swarm(op, caster, dir, spellarch[type], SP_ASTEROID, 3, 0); 00710 break; 00711 00712 case SP_BULLET_SWARM: 00713 success = 1; 00714 fire_swarm(op, caster, dir, spellarch[type], SP_BULLET, 5, 0); 00715 break; 00716 00717 case SP_BULLET_STORM: 00718 success = 1; 00719 fire_swarm(op, caster, dir, spellarch[type], SP_BULLET, 3, 0); 00720 break; 00721 00722 case SP_DESTRUCTION: 00723 success = cast_destruction(op, caster, 5 + op->stats.Int, AT_MAGIC); 00724 break; 00725 00726 case SP_BOMB: 00727 success = create_bomb(op, caster, dir, type); 00728 break; 00729 00730 case SP_TRANSFORM_WEALTH: 00731 success = cast_transform_wealth(op); 00732 break; 00733 00734 case SP_RAIN_HEAL: 00735 case SP_PARTY_HEAL: 00736 success = cast_heal_around(op, SK_level(caster), type); 00737 break; 00738 00739 case SP_FROSTBOLT: 00740 case SP_FIREBOLT: 00741 case SP_LIGHTNING: 00742 case SP_FORKED_LIGHTNING: 00743 case SP_NEGABOLT: 00744 success = fire_bolt(op, caster, dir, type); 00745 break; 00746 00747 default: 00748 LOG(llevBug, "cast_spell(): Invalid invalid spell: %d\n", type); 00749 break; 00750 } 00751 00752 play_sound_map(op->map, CMD_SOUND_EFFECT, spells[type].sound, op->x, op->y, 0, 0); 00753 00754 if (item == CAST_NPC) 00755 { 00756 return success; 00757 } 00758 00759 return success ? spell_cost : 0; 00760 } 00761 00769 int cast_create_obj(object *op, object *new_op, int dir) 00770 { 00771 mapstruct *mt; 00772 int xt, yt; 00773 00774 xt = op->x + freearr_x[dir]; 00775 yt = op->y + freearr_y[dir]; 00776 00777 if (!(mt = get_map_from_coord(op->map, &xt, &yt))) 00778 { 00779 return 0; 00780 } 00781 00782 if (dir && blocked(op, mt, xt, yt, op->terrain_flag)) 00783 { 00784 new_draw_info(0, COLOR_WHITE, op, "Something is in the way.\nYou cast it at your feet."); 00785 dir = 0; 00786 } 00787 00788 xt = op->x + freearr_x[dir]; 00789 yt = op->y + freearr_y[dir]; 00790 00791 if (!(mt = get_map_from_coord(op->map, &xt, &yt))) 00792 { 00793 return 0; 00794 } 00795 00796 new_op->x = xt; 00797 new_op->y = yt; 00798 new_op->map = mt; 00799 insert_ob_in_map(new_op, mt, op, 0); 00800 return dir; 00801 } 00802 00811 static int ok_to_put_more(mapstruct *m, int x, int y, object *op) 00812 { 00813 object *tmp; 00814 00815 /* We must check map here or we will go in trouble some line down */ 00816 if (!(m = get_map_from_coord(m, &x, &y))) 00817 { 00818 return 0; 00819 } 00820 00821 /* Only REAL walls will block this - except player only tiles */ 00822 if (wall(m, x, y)) 00823 { 00824 return 0; 00825 } 00826 00827 for (tmp = get_map_ob(m, x, y); tmp != NULL; tmp = tmp->above) 00828 { 00829 /* Only one part for cone/explosion per tile! */ 00830 if (op->type == tmp->type && op->weight_limit == tmp->weight_limit) 00831 { 00832 return 0; 00833 } 00834 } 00835 00836 /* If it passes the above tests, it must be OK */ 00837 return 1; 00838 } 00839 00848 int fire_bolt(object *op, object *caster, int dir, int type) 00849 { 00850 object *tmp; 00851 int w; 00852 00853 if (!spellarch[type]) 00854 { 00855 return 0; 00856 } 00857 00858 tmp = arch_to_object(spellarch[type]); 00859 00860 if (!tmp) 00861 { 00862 return 0; 00863 } 00864 00865 if (!dir) 00866 { 00867 new_draw_info(0, COLOR_WHITE, op, "You can't fire that at yourself!"); 00868 return 0; 00869 } 00870 00871 tmp->stats.dam = (sint16) SP_level_dam_adjust(caster, type, tmp->stats.dam, 0); 00872 tmp->stats.hp = spells[type].bdur + SP_level_strength_adjust(caster, type); 00873 00874 tmp->direction = dir; 00875 tmp->x = op->x + DIRX(tmp); 00876 tmp->y = op->y + DIRY(tmp); 00877 00878 if (QUERY_FLAG(tmp, FLAG_IS_TURNABLE)) 00879 { 00880 SET_ANIMATION(tmp, (NUM_ANIMATIONS(tmp) / NUM_FACINGS(tmp)) * tmp->direction); 00881 } 00882 00883 set_owner(tmp, op); 00884 tmp->level = SK_level(caster); 00885 w = wall(op->map, tmp->x, tmp->y); 00886 00887 if (w && !QUERY_FLAG(tmp, FLAG_REFLECTING)) 00888 { 00889 return 0; 00890 } 00891 00892 if (w || reflwall(op->map, tmp->x, tmp->y, tmp)) 00893 { 00894 tmp->direction = absdir(tmp->direction + 4); 00895 tmp->x = op->x + DIRX(tmp); 00896 tmp->y = op->y + DIRY(tmp); 00897 } 00898 00899 if (wall(op->map, tmp->x, tmp->y)) 00900 { 00901 new_draw_info(0, COLOR_WHITE, op, "There is something in the way."); 00902 return 0; 00903 } 00904 00905 tmp = insert_ob_in_map(tmp, op->map, op, 0); 00906 00907 if (tmp) 00908 { 00909 move_bolt(tmp); 00910 } 00911 00912 return 1; 00913 } 00914 00925 int fire_arch_from_position(object *op, object *caster, sint16 x, sint16 y, int dir, archetype *at, int type, object *target) 00926 { 00927 object *tmp, *env; 00928 00929 if (at == NULL) 00930 { 00931 return 0; 00932 } 00933 00934 for (env = op; env->env != NULL; env = env->env) 00935 { 00936 } 00937 00938 if (env->map == NULL) 00939 { 00940 return 0; 00941 } 00942 00943 tmp = arch_to_object(at); 00944 00945 if (tmp == NULL) 00946 { 00947 return 0; 00948 } 00949 00950 tmp->stats.sp = type; 00951 tmp->stats.dam = (sint16) SP_level_dam_adjust(caster, type, tmp->stats.dam, 0); 00952 tmp->stats.hp = spells[type].bdur + SP_level_strength_adjust(caster, type); 00953 tmp->x = x, tmp->y = y; 00954 tmp->direction = dir; 00955 tmp->stats.grace = tmp->last_sp; 00956 tmp->stats.maxgrace = 60 + (RANDOM() % 12); 00957 00958 if (target) 00959 { 00960 tmp->enemy = target; 00961 tmp->enemy_count = target->count; 00962 } 00963 00964 if (get_owner(op) != NULL) 00965 { 00966 copy_owner(tmp, op); 00967 } 00968 else 00969 { 00970 set_owner(tmp, op); 00971 } 00972 00973 tmp->level = SK_level(caster); 00974 00975 if (QUERY_FLAG(tmp, FLAG_IS_TURNABLE)) 00976 { 00977 SET_ANIMATION(tmp, (NUM_ANIMATIONS(tmp) / NUM_FACINGS(tmp)) * dir); 00978 } 00979 00980 if ((tmp = insert_ob_in_map(tmp, op->map, op, 0)) == NULL) 00981 { 00982 return 1; 00983 } 00984 00985 move_fired_arch(tmp); 00986 return 1; 00987 } 00988 00999 int cast_cone(object *op, object *caster, int dir, int strength, int spell_type, archetype *spell_arch) 01000 { 01001 object *tmp; 01002 int i, success = 0, range_min = -1, range_max = 1; 01003 uint32 count_ref; 01004 01005 if (!dir) 01006 { 01007 range_min = -3, range_max = 4, strength /= 2; 01008 } 01009 01010 /* Our initial spell object */ 01011 tmp = arch_to_object(spell_arch); 01012 01013 if (!tmp) 01014 { 01015 LOG(llevBug, "cast_cone(): arch_to_object() failed!? (%s)\n", spell_arch->name); 01016 return 0; 01017 } 01018 01019 count_ref = tmp->count; 01020 01021 for (i = range_min; i <= range_max; i++) 01022 { 01023 int x = op->x + freearr_x[absdir(dir + i)], y = op->y + freearr_y[absdir(dir + i)]; 01024 01025 if (wall(op->map, x, y)) 01026 { 01027 continue; 01028 } 01029 01030 success = 1; 01031 01032 if (!tmp) 01033 { 01034 tmp = arch_to_object(spell_arch); 01035 } 01036 01037 set_owner(tmp, op); 01038 copy_owner(tmp, op); 01039 /* *very* important - miss this and the spells go really wild! */ 01040 tmp->weight_limit = count_ref; 01041 01042 tmp->level = SK_level(caster); 01043 tmp->x = x, tmp->y = y; 01044 01045 if (dir) 01046 { 01047 tmp->stats.sp = dir; 01048 } 01049 else 01050 { 01051 tmp->stats.sp = i; 01052 } 01053 01054 tmp->stats.hp = strength; 01055 tmp->stats.dam = (sint16) SP_level_dam_adjust(caster, spell_type, tmp->stats.dam, 0); 01056 tmp->stats.maxhp = tmp->count; 01057 01058 if (!QUERY_FLAG(tmp, FLAG_FLYING)) 01059 { 01060 LOG(llevDebug, "cast_cone(): arch %s doesn't have flying 1\n", spell_arch->name); 01061 } 01062 01063 if ((!QUERY_FLAG(tmp, FLAG_WALK_ON) || !QUERY_FLAG(tmp, FLAG_FLY_ON)) && tmp->stats.dam) 01064 { 01065 LOG(llevDebug, "cast_cone(): arch %s doesn't have walk_on 1 and fly_on 1\n", spell_arch->name); 01066 } 01067 01068 if (!insert_ob_in_map(tmp, op->map, op, 0)) 01069 { 01070 return 0; 01071 } 01072 01073 if (tmp->other_arch) 01074 { 01075 cone_drop(tmp); 01076 } 01077 01078 tmp = NULL; 01079 } 01080 01081 /* Can happen when we can't drop anything */ 01082 if (tmp) 01083 { 01084 /* Was not inserted */ 01085 if (!QUERY_FLAG(tmp, FLAG_REMOVED)) 01086 { 01087 remove_ob(tmp); 01088 } 01089 } 01090 01091 return success; 01092 } 01093 01097 void cone_drop(object *op) 01098 { 01099 object *new_ob = arch_to_object(op->other_arch); 01100 01101 new_ob->x = op->x; 01102 new_ob->y = op->y; 01103 new_ob->stats.food = op->stats.hp; 01104 new_ob->level = op->level; 01105 set_owner(new_ob, op->owner); 01106 01107 if (op->chosen_skill) 01108 { 01109 new_ob->chosen_skill = op->chosen_skill; 01110 new_ob->exp_obj = op->chosen_skill->exp_obj; 01111 } 01112 01113 insert_ob_in_map(new_ob, op->map, op, 0); 01114 } 01115 01119 void move_cone(object *op) 01120 { 01121 int i; 01122 tag_t tag; 01123 01124 /* If no map then hit_map will crash so just ignore object */ 01125 if (!op->map) 01126 { 01127 LOG(llevBug, "Tried to move_cone object %s without a map.\n", query_name(op, NULL)); 01128 remove_ob(op); 01129 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 01130 return; 01131 } 01132 01133 /* Lava saves its life, but not yours :) */ 01134 if (QUERY_FLAG(op, FLAG_LIFESAVE)) 01135 { 01136 hit_map(op, 0, 0); 01137 return; 01138 } 01139 01140 /* If no owner left, the spell dies out. */ 01141 if (get_owner(op) == NULL) 01142 { 01143 remove_ob(op); 01144 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 01145 return; 01146 } 01147 01148 /* Hit map returns 1 if it hits a monster. If it does, set 01149 * food to 1, which will stop the cone from progressing. */ 01150 tag = op->count; 01151 op->stats.food |= hit_map(op, 0, 1); 01152 01153 if (was_destroyed(op, tag)) 01154 { 01155 return; 01156 } 01157 01158 if ((op->stats.hp -= 2) < 0) 01159 { 01160 if (op->stats.exp) 01161 { 01162 op->speed = 0; 01163 update_ob_speed(op); 01164 op->stats.exp = 0; 01165 /* So they will join */ 01166 op->stats.sp = 0; 01167 } 01168 else 01169 { 01170 remove_ob(op); 01171 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 01172 } 01173 01174 return; 01175 } 01176 01177 if (op->stats.food) 01178 { 01179 return; 01180 } 01181 01182 op->stats.food = 1; 01183 01184 for (i = -1; i < 2; i++) 01185 { 01186 int x = op->x + freearr_x[absdir(op->stats.sp + i)], y = op->y + freearr_y[absdir(op->stats.sp + i)]; 01187 01188 if (ok_to_put_more(op->map, x, y, op)) 01189 { 01190 object *tmp = arch_to_object(op->arch); 01191 01192 copy_owner(tmp, op); 01193 01194 /* *very* important - this is the count value of the 01195 * *first* object we created with this cone spell. 01196 * we use it for identify this spell. Miss this 01197 * and ok_to_put_more will allow to create 1000th 01198 * in a single tile! */ 01199 tmp->weight_limit = op->weight_limit; 01200 tmp->x = x, tmp->y = y; 01201 01202 tmp->level = op->level; 01203 tmp->stats.sp = op->stats.sp, tmp->stats.hp = op->stats.hp + 1; 01204 tmp->stats.maxhp = op->stats.maxhp; 01205 tmp->stats.dam = op->stats.dam; 01206 01207 if (!insert_ob_in_map(tmp, op->map, op, 0)) 01208 { 01209 return; 01210 } 01211 01212 if (tmp->other_arch) 01213 { 01214 cone_drop(tmp); 01215 } 01216 } 01217 } 01218 } 01219 01224 void forklightning(object *op, object *tmp) 01225 { 01226 mapstruct *m; 01227 /* Direction or -1 for left, +1 for right 0 if no new bolt */ 01228 int xt, yt, new_dir = 1; 01229 /* Stores temporary dir calculation */ 01230 int t_dir; 01231 01232 /* pick a fork direction. tmp->stats.Con is the left bias 01233 * i.e., the chance in 100 of forking LEFT 01234 * Should start out at 50, down to 25 for one already going left 01235 * down to 0 for one going 90 degrees left off original path*/ 01236 01237 /* Fork left */ 01238 if (rndm(0, 99) < tmp->stats.Con) 01239 { 01240 new_dir = -1; 01241 } 01242 01243 /* Check the new dir for a wall and in the map*/ 01244 t_dir = absdir(tmp->direction + new_dir); 01245 01246 xt = tmp->x + freearr_x[t_dir]; 01247 yt = tmp->y + freearr_y[t_dir]; 01248 01249 if (!(m = get_map_from_coord(tmp->map, &xt, &yt)) || wall(m, xt, yt)) 01250 { 01251 new_dir = 0; 01252 } 01253 01254 /* OK, we made a fork */ 01255 if (new_dir) 01256 { 01257 object *new_bolt = get_object(); 01258 01259 copy_object(tmp, new_bolt, 0); 01260 new_bolt->stats.food = 0; 01261 /* Reduce chances of subsequent forking */ 01262 new_bolt->stats.Dex -= 10; 01263 /* Less forks from main bolt too */ 01264 tmp->stats.Dex -= 10; 01265 /* Adjust the left bias */ 01266 new_bolt->stats.Con += 25 * new_dir; 01267 new_bolt->speed_left = -0.1f; 01268 new_bolt->direction = t_dir; 01269 new_bolt->stats.hp++; 01270 new_bolt->x = xt; 01271 new_bolt->y = yt; 01272 /* Reduce daughter bolt damage */ 01273 new_bolt->stats.dam /= 2; 01274 new_bolt->stats.dam++; 01275 /* Reduce father bolt damage */ 01276 tmp->stats.dam /= 2; 01277 tmp->stats.dam++; 01278 01279 if (!insert_ob_in_map(new_bolt, m, op, 0)) 01280 { 01281 return; 01282 } 01283 01284 update_turn_face(new_bolt); 01285 } 01286 } 01287 01299 int reflwall(mapstruct *m, int x, int y, object *sp_op) 01300 { 01301 object *tmp; 01302 01303 if (!(m = get_map_from_coord(m, &x, &y))) 01304 { 01305 return 0; 01306 } 01307 01308 for (tmp = GET_MAP_OB_LAYER(m, x, y, LAYER_LIVING - 1); tmp && tmp->layer == LAYER_LIVING; tmp = tmp->above) 01309 { 01310 if (QUERY_FLAG(tmp->head ? tmp->head : tmp, FLAG_REFL_SPELL) && (rndm(0, 99)) < 90 - (sp_op->level / 10)) 01311 { 01312 return 1; 01313 } 01314 } 01315 01316 return 0; 01317 } 01318 01323 void move_bolt(object *op) 01324 { 01325 int w, r; 01326 object *tmp; 01327 01328 if (--(op->stats.hp) < 0) 01329 { 01330 destruct_ob(op); 01331 return; 01332 } 01333 01334 if (!op->direction) 01335 { 01336 return; 01337 } 01338 01339 if (blocks_magic(op->map, op->x + DIRX(op), op->y + DIRY(op))) 01340 { 01341 return; 01342 } 01343 01344 check_fired_arch(op); 01345 01346 if (!OBJECT_ACTIVE(op)) 01347 { 01348 return; 01349 } 01350 01351 w = wall(op->map, op->x + DIRX(op), op->y + DIRY(op)); 01352 r = reflwall(op->map, op->x + DIRX(op), op->y + DIRY(op), op); 01353 01354 if (w && !QUERY_FLAG(op, FLAG_REFLECTING)) 01355 { 01356 return; 01357 } 01358 01359 /* We're about to bounce */ 01360 if (w || r) 01361 { 01362 if (op->direction & 1) 01363 { 01364 op->direction = absdir(op->direction + 4); 01365 } 01366 else 01367 { 01368 int left = wall(op->map, op->x + freearr_x[absdir(op->direction - 1)], op->y + freearr_y[absdir(op->direction - 1)]), right = wall(op->map, op->x + freearr_x[absdir(op->direction + 1)], op->y + freearr_y[absdir(op->direction + 1)]); 01369 01370 if (left == right) 01371 { 01372 op->direction = absdir(op->direction + 4); 01373 } 01374 else if (left) 01375 { 01376 op->direction = absdir(op->direction + 2); 01377 } 01378 else if (right) 01379 { 01380 op->direction = absdir(op->direction - 2); 01381 } 01382 } 01383 01384 update_turn_face(op); 01385 return; 01386 } 01387 01388 if (op->stats.food || !op->stats.hp) 01389 { 01390 return; 01391 } 01392 01393 op->stats.food = 1; 01394 01395 /* Create a copy of this object and put it ahead */ 01396 tmp = get_object(); 01397 copy_object(op, tmp, 0); 01398 tmp->speed_left = -0.1f; 01399 tmp->x += DIRX(tmp); 01400 tmp->y += DIRY(tmp); 01401 01402 if (!insert_ob_in_map(tmp, op->map, op, 0)) 01403 { 01404 return; 01405 } 01406 01407 if (rndm(0, 99) < tmp->stats.Dex) 01408 { 01409 forklightning(op, tmp); 01410 } 01411 01412 if (tmp) 01413 { 01414 if (!tmp->stats.food) 01415 { 01416 tmp->stats.food = 1; 01417 move_bolt(tmp); 01418 } 01419 else 01420 { 01421 tmp->stats.food = 0; 01422 } 01423 } 01424 } 01425 01429 void explode_object(object *op) 01430 { 01431 tag_t op_tag = op->count; 01432 object *tmp; 01433 int type; 01434 01435 play_sound_map(op->map, CMD_SOUND_EFFECT, "explosion.ogg", op->x, op->y, 0, 0); 01436 01437 if (op->other_arch == NULL) 01438 { 01439 LOG(llevBug, "explode_object(): op %s without other_arch\n", query_name(op, NULL)); 01440 remove_ob(op); 01441 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 01442 return; 01443 } 01444 01445 tmp = arch_to_object(op->other_arch); 01446 type = tmp->stats.sp; 01447 01448 if (!type) 01449 { 01450 type = op->stats.sp; 01451 } 01452 01453 copy_owner(tmp, op); 01454 cast_cone(op, op, 0, spells[type].bdur, type, op->other_arch); 01455 hit_map(op, 0, 0); 01456 01457 /* remove the firebullet */ 01458 if (!was_destroyed(op, op_tag)) 01459 { 01460 remove_ob(op); 01461 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 01462 } 01463 } 01464 01471 void check_fired_arch(object *op) 01472 { 01473 tag_t op_tag = op->count, tmp_tag; 01474 object *tmp, *hitter, *head; 01475 int dam; 01476 01477 /* we return here if we have NOTHING blocking here */ 01478 if (!blocked(op, op->map, op->x, op->y, op->terrain_flag)) 01479 { 01480 return; 01481 } 01482 01483 if (op->other_arch) 01484 { 01485 explode_object(op); 01486 return; 01487 } 01488 01489 if (op->stats.sp == SP_PROBE && op->type == BULLET) 01490 { 01491 probe(op); 01492 remove_ob(op); 01493 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 01494 return; 01495 } 01496 01497 hitter = get_owner(op); 01498 01499 if (!hitter) 01500 { 01501 hitter = op; 01502 } 01503 else if (hitter->head) 01504 { 01505 hitter = hitter->head; 01506 } 01507 01508 for (tmp = get_map_ob(op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) 01509 { 01510 head = tmp->head; 01511 01512 if (!head) 01513 { 01514 head = tmp; 01515 } 01516 01517 if (!IS_LIVE(tmp)) 01518 { 01519 continue; 01520 } 01521 01522 /* Let friends fire through friends */ 01523 if (is_friend_of(hitter, head) || head == hitter || spell_attack_missed(op, head)) 01524 { 01525 continue; 01526 } 01527 01528 tmp_tag = tmp->count; 01529 01530 dam = hit_player(tmp, op->stats.dam, op, AT_INTERNAL); 01531 01532 if (was_destroyed(op, op_tag) || !was_destroyed(tmp, tmp_tag) || (op->stats.dam -= dam) < 0) 01533 { 01534 if (!QUERY_FLAG(op, FLAG_REMOVED)) 01535 { 01536 remove_ob(op); 01537 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 01538 01539 return; 01540 } 01541 } 01542 } 01543 } 01544 01548 void move_fired_arch(object *op) 01549 { 01550 mapstruct *m; 01551 tag_t op_tag = op->count; 01552 int new_x, new_y; 01553 01554 if (op->stats.sp == SP_METEOR) 01555 { 01556 replace_insert_ob_in_map("fire_trail", op); 01557 01558 if (was_destroyed(op, op_tag)) 01559 { 01560 return; 01561 } 01562 } 01563 01564 if (op->stats.sp == SP_MAGIC_MISSILE) 01565 { 01566 rv_vector rv; 01567 01568 if (!OBJECT_VALID(op->enemy, op->enemy_count) || !get_rangevector(op, op->enemy, &rv, 0)) 01569 { 01570 remove_ob(op); 01571 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 01572 return; 01573 } 01574 01575 op->direction = rv.direction; 01576 update_turn_face(op); 01577 } 01578 01579 new_x = op->x + DIRX(op); 01580 new_y = op->y + DIRY(op); 01581 01582 if (!(m = get_map_from_coord(op->map, &new_x, &new_y))) 01583 { 01584 remove_ob(op); 01585 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 01586 return; 01587 } 01588 01589 /* the spell has reached a wall and/or the end of its moving points */ 01590 if (!op->last_sp-- || (!op->direction || wall(m, new_x, new_y))) 01591 { 01592 if (op->other_arch) 01593 { 01594 explode_object(op); 01595 } 01596 else 01597 { 01598 remove_ob(op); 01599 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 01600 } 01601 01602 return; 01603 } 01604 01605 remove_ob(op); 01606 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 01607 op->x = new_x; 01608 op->y = new_y; 01609 01610 if (insert_ob_in_map(op, m, op, 0) == NULL) 01611 { 01612 return; 01613 } 01614 01615 if (reflwall(op->map, op->x, op->y, op)) 01616 { 01617 if (op->type == BULLET && op->stats.sp == SP_PROBE) 01618 { 01619 if (GET_MAP_FLAGS(op->map, op->x, op->y) & (P_IS_ALIVE | P_IS_PLAYER)) 01620 { 01621 probe(op); 01622 remove_ob(op); 01623 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 01624 return; 01625 } 01626 } 01627 01628 op->direction = absdir(op->direction + 4); 01629 update_turn_face(op); 01630 } 01631 else 01632 { 01633 check_fired_arch(op); 01634 } 01635 } 01636 01644 int find_target_for_spell(object *op, object **target, uint32 flags) 01645 { 01646 object *tmp; 01647 01648 /* Default target is nothing. */ 01649 *target = NULL; 01650 01651 /* We cast something on the map... No target */ 01652 if (flags & SPELL_DESC_DIRECTION) 01653 { 01654 return 1; 01655 } 01656 01657 /* A player has invoked this spell. */ 01658 if (op->type == PLAYER) 01659 { 01660 /* Try to cast on self but only when really no friendly or enemy is set. */ 01661 if ((flags & SPELL_DESC_SELF) && !(flags & (SPELL_DESC_ENEMY | SPELL_DESC_FRIENDLY))) 01662 { 01663 /* Self... and no other tests */ 01664 *target = op; 01665 return 1; 01666 } 01667 01668 tmp = CONTR(op)->target_object; 01669 01670 /* Let's check our target - we have one? friend or enemy? */ 01671 if (!tmp || !OBJECT_ACTIVE(tmp) || tmp == CONTR(op)->ob || CONTR(op)->target_object_count != tmp->count) 01672 { 01673 /* Can we cast this on self? */ 01674 if (flags & SPELL_DESC_SELF) 01675 { 01676 /* Right, we are target */ 01677 *target = op; 01678 return 1; 01679 } 01680 } 01681 /* We have a target and it's not self */ 01682 else 01683 { 01684 if (is_friend_of(op, tmp)) 01685 { 01686 if (flags & SPELL_DESC_FRIENDLY) 01687 { 01688 *target = tmp; 01689 return 1; 01690 } 01691 01692 if (flags & SPELL_DESC_SELF) 01693 { 01694 *target = op; 01695 return 1; 01696 } 01697 01698 /* Can't cast unfriendly spells on friendly creatures, but we set target 01699 * so the message player gets is accurate. */ 01700 if (flags & SPELL_DESC_ENEMY) 01701 { 01702 *target = tmp; 01703 return 0; 01704 } 01705 } 01706 else 01707 { 01708 if (flags & SPELL_DESC_ENEMY) 01709 { 01710 *target = tmp; 01711 return 1; 01712 } 01713 01714 if (flags & SPELL_DESC_SELF) 01715 { 01716 *target = op; 01717 return 1; 01718 } 01719 } 01720 } 01721 } 01722 /* A monster or rune/firewall/etc */ 01723 else 01724 { 01725 if ((flags & SPELL_DESC_SELF) && !(flags & (SPELL_DESC_ENEMY | SPELL_DESC_FRIENDLY))) 01726 { 01727 *target = op; 01728 return 1; 01729 } 01730 else if ((flags & SPELL_DESC_ENEMY) && op->enemy && OBJECT_ACTIVE(op->enemy) && op->enemy->count == op->enemy_count) 01731 { 01732 *target = op->enemy; 01733 return 1; 01734 } 01735 else 01736 { 01737 *target = op; 01738 return 1; 01739 } 01740 } 01741 01742 /* Invalid target/spell or whatever */ 01743 return 0; 01744 } 01745 01753 int SP_level_dam_adjust(object *caster, int spell_type, int base_dam, int exact) 01754 { 01755 int level = SK_level(caster); 01756 sint16 dam; 01757 01758 /* Sanity check */ 01759 if (level <= 0 || level > MAXLEVEL) 01760 { 01761 LOG(llevBug, "SP_level_dam_adjust(): object %s has invalid level %d\n", query_name(caster, NULL), level); 01762 01763 if (level <= 0) 01764 { 01765 level = 1; 01766 } 01767 else 01768 { 01769 level = MAXLEVEL; 01770 } 01771 } 01772 01773 /* get a base damage when we don't have one from caller */ 01774 if (base_dam == -1) 01775 { 01776 base_dam = spells[spell_type].bdam; 01777 } 01778 01779 dam = (sint16) ((float) base_dam * LEVEL_DAMAGE(level) * PATH_DMG_MULT(caster, find_spell(spell_type))); 01780 01781 if (exact || !dam) 01782 { 01783 return dam; 01784 } 01785 01786 return rndm(dam * 0.8f + 1, dam); 01787 } 01788 01794 int SP_level_strength_adjust(object *caster, int spell_type) 01795 { 01796 int level = SK_level(caster); 01797 int adj = (level - spells[spell_type].level); 01798 01799 if (adj < 0) 01800 { 01801 adj = 0; 01802 } 01803 01804 if (spells[spell_type].ldur) 01805 { 01806 adj /= spells[spell_type].ldur; 01807 } 01808 else 01809 { 01810 adj = 0; 01811 } 01812 01813 return adj; 01814 } 01815 01826 int SP_level_spellpoint_cost(object *caster, int spell_type, int caster_level) 01827 { 01828 spell_struct *s = find_spell(spell_type); 01829 int level = (caster_level == -1 ? SK_level(caster) : caster_level), sp; 01830 01831 if (spells[spell_type].spl) 01832 { 01833 sp = (int) (spells[spell_type].sp * (1.0 + (MAX(0, (float) (level - spells[spell_type].level) / (float) spells[spell_type].spl)))); 01834 } 01835 else 01836 { 01837 sp = spells[spell_type].sp; 01838 } 01839 01840 return (int) ((float) sp * (float) PATH_SP_MULT(caster, s)); 01841 } 01842 01850 void move_swarm_spell(object *op) 01851 { 01852 int cardinal_adjust[9] = {-3, -2, -1, 0, 0, 0, 1, 2, 3}; 01853 int diagonal_adjust[10] = {-3, -2, -2, -1, 0, 0, 1, 2, 2, 3}; 01854 int xt, yt, basedir, adjustdir; 01855 sint16 target_x, target_y, origin_x, origin_y; 01856 01857 if (op->stats.hp == 0 || get_owner(op) == NULL) 01858 { 01859 remove_ob(op); 01860 check_walk_off(op, NULL, MOVE_APPLY_VANISHED); 01861 return; 01862 } 01863 01864 op->stats.hp--; 01865 01866 basedir = op->direction; 01867 01868 if (basedir == 0) 01869 { 01870 /* Spray in all directions! 8) */ 01871 basedir = get_random_dir(); 01872 } 01873 01874 /* New offset calculation to make swarm element distribution 01875 * more uniform */ 01876 if (op->stats.hp) 01877 { 01878 if (basedir & 1) 01879 { 01880 adjustdir = cardinal_adjust[rndm(0, 8)]; 01881 } 01882 else 01883 { 01884 adjustdir = diagonal_adjust[rndm(0, 9)]; 01885 } 01886 } 01887 /* Fire the last one from forward. */ 01888 else 01889 { 01890 adjustdir = 0; 01891 } 01892 01893 target_x = op->x + freearr_x[absdir(basedir + adjustdir)]; 01894 target_y = op->y + freearr_y[absdir(basedir + adjustdir)]; 01895 01896 /* Back up one space so we can hit point-blank targets, but this 01897 * necessitates extra get_map_from_coord check below */ 01898 origin_x = target_x - freearr_x[basedir]; 01899 origin_y = target_y - freearr_y[basedir]; 01900 01901 xt = (int) origin_x; 01902 yt = (int) origin_y; 01903 01904 if (!get_map_from_coord(op->map, &xt, &yt)) 01905 { 01906 return; 01907 } 01908 01909 if (!wall(op->map, target_x, target_y)) 01910 { 01911 fire_arch_from_position(op, op, origin_x, origin_y, basedir, op->other_arch, op->stats.sp, NULL); 01912 } 01913 } 01914 01926 void fire_swarm(object *op, object *caster, int dir, archetype *swarm_type, int spell_type, int n, int magic) 01927 { 01928 object *tmp = get_archetype("swarm_spell"); 01929 01930 tmp->x = op->x; 01931 tmp->y = op->y; 01932 /* Needed so that if swarm elements kill, caster gets xp. */ 01933 set_owner(tmp, op); 01934 /* Needed later, to get level dep. right.*/ 01935 tmp->level = SK_level(caster); 01936 /* Needed later, see move_swarm_spell */ 01937 tmp->stats.sp = spell_type; 01938 01939 tmp->magic = magic; 01940 /* n in swarm */ 01941 tmp->stats.hp = n; 01942 /* The archetype of the things to be fired */ 01943 tmp->other_arch = swarm_type; 01944 tmp->direction = dir; 01945 01946 insert_ob_in_map(tmp, op->map, op, 0); 01947 }
1.7.4