--- deliantra/server/server/spell_attack.C 2009/03/02 11:45:19 1.83 +++ deliantra/server/server/spell_attack.C 2010/02/07 04:22:33 1.96 @@ -1,22 +1,23 @@ /* * This file is part of Deliantra, the Roguelike Realtime MMORPG. * - * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team + * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team * Copyright (©) 2002-2003,2007 Mark Wedel & Crossfire Development Team * Copyright (©) 1992,2007 Frank Tore Johansen * - * Deliantra is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Deliantra is free software: you can redistribute it and/or modify it under + * the terms of the Affero GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the Affero GNU General Public License + * and the GNU General Public License along with this program. If not, see + * . * * The authors can be reached via e-mail to */ @@ -38,7 +39,7 @@ * but moved here so it could be applied to bolts too * op is the spell object. */ -void +static void check_spell_knockback (object *op) { int weight_move; @@ -109,7 +110,7 @@ /* Causes op to fork. op is the original bolt, tmp * is the first piece of the fork. */ -void +static void forklightning (object *op, object *tmp) { int new_dir = 1; /* direction or -1 for left, +1 for right 0 if no new bolt */ @@ -278,7 +279,7 @@ if (!spob->other_arch) return 0; - tmp = arch_to_object (spob->other_arch); + tmp = spob->other_arch->instance (); if (tmp == NULL) return 0; @@ -390,7 +391,7 @@ * poison cloud ball, etc. op is the object to * explode. */ -void +static void explode_bullet (object *op) { object *tmp, *owner; @@ -440,7 +441,7 @@ } /* other_arch contains what this explodes into */ - tmp = arch_to_object (op->other_arch); + tmp = op->other_arch->instance (); tmp->set_owner (op); tmp->skill = op->skill; @@ -547,10 +548,6 @@ void move_bullet (object *op) { - sint16 new_x, new_y; - int mflags; - maptile *m; - #if 0 /* We need a better general purpose way to do this */ @@ -575,18 +572,20 @@ return; } - new_x = op->x + DIRX (op); - new_y = op->y + DIRY (op); - m = op->map; - mflags = get_map_flags (m, &m, new_x, new_y, &new_x, &new_y); + mapxy pos (op); + pos.move (op->direction); - if (mflags & P_OUT_OF_MAP) + if (!pos.normalise ()) { op->destroy (); return; } - if (!op->direction || OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, new_x, new_y))) + mapspace &ms = pos.ms (); + + ms.update (); + + if (!op->direction || OB_TYPE_MOVE_BLOCK (op, ms.move_block)) { if (op->other_arch) explode_bullet (op); @@ -596,7 +595,7 @@ return; } - if (!(op = m->insert (op, new_x, new_y, op))) + if (!(op = pos.insert (op, op))) return; if (reflwall (op->map, op->x, op->y, op)) @@ -663,6 +662,19 @@ tmp->map = newmap; + // in case the bullet has direction 0 we explode it in place. + // direction 0 is possible for instance when a poison cloud trap springs. + if (tmp->direction == 0) + { + if (tmp->other_arch + && (tmp = tmp->insert_at (tmp, op))) // insert before explode cleanly + explode_bullet (tmp); // explode object will/should remove tmp + else + tmp->destroy (); + + return 0; + } + if (OB_TYPE_MOVE_BLOCK (tmp, GET_MAP_MOVE_BLOCK (tmp->map, tmp->x, tmp->y))) { if (!QUERY_FLAG (tmp, FLAG_REFLECTING)) @@ -690,10 +702,10 @@ *****************************************************************************/ /* drops an object based on what is in the cone's "other_arch" */ -void +static void cone_drop (object *op) { - object *new_ob = arch_to_object (op->other_arch); + object *new_ob = op->other_arch->instance (); new_ob->level = op->level; new_ob->set_owner (op->owner); @@ -864,7 +876,7 @@ continue; success = 1; - tmp = arch_to_object (spell->other_arch); + tmp = spell->other_arch->instance (); tmp->set_owner (op); set_spell_skill (op, caster, spell, tmp); tmp->level = casting_level (caster, spell); @@ -949,7 +961,7 @@ if (op->env) { - if (env->map == NULL) + if (!env->map) return; if (!(op = op->insert_at (env, op))) @@ -959,7 +971,7 @@ // elmex Tue Aug 15 17:46:51 CEST 2006: Prevent bomb from exploding // on a safe map. I don't like this special casing, but it seems to be neccessary // as bombs can be carried. - if (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_SAFE) + if (op->ms ().flags () & P_SAFE) { op->destroy (); return; @@ -976,7 +988,7 @@ if (out_of_map (op->map, op->x + freearr_x[i], op->y + freearr_x[i])) continue; - object *tmp = arch_to_object (at); + object *tmp = at->instance (); tmp->direction = i; tmp->range = op->range; tmp->stats.dam = op->stats.dam; @@ -1020,7 +1032,7 @@ } } - tmp = arch_to_object (spell->other_arch); + tmp = spell->other_arch->instance (); /* level dependencies for bomb */ tmp->range = spell->range + SP_level_range_adjust (caster, spell); @@ -1050,7 +1062,7 @@ * type is the type of spell - either SPELL_MANA or SPELL_GRACE. * this info is used for blocked magic/unholy spaces. */ -object * +static object * get_pointed_target (object *op, int dir, int range, int type) { object *target; @@ -1124,7 +1136,7 @@ } if (spell->other_arch) - effect = arch_to_object (spell->other_arch); + effect = spell->other_arch->instance (); else return 0; @@ -1247,7 +1259,7 @@ * make this work for non-living objects, we would have to * give them the capability to have an inventory. b.t. */ -int +static int make_object_glow (object *op, int radius, int time) { /* some things are unaffected... */ @@ -1290,33 +1302,38 @@ op->change_skill (find_skill_by_name (op, op->skill)); - unordered_mapwalk (op, -range, -range, range, range) + dynbuf buf; + unordered_mapwalk (buf, op, -range, -range, range, range) { mapspace &ms = m->at (nx, ny); if (ms.flags () & P_IS_ALIVE) - for (object *tmp = ms.bot; tmp; tmp = tmp->above) - if (tmp->flag [FLAG_ALIVE] || tmp->is_player ()) - { - tmp = tmp->head_ (); + for (object *next, *tmp = ms.bot; tmp; tmp = next) + { + next = tmp->above; - if ((friendly && !tmp->flag [FLAG_FRIENDLY] && !tmp->is_player ()) - || (!friendly && (tmp->flag [FLAG_FRIENDLY] || tmp->is_player ()))) - { - if (spell_ob->subtype == SP_DESTRUCTION) - { - hit_player (tmp, dam, op, spell_ob->attacktype, 0); - - if (spell_ob->other_arch) - m->insert (arch_to_object (spell_ob->other_arch), nx, ny, op); - } - else if (spell_ob->subtype == SP_FAERY_FIRE && tmp->resist [ATNR_MAGIC] != 100) - { - if (make_object_glow (tmp, 1, dur) && spell_ob->other_arch) - m->insert (arch_to_object (spell_ob->other_arch), nx, ny, op); - } - } - } + if (tmp->flag [FLAG_ALIVE] || tmp->is_player ()) + { + tmp = tmp->head_ (); + + if ((friendly && !tmp->flag [FLAG_FRIENDLY] && !tmp->is_player ()) + || (!friendly && (tmp->flag [FLAG_FRIENDLY] || tmp->is_player ()))) + { + if (spell_ob->subtype == SP_DESTRUCTION) + { + hit_player (tmp, dam, op, spell_ob->attacktype, 0); + + if (spell_ob->other_arch) + m->insert (spell_ob->other_arch->instance (), nx, ny, op); + } + else if (spell_ob->subtype == SP_FAERY_FIRE && tmp->resist [ATNR_MAGIC] != 100) + { + if (make_object_glow (tmp, 1, dur) && spell_ob->other_arch) + m->insert (spell_ob->other_arch->instance (), nx, ny, op); + } + } + } + } } op->skill = skill; @@ -1328,7 +1345,6 @@ * CURSE * ***************************************************************************/ - int cast_curse (object *op, object *caster, object *spell_ob, int dir) { @@ -1416,8 +1432,8 @@ change_abil (tmp, force); /* Mostly to display any messages */ insert_ob_in_ob (force, tmp); tmp->update_stats (); - return 1; + return 1; } /********************************************************************** @@ -1456,7 +1472,8 @@ else race = spell->race; - unordered_mapwalk (op, -range, -range, range, range) + dynbuf buf; + unordered_mapwalk (buf, op, -range, -range, range, range) { mapspace &ms = m->at (nx, ny); @@ -1528,7 +1545,7 @@ if (head->level > level) continue; - if (random_roll (0, 100, caster, PREFER_LOW) >= (20 + MIN (50, 2 * (level - head->level)))) + if (random_roll (0, 100, caster, PREFER_LOW) >= (20 + min (50, 2 * (level - head->level)))) /* Failed, no effect */ continue; } @@ -1580,7 +1597,7 @@ /* If a monster was effected, put an effect in */ if (done_one && spell->other_arch) - m->insert (arch_to_object (spell->other_arch), nx, ny, op); + m->insert (spell->other_arch->instance (), nx, ny, op); } return 1; @@ -1673,7 +1690,7 @@ /* insert the other arch */ if (op->other_arch && !(OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, hx, hy)))) - m->insert (arch_to_object (op->other_arch), hx, hy, op); + m->insert (op->other_arch->instance (), hx, hy, op); } /* restore to the center location and damage */ @@ -1899,7 +1916,7 @@ } /* ok, looks groovy to just insert a new light on the map */ - tmp = arch_to_object (spell->other_arch); + tmp = spell->other_arch->instance (); if (!tmp) { LOG (llevError, "Error: spell arch for cast_light() missing.\n"); @@ -1910,12 +1927,13 @@ if (tmp->glow_radius) tmp->set_glow_radius ( - min (MAX_LIGHT_RADIUS, spell->range + SP_level_range_adjust (caster, spell))); + clamp (spell->range + SP_level_range_adjust (caster, spell), 1, MAX_LIGHT_RADIUS) + ); if (dir) m->insert (tmp, x, y, op); else - caster->outer_env ()->insert (tmp); + caster->outer_env_or_self ()->insert (tmp); return 1; } @@ -1974,7 +1992,7 @@ for (walk = GET_MAP_OB (m, x, y); walk; walk = walk->above) if (QUERY_FLAG (walk, FLAG_MONSTER) || (walk->type == PLAYER)) { /* found a victim */ - object *disease = arch_to_object (spell->other_arch); + object *disease = spell->other_arch->instance (); disease->set_owner (op); set_spell_skill (op, caster, spell, disease); @@ -2034,7 +2052,7 @@ new_draw_info_format (NDI_UNIQUE, 0, op, "You inflict %s on %s!", &disease->name, &walk->name); disease->destroy (); /* don't need this one anymore */ - walk->map->insert (get_archetype ("detect_magic"), x, y, op); + walk->map->insert (get_archetype (shstr_detect_magic), x, y, op); return 1; }