--- deliantra/server/server/spell_attack.C 2008/12/28 06:59:27 1.73
+++ deliantra/server/server/spell_attack.C 2017/09/16 22:17:42 1.116
@@ -1,23 +1,24 @@
/*
* 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
- *
- * 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.
- *
+ *
+ * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 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 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;
@@ -60,7 +61,7 @@
int num_sections = 1;
/* don't move DM */
- if (QUERY_FLAG (tmp, FLAG_WIZ))
+ if (tmp->flag [FLAG_WIZ])
return;
/* don't move parts of objects */
@@ -68,7 +69,7 @@
continue;
/* don't move floors or immobile objects */
- if (QUERY_FLAG (tmp, FLAG_IS_FLOOR) || (!QUERY_FLAG (tmp, FLAG_ALIVE) && QUERY_FLAG (tmp, FLAG_NO_PICK)))
+ if (tmp->flag [FLAG_IS_FLOOR] || (!tmp->flag [FLAG_ALIVE] && tmp->flag [FLAG_NO_PICK]))
continue;
/* count the object's sections */
@@ -87,14 +88,14 @@
if (rndm (0, weight_move - 1) > ((tmp->weight / num_sections) * frictionmod))
{ /* move it. */
- /* move_object is really for monsters, but looking at
+ /* move_object is really for monsters, but looking at
* the move_object function, it appears that it should
* also be safe for objects.
* This does return if successful or not, but
* 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 */
@@ -130,7 +131,7 @@
/* check the new dir for a wall and in the map */
t_dir = absdir (tmp->direction + new_dir);
- if (get_map_flags (tmp->map, &m, tmp->x + freearr_x[t_dir], tmp->y + freearr_y[t_dir], &sx, &sy) & P_OUT_OF_MAP)
+ if (get_map_flags (tmp->map, &m, tmp->x + DIRX (t_dir), tmp->y + DIRY (t_dir), &sx, &sy) & P_OUT_OF_MAP)
return;
if (OB_TYPE_MOVE_BLOCK (tmp, GET_MAP_MOVE_BLOCK (m, sx, sy)))
@@ -180,8 +181,8 @@
op->range = 0;
else
{
- x = op->x + DIRX (op);
- y = op->y + DIRY (op);
+ x = op->x + DIRX (op->direction);
+ y = op->y + DIRY (op->direction);
m = op->map;
mflags = get_map_flags (m, &m, x, y, &x, &y);
@@ -195,7 +196,7 @@
*/
if (OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y)) || ((mflags & P_IS_ALIVE) && reflwall (m, x, y, op)))
{
- if (!QUERY_FLAG (op, FLAG_REFLECTING))
+ if (!op->flag [FLAG_REFLECTING])
return;
/* Since walls don't run diagonal, if the bolt is in
@@ -218,13 +219,13 @@
* op->direction is within an adjacent map but either
* op->direction-1 or op->direction+1 does not exist.
*/
- mflags = get_map_flags (op->map, &m, op->x + freearr_x[absdir (op->direction - 1)],
- op->y + freearr_y[absdir (op->direction - 1)], &x, &y);
+ mflags = get_map_flags (op->map, &m, op->x + DIRX (absdir (op->direction - 1)),
+ op->y + DIRY (absdir (op->direction - 1)), &x, &y);
left = (mflags & P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y));
- mflags = get_map_flags (op->map, &m, op->x + freearr_x[absdir (op->direction + 1)],
- op->y + freearr_y[absdir (op->direction + 1)], &x, &y);
+ mflags = get_map_flags (op->map, &m, op->x + DIRX (absdir (op->direction + 1)),
+ op->y + DIRY (absdir (op->direction + 1)), &x, &y);
right = (mflags & P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y));
if (left == right)
@@ -248,7 +249,7 @@
tmp->duration++;
/* New forking code. Possibly create forks of this object
- * going off in other directions.
+ * going off in other directions.
*/
if (tmp->stats.Dex && rndm (0, 99) < tmp->stats.Dex)
forklightning (op, tmp); /* stats.Dex % of forking */
@@ -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;
@@ -295,14 +296,14 @@
tmp->stats.Con = spob->stats.Con;
tmp->direction = dir;
- if (QUERY_FLAG (tmp, FLAG_IS_TURNABLE))
+ if (tmp->flag [FLAG_IS_TURNABLE])
SET_ANIMATION (tmp, dir);
tmp->set_owner (op);
set_spell_skill (op, caster, spob, tmp);
- tmp->x = op->x + DIRX (tmp);
- tmp->y = op->y + DIRY (tmp);
+ tmp->x = op->x + DIRX (tmp->direction);
+ tmp->y = op->y + DIRY (tmp->direction);
tmp->map = op->map;
maptile *newmap;
@@ -317,7 +318,7 @@
if (OB_TYPE_MOVE_BLOCK (tmp, GET_MAP_MOVE_BLOCK (tmp->map, tmp->x, tmp->y)))
{
- if (!QUERY_FLAG (tmp, FLAG_REFLECTING))
+ if (!tmp->flag [FLAG_REFLECTING])
{
tmp->drop_and_destroy ();
return 0;
@@ -365,10 +366,10 @@
{
sint16 dx, dy;
- dx = op->x + freearr_x[i];
- dy = op->y + freearr_y[i];
+ dx = op->x + DIRX (i);
+ dy = op->y + DIRY (i);
- /* ok_to_put_more already does things like checks for walls,
+ /* ok_to_put_more already does things like checks for walls,
* out of map, etc.
*/
if (ok_to_put_more (op->map, dx, dy, op, op->attacktype))
@@ -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;
@@ -522,14 +523,14 @@
for (tmp = op->ms ().bot; tmp; tmp = tmp->above)
{
- if (QUERY_FLAG (tmp, FLAG_ALIVE))
+ if (tmp->flag [FLAG_ALIVE])
{
dam = hit_player (tmp, op->stats.dam, op, op->attacktype, 1);
// TODO: can't understand the following if's
if (op->destroyed () || !tmp->destroyed () || (op->stats.dam -= dam) < 0)
{
- if (!QUERY_FLAG (op, FLAG_REMOVED))
+ if (!op->flag [FLAG_REMOVED])
{
op->destroy ();
return;
@@ -547,14 +548,10 @@
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 */
- /* peterm: added to make comet leave a trail of burnouts
+ /* peterm: added to make comet leave a trail of burnouts
it's an unadulterated hack, but the effect is cool. */
if (op->stats.sp == SP_METEOR)
{
@@ -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))
@@ -643,14 +642,14 @@
tmp->dam_modifier = spob->stats.food + SP_level_dam_adjust (caster, spob);
tmp->direction = dir;
- if (QUERY_FLAG (tmp, FLAG_IS_TURNABLE))
+ if (tmp->flag [FLAG_IS_TURNABLE])
SET_ANIMATION (tmp, dir);
tmp->set_owner (op);
set_spell_skill (op, caster, spob, tmp);
- tmp->x = op->x + freearr_x[dir];
- tmp->y = op->y + freearr_y[dir];
+ tmp->x = op->x + DIRX (dir);
+ tmp->y = op->y + DIRY (dir);
tmp->map = op->map;
maptile *newmap;
@@ -663,9 +662,22 @@
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))
+ if (!tmp->flag [FLAG_REFLECTING])
{
tmp->destroy ();
return 0;
@@ -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);
@@ -719,7 +731,7 @@
}
/* lava saves it's life, but not yours :) */
- if (QUERY_FLAG (op, FLAG_LIFESAVE))
+ if (op->flag [FLAG_LIFESAVE])
{
hit_map (op, 0, op->attacktype, 0);
return;
@@ -744,7 +756,7 @@
/* Check to see if we should push anything.
* Spell objects with weight push whatever they encounter to some
- * degree.
+ * degree.
*/
if (op->weight)
{
@@ -771,7 +783,7 @@
for (int i = -1; i <= 1; i++)
{
- sint16 x = op->x + freearr_x[absdir (op->stats.sp + i)], y = op->y + freearr_y[absdir (op->stats.sp + i)];
+ sint16 x = op->x + DIRX (absdir (op->stats.sp + i)), y = op->y + DIRY (absdir (op->stats.sp + i));
if (ok_to_put_more (op->map, x, y, op, op->attacktype))
{
@@ -810,9 +822,9 @@
if (!spell->other_arch)
return 0;
- if (op->type == PLAYER && QUERY_FLAG (op, FLAG_UNDEAD) && op->attacktype & AT_TURN_UNDEAD)
+ if (op->type == PLAYER && op->flag [FLAG_UNDEAD] && op->attacktype & AT_TURN_UNDEAD)
{
- new_draw_info (NDI_UNIQUE, 0, op, "Your undead nature prevents you from turning undead!");
+ op->failmsg ("Your undead nature prevents you from turning undead!");
return 0;
}
@@ -830,18 +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
+ * 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;
- while (d < 0)
- d += 8;
- while (d > 8)
- d -= 8;
+ 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,
@@ -858,8 +866,8 @@
continue;
}
- x = op->x + freearr_x[d];
- y = op->y + freearr_y[d];
+ x = op->x + DIRX (d);
+ y = op->y + DIRY (d);
if (get_map_flags (op->map, &m, x, y, &sx, &sy) & P_OUT_OF_MAP)
continue;
@@ -868,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);
@@ -953,7 +961,7 @@
if (op->env)
{
- if (env->map == NULL)
+ if (!env->map)
return;
if (!(op = op->insert_at (env, op)))
@@ -963,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;
@@ -977,10 +985,10 @@
{
for (int i = 1; i < 9; i++)
{
- if (out_of_map (op->map, op->x + freearr_x[i], op->y + freearr_x[i]))
+ if (out_of_map (op->map, op->x + DIRX (i), op->y + DIRX (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;
@@ -990,10 +998,10 @@
if (op->skill && op->skill != tmp->skill)
tmp->skill = op->skill;
- if (QUERY_FLAG (tmp, FLAG_IS_TURNABLE))
+ if (tmp->flag [FLAG_IS_TURNABLE])
SET_ANIMATION (tmp, i);
- op->map->insert (tmp, op->x + freearr_x[i], op->y + freearr_x[i], op);
+ op->map->insert (tmp, op->x + DIRX (i), op->y + DIRX (i), op);
move_bullet (tmp);
}
}
@@ -1006,7 +1014,7 @@
{
object *tmp;
int mflags;
- sint16 dx = op->x + freearr_x[dir], dy = op->y + freearr_y[dir];
+ sint16 dx = op->x + DIRX (dir), dy = op->y + DIRY (dir);
maptile *m;
mflags = get_map_flags (op->map, &m, dx, dy, &dx, &dy);
@@ -1019,12 +1027,12 @@
{
if ((mflags & P_OUT_OF_MAP) || (GET_MAP_MOVE_BLOCK (m, dx, dy) & MOVE_WALK))
{
- new_draw_info (NDI_UNIQUE, 0, op, "There is something in the way.");
+ op->failmsg ("There is something in the way.");
return 0;
}
}
- 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);
@@ -1054,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;
@@ -1067,8 +1075,8 @@
for (dist = 1; dist < range; dist++)
{
- x = op->x + freearr_x[dir] * dist;
- y = op->y + freearr_y[dir] * dist;
+ x = op->x + DIRX (dir) * dist;
+ y = op->y + DIRY (dir) * dist;
mp = op->map;
mflags = get_map_flags (op->map, &mp, x, y, &x, &y);
@@ -1083,15 +1091,15 @@
if (mflags & P_IS_ALIVE)
for (target = GET_MAP_OB (mp, x, y); target; target = target->above)
- if (QUERY_FLAG (target, FLAG_MONSTER))
+ if (target->flag [FLAG_MONSTER])
return target;
}
return NULL;
}
-/* cast_smite_arch() - the priest points to a creature and causes
- * a 'godly curse' to decend.
+/* cast_smite_spell() - the priest points to a creature and causes
+ * a 'godly curse' to decend.
* usual params -
* op = player
* caster = object casting the spell.
@@ -1103,12 +1111,10 @@
{
object *effect, *target;
object *god = find_god (determine_god (op));
- int range;
- range = spell->range + SP_level_range_adjust (caster, spell);
target = get_pointed_target (op, dir, 50, spell->stats.grace ? SPELL_GRACE : SPELL_MANA);
- /* Bunch of conditions for casting this spell. Note that only
+ /* Bunch of conditions for casting this spell. Note that only
* require a god if this is a cleric spell (requires grace).
* This makes this spell much more general purpose - it can be used
* by wizards also, which is good, because I think this is a very
@@ -1117,16 +1123,18 @@
* can't be friendly to your god.
*/
- if (!target || QUERY_FLAG (target, FLAG_REFL_SPELL)
+ if (!target
+ || target->flag [FLAG_REFL_SPELL]
|| (!god && spell->stats.grace)
- || (target->title && god && !strcmp (target->title, god->name)) || (target->race && god && strstr (target->race, god->race)))
+ || (god && target->title == god->name)
+ || (god && target->race.contains (god->race)))
{
- new_draw_info (NDI_UNIQUE, 0, op, "Your request is unheeded.");
+ op->failmsg ("Your request is unheeded.");
return 0;
}
if (spell->other_arch)
- effect = arch_to_object (spell->other_arch);
+ effect = spell->other_arch->instance ();
else
return 0;
@@ -1136,10 +1144,10 @@
if (effect->attacktype & (AT_HOLYWORD | AT_GODPOWER))
{
if (tailor_god_spell (effect, op))
- new_draw_info_format (NDI_UNIQUE, 0, op, "%s answers your call!", determine_god (op));
+ new_draw_info_format (NDI_UNIQUE, 0, op, "%s answers your call!", (const char *)determine_god (op));
else
{
- new_draw_info (NDI_UNIQUE, 0, op, "Your request is ignored.");
+ op->failmsg ("Your request is ignored.");
return 0;
}
}
@@ -1153,7 +1161,7 @@
effect->level = spell->stats.dam + SP_level_dam_adjust (caster, spell);
/* casting death spells at undead isn't a good thing */
- if (QUERY_FLAG (target, FLAG_UNDEAD))
+ if (target->flag [FLAG_UNDEAD])
{
if (random_roll (0, 2, op, PREFER_LOW))
{
@@ -1244,27 +1252,27 @@
****************************************************************************/
/* make_object_glow() - currently only makes living objects glow.
- * we do this by creating a force and inserting it in the
+ * we do this by creating a force and inserting it in the
* object. if time is 0, the object glows permanently. To truely
- * make this work for non-living objects, we would have to
+ * 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... */
if (op->path_denied & PATH_LIGHT)
return 0;
- object *tmp = get_archetype (FORCE_NAME);
- tmp->speed = 0.01;
+ object *tmp = archetype::get (FORCE_NAME);
+ tmp->set_speed (0.01);
tmp->stats.food = time;
- SET_FLAG (tmp, FLAG_IS_USED_UP);
- tmp->glow_radius = min (MAX_LIGHT_RADIUS, radius);
+ tmp->set_flag (FLAG_IS_USED_UP);
+ tmp->set_glow_radius (min (MAX_LIGHT_RADIUS, radius));
tmp = insert_ob_in_ob (tmp, op);
if (tmp->glow_radius > op->glow_radius)
- op->glow_radius = tmp->glow_radius;
+ op->set_glow_radius (tmp->glow_radius);
return 1;
}
@@ -1272,79 +1280,46 @@
int
cast_destruction (object *op, object *caster, object *spell_ob)
{
- int i, j, range, mflags, friendly = 0, dam, dur;
- sint16 sx, sy;
- maptile *m;
- object *tmp;
- const char *skill;
-
- range = spell_ob->range + SP_level_range_adjust (caster, spell_ob);
- dam = spell_ob->stats.dam + SP_level_dam_adjust (caster, spell_ob);
- dur = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob);
- if (QUERY_FLAG (op, FLAG_FRIENDLY) || op->type == PLAYER)
- friendly = 1;
-
- /* destruction doesn't use another spell object, so we need
- * update op's skill pointer so that exp is properly awarded.
- * We do some shortcuts here - since this is just temporary
- * and we'll reset the values back, we don't need to go through
- * the full share string/free_string route.
- */
- skill = op->skill;
- if (caster == op)
- op->skill = spell_ob->skill;
- else if (caster->skill)
- op->skill = caster->skill;
- else
- op->skill = NULL;
+ int range = spell_ob->range + SP_level_range_adjust (caster, spell_ob);
+ int dam = spell_ob->stats.dam + SP_level_dam_adjust (caster, spell_ob);
+ int dur = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob);
- op->change_skill (find_skill_by_name (op, op->skill));
+ bool friendly = op->flag [FLAG_FRIENDLY] || op->is_player ();
- for (i = -range; i <= range; i++)
+ dynbuf buf;
+ unordered_mapwalk (buf, op, -range, -range, range, range)
{
- for (j = -range; j <= range; j++)
- {
- m = op->map;
- sx = op->x + i;
- sy = op->y + j;
-
- mflags = get_map_flags (m, &m, sx, sy, &sx, &sy);
- if (mflags & P_OUT_OF_MAP)
- continue;
+ mapspace &ms = m->at (nx, ny);
- if (mflags & P_IS_ALIVE)
- {
- for (tmp = GET_MAP_OB (m, sx, sy); tmp; tmp = tmp->above)
- if (QUERY_FLAG (tmp, FLAG_ALIVE) || tmp->type == PLAYER)
- break;
+ if (ms.flags () & P_IS_ALIVE)
+ for (object *next, *tmp = ms.bot; tmp; tmp = next)
+ {
+ next = tmp->above;
- if (tmp)
- {
- if (tmp->head)
- tmp = tmp->head;
+ if (tmp->flag [FLAG_ALIVE] || tmp->is_player ())
+ {
+ tmp = tmp->head_ ();
- if ((friendly && !QUERY_FLAG (tmp, FLAG_FRIENDLY) && tmp->type != PLAYER) ||
- (!friendly && (QUERY_FLAG (tmp, FLAG_FRIENDLY) || tmp->type == 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), sx, sy, 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), sx, sy, op);
- }
- }
- }
- }
- }
+ 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;
return 1;
}
@@ -1353,7 +1328,6 @@
* CURSE
*
***************************************************************************/
-
int
cast_curse (object *op, object *caster, object *spell_ob, int dir)
{
@@ -1363,7 +1337,7 @@
tmp = get_pointed_target (op, (dir == 0) ? op->direction : dir, spell_ob->range, SPELL_GRACE);
if (!tmp)
{
- new_draw_info (NDI_UNIQUE, 0, op, "There is no one in that direction to curse.");
+ op->failmsg ("There is no one in that direction to curse.");
return 0;
}
@@ -1388,7 +1362,7 @@
if (!force)
{
- force = get_archetype (FORCE_NAME);
+ force = archetype::get (FORCE_NAME);
force->subtype = FORCE_CHANGE_ABILITY;
if (spell_ob->race)
@@ -1416,9 +1390,9 @@
}
force->duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob) * 50;
- force->speed = 1.f;
force->speed_left = -1.f;
- SET_FLAG (force, FLAG_APPLIED);
+ force->set_speed (1.f);
+ force->set_flag (FLAG_APPLIED);
if (god)
{
@@ -1441,8 +1415,8 @@
change_abil (tmp, force); /* Mostly to display any messages */
insert_ob_in_ob (force, tmp);
tmp->update_stats ();
- return 1;
+ return 1;
}
/**********************************************************************
@@ -1458,9 +1432,7 @@
mood_change (object *op, object *caster, object *spell)
{
object *tmp, *god, *head;
- int done_one, range, mflags, level, at, best_at;
- sint16 x, y, nx, ny;
- maptile *m;
+ int done_one, range, level, at, best_at;
const char *race;
/* We precompute some values here so that we don't have to keep
@@ -1476,147 +1448,140 @@
*/
if (!spell->race)
race = NULL;
- else if (god && !strcmp (spell->race, "GOD_SLAYING"))
+ else if (god && spell->race == shstr_GOD_SLAYING)
race = god->slaying;
- else if (god && !strcmp (spell->race, "GOD_FRIEND"))
+ else if (god && spell->race == shstr_GOD_FRIEND)
race = god->race;
else
race = spell->race;
- for (x = op->x - range; x <= op->x + range; x++)
- for (y = op->y - range; y <= op->y + range; y++)
- {
- done_one = 0;
- m = op->map;
- nx = x;
- ny = y;
- mflags = get_map_flags (m, &m, x, y, &nx, &ny);
- if (mflags & P_OUT_OF_MAP)
- continue;
-
- /* If there is nothing living on this space, no need to go further */
- if (!(mflags & P_IS_ALIVE))
- continue;
-
- // players can only affect spaces that they can actually see
- if (caster
- && caster->contr
- && caster->contr->darkness_at (m, nx, ny) == LOS_BLOCKED)
- continue;
-
- for (tmp = GET_MAP_TOP (m, nx, ny); tmp; tmp = tmp->below)
- if (QUERY_FLAG (tmp, FLAG_MONSTER))
- break;
-
- /* There can be living objects that are not monsters */
- if (!tmp || tmp->type == PLAYER)
- continue;
-
- /* Only the head has meaningful data, so resolve to that */
- if (tmp->head)
- head = tmp->head;
- else
- head = tmp;
-
- /* Make sure the race is OK. Likewise, only effect undead if spell specifically allows it */
- if (race && head->race && !strstr (race, head->race))
- continue;
-
- if (QUERY_FLAG (head, FLAG_UNDEAD) && !QUERY_FLAG (spell, FLAG_UNDEAD))
- continue;
-
- /* Now do a bunch of stuff related to saving throws */
- best_at = -1;
- if (spell->attacktype)
- {
- for (at = 0; at < NROFATTACKS; at++)
- if (spell->attacktype & (1 << at))
- if (best_at == -1 || head->resist[at] > head->resist[best_at])
- best_at = at;
-
- if (best_at == -1)
- at = 0;
- else
- {
- if (head->resist[best_at] == 100)
- continue;
- else
- at = head->resist[best_at] / 5;
- }
- at -= level / 5;
- if (did_make_save (head, head->level, at))
- continue;
- }
- else /* spell->attacktype */
- {
- /*
- Spell has no attacktype (charm & such), so we'll have a specific saving:
- * if spell level < monster level, no go
- * else, chance of effect = 20 + min( 50, 2 * ( spell level - monster level ) )
-
- The chance will then be in the range [20-70] percent, not too bad.
-
- This is required to fix the 'charm monster' abuse, where a player level 1 can
- charm a level 125 monster...
-
- Ryo, august 14th
- */
- if (head->level > level)
- continue;
-
- if (random_roll (0, 100, caster, PREFER_LOW) >= (20 + MIN (50, 2 * (level - head->level))))
- /* Failed, no effect */
- continue;
- }
+ dynbuf buf;
+ unordered_mapwalk (buf, op, -range, -range, range, range)
+ {
+ mapspace &ms = m->at (nx, ny);
- /* Done with saving throw. Now start affecting the monster */
+ /* If there is nothing living on this space, no need to go further */
+ if (!(ms.flags () & P_IS_ALIVE))
+ continue;
- /* aggravation */
- if (QUERY_FLAG (spell, FLAG_MONSTER))
- {
- CLEAR_FLAG (head, FLAG_SLEEP);
- remove_friendly_object (head);
- done_one = 1;
- head->enemy = op;
- }
+ // players can only affect spaces that they can actually see
+ if (caster
+ && caster->contr
+ && caster->contr->darkness_at (m, nx, ny) == LOS_BLOCKED)
+ continue;
- /* calm monsters */
- if (QUERY_FLAG (spell, FLAG_UNAGGRESSIVE) && !QUERY_FLAG (head, FLAG_UNAGGRESSIVE))
- {
- SET_FLAG (head, FLAG_UNAGGRESSIVE);
- head->enemy = NULL;
- done_one = 1;
- }
+ for (tmp = ms.top; tmp; tmp = tmp->below)
+ if (tmp->flag [FLAG_MONSTER])
+ break;
- /* berserk monsters */
- if (QUERY_FLAG (spell, FLAG_BERSERK) && !QUERY_FLAG (head, FLAG_BERSERK))
- {
- SET_FLAG (head, FLAG_BERSERK);
- done_one = 1;
- }
+ /* There can be living objects that are not monsters */
+ if (!tmp)
+ continue;
- /* charm */
- if (QUERY_FLAG (spell, FLAG_NO_ATTACK) && !QUERY_FLAG (head, FLAG_FRIENDLY))
- {
- INVOKE_OBJECT (KILL, head, ARG_OBJECT (caster));
+ /* Only the head has meaningful data, so resolve to that */
+ head = tmp->head_ ();
- /* Prevent uncontrolled outbreaks of self replicating monsters.
- Typical use case is charm, go somwhere, use aggravation to make hostile.
- This could lead to fun stuff like mice outbreak in bigworld and server crawl. */
- CLEAR_FLAG (head, FLAG_GENERATOR);
- head->set_owner (op);
- set_spell_skill (op, caster, spell, head);
- add_friendly_object (head);
- head->attack_movement = PETMOVE;
- done_one = 1;
- change_exp (op, head->stats.exp / 2, head->skill, SK_EXP_ADD_SKILL);
- head->stats.exp = 0;
- }
+ /* Make sure the race is OK. Likewise, only effect undead if spell specifically allows it */
+ if (race && head->race && !strstr (race, head->race))
+ continue;
+
+ if (head->flag [FLAG_UNDEAD] && !spell->flag [FLAG_UNDEAD])
+ continue;
- /* 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);
- } /* for y */
+ /* Now do a bunch of stuff related to saving throws */
+ best_at = -1;
+ if (spell->attacktype)
+ {
+ for (at = 0; at < NROFATTACKS; at++)
+ if (spell->attacktype & (1 << at))
+ if (best_at == -1 || head->resist[at] > head->resist[best_at])
+ best_at = at;
+
+ if (best_at == -1)
+ at = 0;
+ else
+ {
+ if (head->resist[best_at] == 100)
+ continue;
+ else
+ at = head->resist[best_at] / 5;
+ }
+
+ at -= level / 5;
+ if (did_make_save (head, head->level, at))
+ continue;
+ }
+ else /* spell->attacktype */
+ {
+ /*
+ Spell has no attacktype (charm & such), so we'll have a specific saving:
+ * if spell level < monster level, no go
+ * else, chance of effect = 20 + min( 50, 2 * ( spell level - monster level ) )
+
+ The chance will then be in the range [20-70] percent, not too bad.
+
+ This is required to fix the 'charm monster' abuse, where a player level 1 can
+ charm a level 125 monster...
+
+ Ryo, august 14th
+ */
+ if (head->level > level)
+ continue;
+
+ if (random_roll (0, 100, caster, PREFER_LOW) >= (20 + min (50, 2 * (level - head->level))))
+ /* Failed, no effect */
+ continue;
+ }
+
+ /* Done with saving throw. Now start affecting the monster */
+ done_one = 0;
+
+ /* aggravation */
+ if (spell->flag [FLAG_MONSTER])
+ {
+ head->clr_flag (FLAG_SLEEP);
+ remove_friendly_object (head);
+ done_one = 1;
+ head->enemy = op;
+ }
+
+ /* calm monsters */
+ if (spell->flag [FLAG_UNAGGRESSIVE] && !head->flag [FLAG_UNAGGRESSIVE])
+ {
+ head->set_flag (FLAG_UNAGGRESSIVE);
+ head->enemy = NULL;
+ done_one = 1;
+ }
+
+ /* berserk monsters */
+ if (spell->flag [FLAG_BERSERK] && !head->flag [FLAG_BERSERK])
+ {
+ head->set_flag (FLAG_BERSERK);
+ done_one = 1;
+ }
+
+ /* charm */
+ if (spell->flag [FLAG_NO_ATTACK] && !head->flag [FLAG_FRIENDLY])
+ {
+ INVOKE_OBJECT (KILL, head, ARG_OBJECT (caster));
+
+ /* Prevent uncontrolled outbreaks of self replicating monsters.
+ Typical use case is charm, go somwhere, use aggravation to make hostile.
+ This could lead to fun stuff like mice outbreak in bigworld and server crawl. */
+ head->clr_flag (FLAG_GENERATOR);
+ head->set_owner (op);
+ set_spell_skill (op, caster, spell, head);
+ add_friendly_object (head);
+ head->attack_movement = PETMOVE;
+ done_one = 1;
+ change_exp (op, head->stats.exp / 2, head->skill, SK_EXP_ADD_SKILL);
+ head->stats.exp = 0;
+ }
+
+ /* If a monster was effected, put an effect in */
+ if (done_one && spell->other_arch)
+ m->insert (spell->other_arch->instance (), nx, ny, op);
+ }
return 1;
}
@@ -1658,8 +1623,8 @@
int offset = ((i ^ j) & 1) ? (i / 2) : -(i / 2);
int tmpdir = absdir (op->direction + offset);
- nx = op->x + freearr_x[tmpdir];
- ny = op->y + freearr_y[tmpdir];
+ nx = op->x + DIRX (tmpdir);
+ ny = op->y + DIRY (tmpdir);
if (!(get_map_flags (op->map, &m, nx, ny, &nx, &ny) & P_OUT_OF_MAP) && !(OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, nx, ny))))
{
dir = tmpdir;
@@ -1676,7 +1641,7 @@
m->insert (op, nx, ny, op);
- dam_save = op->stats.dam; /* save the original dam: we do halfdam on
+ dam_save = op->stats.dam; /* save the original dam: we do halfdam on
surrounding squares */
/* loop over current square and neighbors to hit.
@@ -1685,8 +1650,8 @@
*/
for (j = 0; j < 9; j++)
{
- hx = nx + freearr_x[j];
- hy = ny + freearr_y[j];
+ hx = nx + DIRX (j);
+ hy = ny + DIRY (j);
m = op->map;
mflags = get_map_flags (m, &m, hx, hy, &hx, &hy);
@@ -1708,7 +1673,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 */
@@ -1719,7 +1684,7 @@
if (i >= 0)
{ /* we have a preferred direction! */
/* pick another direction if the preferred dir is blocked. */
- if (get_map_flags (op->map, &m, nx + freearr_x[i], ny + freearr_y[i], &hx, &hy) & P_OUT_OF_MAP ||
+ if (get_map_flags (op->map, &m, nx + DIRX (i), ny + DIRY (i), &hx, &hy) & P_OUT_OF_MAP ||
OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, hx, hy)))
i = absdir (i + rndm (0, 2) - 1); /* -1, 0, +1 */
@@ -1727,12 +1692,12 @@
}
}
-/* move_swarm_spell: peterm
+/* move_swarm_spell: peterm
* This is an implementation of the swarm spell. It was written for
* meteor swarm, but it could be used for any swarm. A swarm spell
* is a special type of object that casts swarms of other types
* of spells. Which spell it casts is flexible. It fires the spells
- * from a set of squares surrounding the caster, in a given direction.
+ * from a set of squares surrounding the caster, in a given direction.
*/
void
move_swarm_spell (object *op)
@@ -1778,7 +1743,7 @@
// (schmorp)
/* new offset calculation to make swarm element distribution
- * more uniform
+ * more uniform
*/
if (op->duration)
{
@@ -1796,14 +1761,14 @@
adjustdir = 0; /* fire the last one from forward. */
}
- target_x = op->x + freearr_x[absdir (basedir + adjustdir)];
- target_y = op->y + freearr_y[absdir (basedir + adjustdir)];
+ target_x = op->x + DIRX (absdir (basedir + adjustdir));
+ target_y = op->y + DIRY (absdir (basedir + adjustdir));
/* back up one space so we can hit point-blank targets, but this
- * necessitates extra out_of_map check below
+ * necessitates extra out_of_map check below
*/
- origin_x = target_x - freearr_x[basedir];
- origin_y = target_y - freearr_y[basedir];
+ origin_x = target_x - DIRX (basedir);
+ origin_y = target_y - DIRY (basedir);
/* spell pointer is set up for the spell this casts. Since this
@@ -1844,7 +1809,7 @@
/* fire_swarm:
* The following routine creates a swarm of objects. It actually
* sets up a specific swarm object, which then fires off all
- * the parts of the swarm.
+ * the parts of the swarm.
*
* op: the owner
* caster: the caster (owner, wand, rod, scroll)
@@ -1899,22 +1864,22 @@
if (dir)
{
- x = op->x + freearr_x[dir];
- y = op->y + freearr_y[dir];
+ x = op->x + DIRX (dir);
+ y = op->y + DIRY (dir);
m = op->map;
mflags = get_map_flags (m, &m, x, y, &x, &y);
if (mflags & P_OUT_OF_MAP)
{
- new_draw_info (NDI_UNIQUE, 0, op, "Nothing is there.");
+ op->failmsg ("Nothing is there.");
return 0;
}
if (mflags & P_IS_ALIVE && spell->attacktype)
{
for (target = GET_MAP_OB (m, x, y); target; target = target->above)
- if (QUERY_FLAG (target, FLAG_MONSTER))
+ if (target->flag [FLAG_MONSTER])
{
/* oky doky. got a target monster. Lets make a blinding attack */
if (target->head)
@@ -1928,13 +1893,13 @@
/* no live target, perhaps a wall is in the way? */
if (OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y)))
{
- new_draw_info (NDI_UNIQUE, 0, op, "Something is in the way.");
+ op->failmsg ("Something is in the way.");
return 0;
}
}
/* 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");
@@ -1944,18 +1909,20 @@
tmp->stats.food = spell->duration + SP_level_duration_adjust (caster, spell);
if (tmp->glow_radius)
- tmp->glow_radius = min (MAX_LIGHT_RADIUS, spell->range + SP_level_range_adjust (caster, spell));
+ tmp->set_glow_radius (
+ 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;
}
/* cast_cause_disease: this spell looks along from the
- * player and infects someone.
+ * player and infects someone.
* op is the player/monster, caster is the object, dir is the direction
* to cast, disease_arch is the specific disease, and type is the spell number
* perhaps this should actually be in disease.c?
@@ -1971,7 +1938,7 @@
x = op->x;
y = op->y;
- /* If casting from a scroll, no direction will be available, so refer to the
+ /* If casting from a scroll, no direction will be available, so refer to the
* direction the player is pointing.
*/
if (!dir)
@@ -1988,8 +1955,8 @@
/* search in a line for a victim */
for (i = 1; i < range; i++)
{
- x = op->x + i * freearr_x[dir];
- y = op->y + i * freearr_y[dir];
+ x = op->x + i * DIRX (dir);
+ y = op->y + i * DIRY (dir);
m = op->map;
mflags = get_map_flags (m, &m, x, y, &x, &y);
@@ -2006,9 +1973,9 @@
{
/* search this square for a victim */
for (walk = GET_MAP_OB (m, x, y); walk; walk = walk->above)
- if (QUERY_FLAG (walk, FLAG_MONSTER) || (walk->type == PLAYER))
+ if (walk->flag [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);
@@ -2016,59 +1983,32 @@
disease->level = casting_level (caster, spell);
/* do level adjustments */
- if (disease->stats.wc)
- disease->stats.wc += dur_mod / 2;
-
- if (disease->magic > 0)
- disease->magic += dur_mod / 8;
-
- if (disease->stats.maxhp > 0)
- disease->stats.maxhp += dur_mod;
-
- if (disease->stats.maxgrace > 0)
- disease->stats.maxgrace += dur_mod;
-
- if (disease->stats.dam)
- {
- if (disease->stats.dam > 0)
- disease->stats.dam += dam_mod;
- else
- disease->stats.dam -= dam_mod;
- }
+ if (disease->stats.wc ) disease->stats.wc += dur_mod / 2;
+ if (disease->magic > 0) disease->magic += dur_mod / 8;
+ if (disease->stats.maxhp > 0) disease->stats.maxhp += dur_mod;
+ if (disease->stats.maxgrace > 0) disease->stats.maxgrace += dur_mod;
if (disease->last_sp)
{
disease->last_sp -= 2 * dam_mod;
+
if (disease->last_sp < 1)
disease->last_sp = 1;
}
- if (disease->stats.maxsp)
- {
- if (disease->stats.maxsp > 0)
- disease->stats.maxsp += dam_mod;
- else
- disease->stats.maxsp -= dam_mod;
- }
-
- if (disease->stats.ac)
- disease->stats.ac += dam_mod;
-
- if (disease->last_eat)
- disease->last_eat -= dam_mod;
-
- if (disease->stats.hp)
- disease->stats.hp -= dam_mod;
-
- if (disease->stats.sp)
- disease->stats.sp -= dam_mod;
+ if (disease->stats.dam ) disease->stats.dam += copysignl (disease->stats.dam , dam_mod);
+ if (disease->stats.maxsp) disease->stats.maxsp += copysignl (disease->stats.maxsp, dam_mod);
+ if (disease->stats.ac ) disease->stats.ac += dam_mod;
+ if (disease->last_eat ) disease->last_eat -= dam_mod;
+ if (disease->stats.hp ) disease->stats.hp -= dam_mod;
+ if (disease->stats.sp ) disease->stats.sp -= dam_mod;
if (infect_object (walk, disease, 1))
{
- new_draw_info_format (NDI_UNIQUE, 0, op, "You inflict %s on %s!", &disease->name, &walk->name);
+ op->statusmsg (format ("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 (archetype::get (shstr_detect_magic), x, y, op);
return 1;
}