--- deliantra/server/server/spell_attack.C 2009/01/12 00:17:23 1.81
+++ deliantra/server/server/spell_attack.C 2010/03/26 01:04:45 1.99
@@ -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 (©) 2002-2003,2007 Mark Wedel & Crossfire Development Team
- * Copyright (©) 1992,2007 Frank Tore Johansen
+ * Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
+ * Copyright (©) 2002-2003 Mark Wedel & Crossfire Development Team
+ * Copyright (©) 1992 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;
@@ -94,7 +95,7 @@
* I don't see us doing anything useful with that information
* right now.
*/
- move_object (tmp, absdir (op->stats.sp));
+ tmp->move (absdir (op->stats.sp));
}
}
@@ -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);
@@ -830,14 +842,14 @@
for (i = range_min; i <= range_max; i++)
{
- sint16 x, y, d;
+ sint16 x, y;
/* We can't use absdir here, because it never returns
* 0. If this is a rune, we want to hit the person on top
* of the trap (d==0). If it is not a rune, then we don't want
* to hit that person.
*/
- d = (dir + i) % 9;
+ int d = dir ? absdir (dir + i) : i;
/* If it's not a rune, we don't want to blast the caster.
* In that case, we have to see - if dir is specified,
@@ -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;
}