--- deliantra/server/server/spell_attack.C 2008/12/28 07:48:44 1.74 +++ deliantra/server/server/spell_attack.C 2009/03/02 11:45:19 1.83 @@ -830,18 +830,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, @@ -1117,9 +1113,11 @@ * 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."); return 0; @@ -1136,7 +1134,7 @@ 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."); @@ -1260,11 +1258,11 @@ tmp->speed = 0.01; tmp->stats.food = time; SET_FLAG (tmp, FLAG_IS_USED_UP); - tmp->glow_radius = min (MAX_LIGHT_RADIUS, radius); + 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; } @@ -1435,9 +1433,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 @@ -1453,147 +1449,139 @@ */ 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; - } - - /* Done with saving throw. Now start affecting the monster */ - - /* aggravation */ - if (QUERY_FLAG (spell, FLAG_MONSTER)) - { - CLEAR_FLAG (head, FLAG_SLEEP); - remove_friendly_object (head); - done_one = 1; - head->enemy = op; - } - - /* calm monsters */ - if (QUERY_FLAG (spell, FLAG_UNAGGRESSIVE) && !QUERY_FLAG (head, FLAG_UNAGGRESSIVE)) - { - SET_FLAG (head, FLAG_UNAGGRESSIVE); - head->enemy = NULL; - done_one = 1; - } - - /* berserk monsters */ - if (QUERY_FLAG (spell, FLAG_BERSERK) && !QUERY_FLAG (head, FLAG_BERSERK)) - { - SET_FLAG (head, FLAG_BERSERK); - done_one = 1; - } - - /* charm */ - if (QUERY_FLAG (spell, FLAG_NO_ATTACK) && !QUERY_FLAG (head, 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. */ - 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; - } - - /* 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 */ + unordered_mapwalk (op, -range, -range, range, range) + { + mapspace &ms = m->at (nx, ny); + + /* If there is nothing living on this space, no need to go further */ + if (!ms.flags () & 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 = ms.top; tmp; tmp = tmp->below) + if (tmp->flag [FLAG_MONSTER]) + break; + + /* There can be living objects that are not monsters */ + if (!tmp) + continue; + + /* Only the head has meaningful data, so resolve to that */ + head = tmp->head_ (); + + /* 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; + } + + /* Done with saving throw. Now start affecting the monster */ + done_one = 0; + + /* aggravation */ + if (QUERY_FLAG (spell, FLAG_MONSTER)) + { + CLEAR_FLAG (head, FLAG_SLEEP); + remove_friendly_object (head); + done_one = 1; + head->enemy = op; + } + + /* calm monsters */ + if (QUERY_FLAG (spell, FLAG_UNAGGRESSIVE) && !QUERY_FLAG (head, FLAG_UNAGGRESSIVE)) + { + SET_FLAG (head, FLAG_UNAGGRESSIVE); + head->enemy = NULL; + done_one = 1; + } + + /* berserk monsters */ + if (QUERY_FLAG (spell, FLAG_BERSERK) && !QUERY_FLAG (head, FLAG_BERSERK)) + { + SET_FLAG (head, FLAG_BERSERK); + done_one = 1; + } + + /* charm */ + if (QUERY_FLAG (spell, FLAG_NO_ATTACK) && !QUERY_FLAG (head, 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. */ + 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; + } + + /* 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); + } return 1; } @@ -1921,7 +1909,8 @@ 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 ( + min (MAX_LIGHT_RADIUS, spell->range + SP_level_range_adjust (caster, spell))); if (dir) m->insert (tmp, x, y, op);