Atrinik Server 2.5
server/spell_util.c
Go to the documentation of this file.
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 }