--- deliantra/server/server/spell_attack.C 2008/05/17 14:11:13 1.57 +++ deliantra/server/server/spell_attack.C 2008/09/29 10:20:49 1.65 @@ -41,7 +41,6 @@ void check_spell_knockback (object *op) { - object *tmp, *tmp2; /* object on the map */ int weight_move; int frictionmod = 2; /*poor man's physics - multipy targets weight by this amount */ @@ -56,7 +55,7 @@ /*LOG (llevDebug, "DEBUG: arch weighs %d and masses %d (%s,level %d)\n", op->weight,weight_move,op->name,op->level); */ } - for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) + for (object *tmp = op->ms ().bot; tmp; tmp = tmp->above) { int num_sections = 1; @@ -73,7 +72,7 @@ continue; /* count the object's sections */ - for (tmp2 = tmp; tmp2 != NULL; tmp2 = tmp2->more) + for (object *tmp2 = tmp; tmp2; tmp2 = tmp2->more) num_sections++; /* I'm not sure if it makes sense to divide by num_sections - bigger @@ -151,6 +150,7 @@ new_bolt->stats.dam++; tmp->stats.dam /= 2; /* reduce father bolt damage */ tmp->stats.dam++; + if ((new_bolt = m->insert (new_bolt, sx, sy, op))) update_turn_face (new_bolt); } @@ -158,7 +158,6 @@ /* move_bolt: moves bolt 'op'. Basically, it just advances a space, * and checks for various things that may stop it. */ - void move_bolt (object *op) { @@ -168,7 +167,8 @@ if (--op->duration < 0) { - op->destroy (); + op->destroy_inv (true); // be explicit about dropping + op->destroy (true); return; } @@ -251,10 +251,8 @@ /* New forking code. Possibly create forks of this object * going off in other directions. */ - if (rndm (0, 99) < tmp->stats.Dex) - { /* stats.Dex % of forking */ - forklightning (op, tmp); - } + if (tmp->stats.Dex && rndm (0, 99) < tmp->stats.Dex) + forklightning (op, tmp); /* stats.Dex % of forking */ /* In this way, the object left behind sticks on the space, but * doesn't create any bolts that continue to move onward. @@ -288,8 +286,10 @@ /* peterm: level dependency for bolts */ tmp->stats.dam = spob->stats.dam + SP_level_dam_adjust (caster, spob); tmp->attacktype = spob->attacktype; + if (spob->slaying) tmp->slaying = spob->slaying; + tmp->range = spob->range + SP_level_range_adjust (caster, spob); tmp->duration = spob->duration + SP_level_duration_adjust (caster, spob); tmp->stats.Dex = spob->stats.Dex; @@ -310,7 +310,8 @@ mflags = get_map_flags (tmp->map, &newmap, tmp->x, tmp->y, &tmp->x, &tmp->y); if (mflags & P_OUT_OF_MAP) { - tmp->destroy (); + tmp->destroy_inv (true); // be explicit about dropping + tmp->destroy (true); return 0; } @@ -320,7 +321,8 @@ { if (!QUERY_FLAG (tmp, FLAG_REFLECTING)) { - tmp->destroy (); + tmp->destroy_inv (true); // be explicit about dropping + tmp->destroy (true); return 0; } @@ -354,7 +356,7 @@ if (--op->duration < 0) { - op->destroy (); + op->destroy (true); return; } @@ -396,10 +398,10 @@ { object *tmp, *owner; - if (op->other_arch == NULL) + if (!op->other_arch) { LOG (llevError, "BUG: explode_bullet(): op without other_arch\n"); - op->destroy (); + op->destroy (true); return; } @@ -410,7 +412,7 @@ if (!env->map || out_of_map (env->map, env->x, env->y)) { LOG (llevError, "BUG: explode_bullet(): env out of map\n"); - op->destroy (); + op->destroy (true); return; } @@ -419,7 +421,7 @@ else if (out_of_map (op->map, op->x, op->y)) { LOG (llevError, "BUG: explode_bullet(): op out of map\n"); - op->destroy (); + op->destroy (true); return; } @@ -428,13 +430,14 @@ // bad at the moment that might happen from this. if (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_SAFE) { - op->destroy (); + op->destroy (true); return; } if (op->attacktype) { hit_map (op, 0, op->attacktype, 1); + if (op->destroyed ()) return; } @@ -447,9 +450,12 @@ owner = op->owner; - if ((tmp->attacktype & AT_HOLYWORD || tmp->attacktype & AT_GODPOWER) && owner && !tailor_god_spell (tmp, owner)) + if ((tmp->attacktype & AT_HOLYWORD + || tmp->attacktype & AT_GODPOWER) + && owner + && !tailor_god_spell (tmp, owner)) { - op->destroy (); + op->destroy (true); return; } @@ -487,7 +493,7 @@ tmp->play_sound (tmp->sound); /* remove the firebullet */ - op->destroy (); + op->destroy (true); } /* checks to see what op should do, given the space it is on @@ -522,11 +528,13 @@ if (QUERY_FLAG (tmp, 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)) { - op->destroy (); + op->destroy (true); return; } } @@ -565,7 +573,7 @@ if (op->other_arch) explode_bullet (op); else - op->destroy (); + op->destroy (true); return; } @@ -577,7 +585,7 @@ if (mflags & P_OUT_OF_MAP) { - op->destroy (); + op->destroy (true); return; } @@ -586,7 +594,7 @@ if (op->other_arch) explode_bullet (op); else - op->destroy (); + op->destroy (true); return; } @@ -652,7 +660,7 @@ mflags = get_map_flags (tmp->map, &newmap, tmp->x, tmp->y, &tmp->x, &tmp->y); if (mflags & P_OUT_OF_MAP) { - tmp->destroy (); + tmp->destroy (true); return 0; } @@ -662,7 +670,7 @@ { if (!QUERY_FLAG (tmp, FLAG_REFLECTING)) { - tmp->destroy (); + tmp->destroy (true); return 0; } @@ -705,8 +713,6 @@ void move_cone (object *op) { - int i; - /* if no map then hit_map will crash so just ignore object */ if (!op->map) { @@ -729,7 +735,7 @@ /* If no owner left, the spell dies out. */ if (op->owner == NULL) { - op->destroy (); + op->destroy (true); return; } #endif @@ -746,9 +752,9 @@ if (op->destroyed ()) return; - if ((op->duration--) < 0) + if (op->duration-- < 0) { - op->destroy (); + op->destroy (true); return; } /* Object has hit maximum range, so don't have it move @@ -761,7 +767,7 @@ return; } - for (i = -1; i < 2; i++) + 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)]; @@ -863,7 +869,7 @@ tmp = arch_to_object (spell->other_arch); tmp->set_owner (op); set_spell_skill (op, caster, spell, tmp); - tmp->level = caster_level (caster, spell); + tmp->level = casting_level (caster, spell); tmp->attacktype = spell->attacktype; /* holy word stuff */ @@ -957,7 +963,7 @@ // as bombs can be carried. if (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_SAFE) { - op->destroy (); + op->destroy (true); return; } @@ -1115,7 +1121,7 @@ return 0; /* tailor the effect by priest level and worshipped God */ - effect->level = caster_level (caster, spell); + effect->level = casting_level (caster, spell); effect->attacktype = spell->attacktype; if (effect->attacktype & (AT_HOLYWORD | AT_GODPOWER)) { @@ -1149,7 +1155,7 @@ { new_draw_info_format (NDI_UNIQUE, 0, op, "The %s looks stronger!", query_name (target)); target->stats.hp = target->stats.maxhp * 2; - effect->destroy (); + effect->destroy (true); return 0; } } @@ -1180,62 +1186,48 @@ void move_missile (object *op) { - int i, mflags; - object *owner; - sint16 new_x, new_y; - maptile *m; - if (op->range-- <= 0) { - op->destroy (); + op->destroy_inv (true); // be explicit about dropping + op->destroy (true); return; } - owner = op->owner; -#if 0 - /* It'd make things nastier if this wasn't here - spells cast by - * monster that are then killed would continue to survive - */ - if (owner == NULL) + mapxy pos (op); + pos.move (op->direction); + + if (!pos.normalise ()) { - op->destroy (); + op->destroy (true); return; } -#endif - new_x = op->x + DIRX (op); - new_y = op->y + DIRY (op); + mapspace &ms = pos.ms (); - mflags = get_map_flags (op->map, &m, new_x, new_y, &new_x, &new_y); - - if (!(mflags & P_OUT_OF_MAP) && ((mflags & P_IS_ALIVE) || OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, new_x, new_y)))) + if (ms.flags () & P_IS_ALIVE || ms.blocks (op)) { hit_map (op, op->direction, AT_MAGIC, 1); /* Basically, missile only hits one thing then goes away. * we need to remove it if someone hasn't already done so. */ - if (!op->destroyed ()) - op->destroy (); - + op->destroy (true); return; } - op->remove (); - - if (!op->direction || (mflags & P_OUT_OF_MAP)) + if (!op->direction) { - op->destroy (); + op->destroy (true); return; } - i = spell_find_dir (m, new_x, new_y, op->owner); + int i = spell_find_dir (pos.m, pos.x, pos.y, op->owner); if (i > 0 && i != op->direction) { op->direction = i; SET_ANIMATION (op, op->direction); } - m->insert (op, new_x, new_y, op); + pos.insert (op, op); } /**************************************************************************** @@ -1302,9 +1294,9 @@ op->change_skill (find_skill_by_name (op, op->skill)); - for (i = -range; i < range; i++) + for (i = -range; i <= range; i++) { - for (j = -range; j < range; j++) + for (j = -range; j <= range; j++) { m = op->map; sx = op->x + i; @@ -1331,6 +1323,7 @@ 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); } @@ -1468,7 +1461,7 @@ * doing it over and over again. */ god = find_god (determine_god (op)); - level = caster_level (caster, spell); + level = casting_level (caster, spell); range = spell->range + SP_level_range_adjust (caster, spell); /* On the bright side, no monster should ever have a race of GOD_... @@ -1628,7 +1621,6 @@ * op is the spell effect. * note that duration is handled by process_object() in time.c */ - void move_ball_spell (object *op) { @@ -1704,8 +1696,8 @@ { if (j) op->stats.dam = dam_save / 2; - hit_map (op, j, op->attacktype, 1); + hit_map (op, j, op->attacktype, 1); } /* insert the other arch */ @@ -1748,9 +1740,17 @@ #endif object *owner = op->env; + if (!owner) // MUST not happen, remove when true TODO + { + LOG (llevError, "swarm spell found outside inventory: %s\n", op->debug_desc ()); + op->destroy (true); + return; + } + if (!op->duration || !owner->is_on_map ()) { - op->destroy (); + op->destroy_inv (true); // be explicit about dropping + op->destroy (true); return; } @@ -1758,8 +1758,11 @@ int basedir = op->direction; if (!basedir) - /* spray in all directions! 8) */ - basedir = (op->facing += op->state) % 8 + 1; + { + /* spray in all directions! 8) */ + op->facing = (op->facing + op->state) & 7; + basedir = op->facing + 1; + } #if 0 // this is bogus: it causes wrong places to be checked below @@ -1851,8 +1854,9 @@ return 0; object *tmp = archetype::get (SWARM_SPELL); + set_spell_skill (op, caster, spell, tmp); - tmp->level = caster_level (caster, spell); /* needed later, to get level dep. right. */ + tmp->level = casting_level (caster, spell); /* needed later, to get level dep. right. */ tmp->spell = spell->other_arch->instance (); tmp->attacktype = tmp->spell->attacktype; @@ -1864,8 +1868,9 @@ for (int i = 0; i < spell->duration; i++) tmp->duration += die_roll (1, 3, op, PREFER_HIGH); - tmp->direction = dir; tmp->invisible = 1; + tmp->flag [FLAG_NO_DROP] = 1; // make sure it stays in inv, or else + tmp->direction = dir; tmp->facing = rndm (1, 8); // initial firing direction tmp->state = rndm (4) * 2 + 1; // direction increment @@ -1913,7 +1918,8 @@ /* oky doky. got a target monster. Lets make a blinding attack */ if (target->head) target = target->head; - (void) hit_player (target, dam, op, spell->attacktype, 1); + + hit_player (target, dam, op, spell->attacktype, 1); return 1; /* one success only! */ } } @@ -2003,7 +2009,7 @@ disease->set_owner (op); set_spell_skill (op, caster, spell, disease); disease->stats.exp = 0; - disease->level = caster_level (caster, spell); + disease->level = casting_level (caster, spell); /* do level adjustments */ if (disease->stats.wc) @@ -2057,12 +2063,12 @@ { 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 */ + disease->destroy (true); /* don't need this one anymore */ walk->map->insert (get_archetype ("detect_magic"), x, y, op); return 1; } - disease->destroy (); + disease->destroy (true); } } /* if living creature */ } /* for range of spaces */