From bad09911df71edf9399974fb619ff79e4797fa5e Mon Sep 17 00:00:00 2001 From: Darshan Shaligram Date: Mon, 28 Dec 2009 23:05:38 +0530 Subject: Place clumps of plants on Shoals levels. --- crawl-ref/source/dgn-shoals.cc | 338 ++++++++++++++++++++++++++++++++++++++++- crawl-ref/source/dungeon.cc | 24 +-- crawl-ref/source/dungeon.h | 3 + 3 files changed, 352 insertions(+), 13 deletions(-) diff --git a/crawl-ref/source/dgn-shoals.cc b/crawl-ref/source/dgn-shoals.cc index a3a2b12ea9..10b49fafb8 100644 --- a/crawl-ref/source/dgn-shoals.cc +++ b/crawl-ref/source/dgn-shoals.cc @@ -9,6 +9,7 @@ #include "flood_find.h" #include "items.h" #include "maps.h" +#include "mgen_data.h" #include "mon-place.h" #include "mon-util.h" #include "random.h" @@ -18,6 +19,9 @@ #include #include +typedef FixedArray grid_bool; +typedef FixedArray grid_short; + const char *ENVP_SHOALS_TIDE_KEY = "shoals-tide-height"; const char *ENVP_SHOALS_TIDE_VEL = "shoals-tide-velocity"; @@ -401,7 +405,8 @@ static void _shoals_furniture(int margin) const coord_def p = _pick_shoals_island_distant_from(c); // Place the rune const map_def *vault = random_map_for_tag("shoal_rune"); - dgn_place_map(vault, false, true, p); + dgn_ensure_vault_placed(dgn_place_map(vault, false, true, p), + false); const int nhuts = std::min(8, int(_shoals_islands.size())); for (int i = 2; i < nhuts; ++i) @@ -464,6 +469,334 @@ static void _shoals_deepen_edges() } } +static int _shoals_contiguous_feature_flood( + FixedArray &rmap, + coord_def c, + dungeon_feature_type feat, + int nregion, + int size_limit) +{ + std::vector visit; + visit.push_back(c); + int npoints = 1; + for (size_t i = 0; i < visit.size() && npoints < size_limit; ++i) + { + const coord_def p(visit[i]); + rmap(p) = nregion; + + if (npoints < size_limit) + { + for (adjacent_iterator ai(p); ai && npoints < size_limit; ++ai) + { + const coord_def adj(*ai); + if (in_bounds(adj) && !rmap(adj) && grd(adj) == feat + && unforbidden(adj, MMT_VAULT)) + { + rmap(adj) = nregion; + visit.push_back(adj); + ++npoints; + } + } + } + } + return npoints; +} + +static coord_def _shoals_region_center( + FixedArray &rmap, + coord_def c) +{ + const int nregion(rmap(c)); + int nseen = 0; + + double cx = 0.0, cy = 0.0; + std::vector visit; + visit.push_back(c); + FixedArray visited(false); + for (size_t i = 0; i < visit.size(); ++i) + { + const coord_def p(visit[i]); + visited(p) = true; + + ++nseen; + if (nseen == 1) + { + cx = p.x; + cy = p.y; + } + else + { + cx = (cx * (nseen - 1) + p.x) / nseen; + cy = (cy * (nseen - 1) + p.y) / nseen; + } + + for (adjacent_iterator ai(p); ai; ++ai) + { + const coord_def adj(*ai); + if (in_bounds(adj) && !visited(adj) && rmap(adj) == nregion) + { + visited(adj) = true; + visit.push_back(adj); + } + } + } + + const coord_def cgravity(cx, cy); + coord_def closest_to_center; + int closest_distance = 0; + for (int i = 0, size = visit.size(); i < size; ++i) + { + const coord_def p(visit[i]); + const int dist2 = (p - cgravity).abs(); + if (closest_to_center.origin() || closest_distance > dist2) + { + closest_to_center = p; + closest_distance = dist2; + } + } + return closest_to_center; +} + +struct weighted_region +{ + int weight; + coord_def pos; + + weighted_region(int _weight, coord_def _pos) : weight(_weight), pos(_pos) + { + } +}; + +static std::vector +_shoals_point_feat_cluster(dungeon_feature_type feat, + const int wanted_count, + grid_short ®ion_map) +{ + std::vector regions; + int region = 1; + for (rectangle_iterator ri(1); ri; ++ri) + { + coord_def c(*ri); + if (!region_map(c) && grd(c) == feat + && unforbidden(c, MMT_VAULT)) + { + const int featcount = + _shoals_contiguous_feature_flood(region_map, + c, + feat, + region++, + wanted_count * 3 / 2); + if (featcount >= wanted_count) + regions.push_back(weighted_region(featcount, c)); + } + } + return (regions); +} + +static coord_def _shoals_pick_region( + grid_short ®ion_map, + const std::vector ®ions) +{ + if (regions.empty()) + return coord_def(); + return _shoals_region_center(region_map, + regions[random2(regions.size())].pos); +} + +static void _shoals_make_plant_at(coord_def p) +{ + // [ds] Why is hostile_at() saddled with unnecessary parameters + // related to summoning? + mons_place(mgen_data::hostile_at(MONS_PLANT, "", false, 0, 0, p)); +} + +static bool _shoals_plantworthy_feat(dungeon_feature_type feat) +{ + return (feat == DNGN_SHALLOW_WATER || feat == DNGN_FLOOR); +} + +static void _shoals_make_plant_near(coord_def c, int radius, + dungeon_feature_type preferred_feat, + grid_bool *verboten) +{ + const int ntries = 5; + for (int i = 0; i < ntries; ++i) + { + const coord_def plant_place(_random_point_from(c, random2(1 + radius))); + if (!plant_place.origin() + && !monster_at(plant_place)) + { + const dungeon_feature_type feat(grd(plant_place)); + if (_shoals_plantworthy_feat(feat) + && (feat == preferred_feat || coinflip()) + && (!verboten || !(*verboten)(plant_place))) + { + _shoals_make_plant_at(plant_place); + return; + } + } + } +} + +static void _shoals_plant_cluster(coord_def c, int nplants, int radius, + dungeon_feature_type favoured_feat, + grid_bool *verboten) +{ + for (int i = 0; i < nplants; ++i) + _shoals_make_plant_near(c, radius, favoured_feat, verboten); +} + +static void _shoals_plant_supercluster(coord_def c, + dungeon_feature_type favoured_feat, + grid_bool *verboten = NULL) +{ + _shoals_plant_cluster(c, random_range(10, 25, 2), + random_range(3, 9), favoured_feat, + verboten); + + const int nadditional_clusters(std::max(0, random_range(-1, 4, 2))); + for (int i = 0; i < nadditional_clusters; ++i) + { + const coord_def satellite( + _random_point_from(c, random_range(2, 12))); + if (!satellite.origin()) + _shoals_plant_cluster(satellite, random_range(5, 23, 2), + random_range(2, 7), + favoured_feat, + verboten); + } +} + +static void _shoals_generate_water_plants(coord_def mangrove_central) +{ + if (!mangrove_central.origin()) + _shoals_plant_supercluster(mangrove_central, DNGN_SHALLOW_WATER); +} + +struct coord_dbl +{ + double x, y; + + coord_dbl(double _x, double _y) : x(_x), y(_y) { } + coord_dbl operator + (const coord_dbl &o) const + { + return coord_dbl(x + o.x, y + o.y); + } + coord_dbl &operator += (const coord_dbl &o) + { + x += o.x; + y += o.y; + return *this; + } +}; + +static coord_def _int_coord(const coord_dbl &c) +{ + return coord_def(c.x, c.y); +} + +static std::vector _shoals_windshadows(grid_bool &windy) +{ + const int wind_angle_degrees = random2(360); + const double wind_angle(_to_radians(wind_angle_degrees)); + const coord_dbl wi(cos(wind_angle), sin(wind_angle)); + const double epsilon = 1e-5; + + std::vector wind_points; + if (wi.x > epsilon || wi.x < -epsilon) + { + for (int y = 1; y < GYM - 1; ++y) + wind_points.push_back(coord_dbl(wi.x > epsilon ? 1 : GXM - 2, y)); + } + if (wi.y > epsilon || wi.y < -epsilon) + { + for (int x = 1; x < GXM - 1; ++x) + wind_points.push_back(coord_dbl(x, wi.y > epsilon ? 1 : GYM - 2)); + } + + for (size_t i = 0; i < wind_points.size(); ++i) + { + const coord_def here(_int_coord(wind_points[i])); + windy(here) = true; + + coord_dbl next = wind_points[i] + wi; + while (_int_coord(next) == here) + next += wi; + + const coord_def nextp(_int_coord(next)); + if (in_bounds(nextp) && !windy(nextp) && !feat_is_solid(grd(nextp))) + { + windy(nextp) = true; + wind_points.push_back(next); + } + } + + // To avoid plants cropping up inside vaults, mark everything inside + // vaults as "windy". + for (rectangle_iterator ri(1); ri; ++ri) + if (!unforbidden(*ri, MMT_VAULT)) + windy(*ri) = true; + + // Now we know the places in the wind shadow: + std::vector wind_shadows; + for (rectangle_iterator ri(1); ri; ++ri) + { + const coord_def p(*ri); + if (!windy(p) && grd(p) == DNGN_FLOOR + && (_has_adjacent_feat(p, DNGN_STONE_WALL) + || _has_adjacent_feat(p, DNGN_ROCK_WALL))) + wind_shadows.push_back(p); + } + return wind_shadows; +} + +static void _shoals_generate_wind_sheltered_plants( + std::vector &places, grid_bool &windy) +{ + if (places.empty()) + return; + + const int chosen = random2(places.size()); + const coord_def spot = places[random2(places.size())]; + places.erase(places.begin() + chosen); + + _shoals_plant_supercluster(spot, DNGN_FLOOR, &windy); +} + +static void _shoals_generate_flora() +{ + // Water clusters are groups of plants clustered near the water. + // Wind clusters are groups of plants clustered in wind shadow -- + // possibly because they can grow better without being exposed to the + // strong winds of the Shoals. + // + // Yeah, the strong winds aren't there yet, but they could be! + // + const int n_water_clusters = std::max(0, random_range(-1, 6, 2)); + const int n_wind_clusters = std::max(0, random_range(-2, 2, 2)); + + if (n_water_clusters) + { + grid_short region_map(0); + std::vector regions( + _shoals_point_feat_cluster(DNGN_SHALLOW_WATER, 6, region_map)); + + for (int i = 0; i < n_water_clusters; ++i) + { + const coord_def p(_shoals_pick_region(region_map, regions)); + _shoals_generate_water_plants(p); + } + } + + if (n_wind_clusters) + { + grid_bool windy(false); + std::vector wind_shadows = _shoals_windshadows(windy); + for (int i = 0; i < n_wind_clusters; ++i) + _shoals_generate_wind_sheltered_plants(wind_shadows, windy); + } +} + void prepare_shoals(int level_number) { dgn_Build_Method += make_stringf(" shoals+ [%d]", level_number); @@ -481,6 +814,9 @@ void prepare_shoals(int level_number) _shoals_deepen_edges(); _shoals_smooth_water(); _shoals_furniture(_shoals_margin); + + // This has to happen after placing shoal rune vault! + _shoals_generate_flora(); } // Search the map for vaults and set the terrain heights for features diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index 48268f2067..04ce67e162 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -897,8 +897,8 @@ void dgn_register_place(const vault_placement &place, bool register_vault) #endif } -static bool _ensure_vault_placed(bool vault_success, - bool disable_further_vaults) +bool dgn_ensure_vault_placed(bool vault_success, + bool disable_further_vaults) { if (!vault_success) dgn_level_vetoed = true; @@ -909,9 +909,9 @@ static bool _ensure_vault_placed(bool vault_success, static bool _ensure_vault_placed_ex( bool vault_success, const map_def *vault ) { - return _ensure_vault_placed( vault_success, - (!vault->has_tag("extra") - && vault->orient == MAP_ENCOMPASS) ); + return dgn_ensure_vault_placed( vault_success, + (!vault->has_tag("extra") + && vault->orient == MAP_ENCOMPASS) ); } static coord_def _find_level_feature(int feat) @@ -1766,7 +1766,7 @@ static void _build_overflow_temples(int level_number) // find the overflow temple map, so don't veto the level. return; - if (!_ensure_vault_placed(_build_vaults(level_number, vault), false)) + if (!dgn_ensure_vault_placed(_build_vaults(level_number, vault), false)) { #ifdef DEBUG_TEMPLES mprf(MSGCH_DIAGNOSTICS, "Couldn't place overlfow temple '%s', " @@ -2245,7 +2245,7 @@ static builder_rc_type _builder_by_type(int level_number, char level_type) pandemon_level_names[which_demon]); } - _ensure_vault_placed( _build_vaults(level_number, vault), true ); + dgn_ensure_vault_placed( _build_vaults(level_number, vault), true ); } else { @@ -2322,7 +2322,7 @@ static void _portal_vault_level(int level_number) dgn_replace_area(0, 0, GXM-1, GYM-1, DNGN_ROCK_WALL, vault->border_fill_type); - _ensure_vault_placed( _build_vaults(level_number, vault), true ); + dgn_ensure_vault_placed( _build_vaults(level_number, vault), true ); } else { @@ -6002,7 +6002,7 @@ static bool _plan_1(int level_number) ASSERT(vault); bool success = _build_vaults(level_number, vault); - _ensure_vault_placed(success, false); + dgn_ensure_vault_placed(success, false); return false; } @@ -6016,7 +6016,7 @@ static bool _plan_2(int level_number) ASSERT(vault); bool success = _build_vaults(level_number, vault); - _ensure_vault_placed(success, false); + dgn_ensure_vault_placed(success, false); return false; } @@ -6030,7 +6030,7 @@ static bool _plan_3(int level_number) ASSERT(vault); bool success = _build_vaults(level_number, vault); - _ensure_vault_placed(success, false); + dgn_ensure_vault_placed(success, false); return true; } @@ -6174,7 +6174,7 @@ static bool _plan_6(int level_number) ASSERT(vault); bool success = _build_vaults(level_number, vault); - _ensure_vault_placed(success, false); + dgn_ensure_vault_placed(success, false); // This "back door" is often one of the easier ways to get out of // pandemonium... the easiest is to use the banish spell. diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h index bc140c3f2e..f58c17355c 100644 --- a/crawl-ref/source/dungeon.h +++ b/crawl-ref/source/dungeon.h @@ -268,6 +268,9 @@ void dgn_replace_area(int sx, int sy, int ex, int ey, dungeon_feature_type feature, unsigned mmask = 0, bool needs_update = false); +bool dgn_ensure_vault_placed(bool vault_success, + bool disable_further_vaults); + inline int count_feature_in_box( const coord_def& p1, const coord_def& p2, dungeon_feature_type feat ) { -- cgit v1.2.3-54-g00ecf From e9017206fd30a9cb7981d42ee6f8f1809f2f2933 Mon Sep 17 00:00:00 2001 From: Darshan Shaligram Date: Tue, 29 Dec 2009 00:01:37 +0530 Subject: Experimental kraken adjustments. Boost kraken and tentacle damage. Force the tentacles to stay close to the body of the kraken to make the creature look more like a unit. Tentacles are now amphibious and can reach out onto land, although they cannot stray too far from the main body. --- crawl-ref/source/externs.h | 10 ++++++++++ crawl-ref/source/mon-act.cc | 22 ++++++++++++++++++++-- crawl-ref/source/mon-data.h | 8 ++++---- crawl-ref/source/mon-stuff.cc | 2 +- crawl-ref/source/monster.h | 2 ++ crawl-ref/source/stuff.h | 5 ----- 6 files changed, 37 insertions(+), 12 deletions(-) diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index 5f4f5e7e40..1c3a962d5d 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -92,6 +92,11 @@ class KillMaster; class ghost_demon; struct glyph; +template inline Z sgn(Z x) +{ + return (x < 0 ? -1 : (x > 0 ? 1 : 0)); +} + struct coord_def { int x; @@ -215,6 +220,11 @@ struct coord_def return (copy *= mul); } + coord_def sgn() const + { + return coord_def(::sgn(x), ::sgn(y)); + } + int abs() const { return (x * x + y * y); diff --git a/crawl-ref/source/mon-act.cc b/crawl-ref/source/mon-act.cc index 16c025e217..3fc1cea5a0 100644 --- a/crawl-ref/source/mon-act.cc +++ b/crawl-ref/source/mon-act.cc @@ -332,6 +332,24 @@ static void _maybe_set_patrol_route(monsters *monster) } } +// Keep kraken tentacles from wandering too far away from the boss monster. +static void _kraken_tentacle_movement_clamp(monsters *tentacle) +{ + if (tentacle->type != MONS_KRAKEN_TENTACLE) + return; + + const int kraken_idx = tentacle->number; + ASSERT(!invalid_monster_index(kraken_idx)); + + monsters *kraken = &menv[kraken_idx]; + const int distance_to_head = + grid_distance(tentacle->pos(), kraken->pos()); + // Beyond max distance, the only move the tentacle can make is + // back towards the head. + if (distance_to_head >= KRAKEN_TENTACLE_RANGE) + mmov = (kraken->pos() - tentacle->pos()).sgn(); +} + //--------------------------------------------------------------- // // handle_movement @@ -378,8 +396,7 @@ static void _handle_movement(monsters *monster) delta = monster->target - monster->pos(); // Move the monster. - mmov.x = (delta.x > 0) ? 1 : ((delta.x < 0) ? -1 : 0); - mmov.y = (delta.y > 0) ? 1 : ((delta.y < 0) ? -1 : 0); + mmov = delta.sgn(); if (mons_is_fleeing(monster) && monster->travel_target != MTRAV_WALL && (!monster->friendly() @@ -1849,6 +1866,7 @@ static void _handle_monster_move(monsters *monster) { // Calculates mmov based on monster target. _handle_movement(monster); + _kraken_tentacle_movement_clamp(monster); if (mons_is_confused(monster) || monster->type == MONS_AIR_ELEMENTAL diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h index 5d42867f4d..ad3414acae 100644 --- a/crawl-ref/source/mon-data.h +++ b/crawl-ref/source/mon-data.h @@ -3303,7 +3303,7 @@ static monsterentry mondata[] = { M_COLD_BLOOD | M_SPELLCASTER, MR_NO_FLAGS, 1500, 20, MONS_KRAKEN, MONS_KRAKEN, MH_NATURAL, -3, - { {AT_BITE, AF_PLAIN, 15}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, + { {AT_BITE, AF_PLAIN, 65}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, { 20, 10, 10, 0 }, 20, 0, MST_KRAKEN, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_ANIMAL, HT_WATER, FL_NONE, 10, DEFAULT_ENERGY, @@ -3315,10 +3315,10 @@ static monsterentry mondata[] = { M_COLD_BLOOD | M_NO_EXP_GAIN, MR_RES_ASPHYX, 0, 10, MONS_KRAKEN_TENTACLE, MONS_KRAKEN_TENTACLE, MH_NATURAL, MAG_IMMUNE, - { {AT_TENTACLE_SLAP, AF_PLAIN, 15}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, - { 5, 3, 5, 0 }, + { {AT_TENTACLE_SLAP, AF_PLAIN, 29}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, + { 12, 3, 2, 0 }, 5, 7, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, - I_ANIMAL, HT_WATER, FL_NONE, 10, DEFAULT_ENERGY, + I_ANIMAL, HT_AMPHIBIOUS_WATER, FL_NONE, 10, DEFAULT_ENERGY, MONUSE_NOTHING, MONEAT_NOTHING, SIZE_LARGE }, diff --git a/crawl-ref/source/mon-stuff.cc b/crawl-ref/source/mon-stuff.cc index 7a85194ea2..3db902c13b 100644 --- a/crawl-ref/source/mon-stuff.cc +++ b/crawl-ref/source/mon-stuff.cc @@ -1323,7 +1323,7 @@ static int _tentacle_too_far(monsters *head, monsters *tentacle) // If this ever changes, we'd need to check if the head and tentacle // are still in the same pool. // XXX: Actually, using Fedhas's Sunlight power you can separate pools... - return grid_distance(head->pos(), tentacle->pos()) > LOS_RADIUS; + return grid_distance(head->pos(), tentacle->pos()) > KRAKEN_TENTACLE_RANGE; } void mons_relocated(monsters *monster) diff --git a/crawl-ref/source/monster.h b/crawl-ref/source/monster.h index 524c48b4d4..109dc876fb 100644 --- a/crawl-ref/source/monster.h +++ b/crawl-ref/source/monster.h @@ -3,6 +3,8 @@ #include "actor.h" +const int KRAKEN_TENTACLE_RANGE = 3; + class mon_enchant { public: diff --git a/crawl-ref/source/stuff.h b/crawl-ref/source/stuff.h index 89757eb99d..684df4175d 100644 --- a/crawl-ref/source/stuff.h +++ b/crawl-ref/source/stuff.h @@ -83,11 +83,6 @@ inline bool testbits(unsigned long flags, unsigned long test) return ((flags & test) == test); } -template inline Z sgn(Z x) -{ - return (x < 0 ? -1 : (x > 0 ? 1 : 0)); -} - bool is_trap_square(dungeon_feature_type grid); void zap_los_monsters(bool items_also); -- cgit v1.2.3-54-g00ecf From 6af92e2651be67206e4f153f73adeaa1e16f0b40 Mon Sep 17 00:00:00 2001 From: Darshan Shaligram Date: Tue, 29 Dec 2009 03:59:18 +0530 Subject: Generalise shopping-list-disable-check to need_save; fixes crashes on arena. --- crawl-ref/source/shopping.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crawl-ref/source/shopping.cc b/crawl-ref/source/shopping.cc index 8cb0dfa4be..2b5d582316 100644 --- a/crawl-ref/source/shopping.cc +++ b/crawl-ref/source/shopping.cc @@ -2430,7 +2430,7 @@ void ShoppingList::move_things(const coord_def &_src, const coord_def &_dst) void ShoppingList::forget_pos(const level_pos &pos) { - if (crawl_state.map_stat_gen || crawl_state.test) + if (!crawl_state.need_save) // Shopping list is unitialized and uneeded. return; -- cgit v1.2.3-54-g00ecf From 5fccd300ac36d6689cb864ec3f128e49427f170f Mon Sep 17 00:00:00 2001 From: Darshan Shaligram Date: Tue, 29 Dec 2009 04:00:08 +0530 Subject: Merfolk gladiators join the Shoals party. --- crawl-ref/source/enum.h | 4 ++++ crawl-ref/source/mon-data.h | 15 ++++++++++++++- crawl-ref/source/mon-gear.cc | 41 +++++++++++++++++++++++++++++++++++++++++ crawl-ref/source/mon-pick.cc | 2 ++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index 48bcb16db5..9bc022522f 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -1818,6 +1818,10 @@ enum monster_type // (int) menv[].type MONS_TOADSTOOL, MONS_BUSH, MONS_BALLISTOMYCETE, // 200 + + // Shoals guardians + MONS_MERFOLK_GLADIATOR, + //jmf: end new monsters MONS_WHITE_IMP = 220, // 220 MONS_LEMURE, diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h index ad3414acae..efbb63d0b0 100644 --- a/crawl-ref/source/mon-data.h +++ b/crawl-ref/source/mon-data.h @@ -1107,7 +1107,7 @@ static monsterentry mondata[] = { // merfolk ('m') { - MONS_MERFOLK, 'm', LIGHTBLUE, "merfolk", + MONS_MERFOLK, 'm', BLUE, "merfolk", M_WARM_BLOOD | M_SPEAKS, MR_NO_FLAGS, 500, 10, MONS_MERFOLK, MONS_MERFOLK, MH_NATURAL, -3, @@ -1118,6 +1118,19 @@ static monsterentry mondata[] = { MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM }, +{ + MONS_MERFOLK_GLADIATOR, 'm', LIGHTBLUE, "merfolk gladiator", + M_WARM_BLOOD, + MR_NO_FLAGS, + 500, 10, MONS_MERFOLK, MONS_MERFOLK, MH_NATURAL, -3, + { {AT_HIT, AF_PLAIN, 35}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, + { 14, 5, 3, 0 }, + // Gladiators prefer light armour, and are dodging experts. + 0, 16, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, + I_NORMAL, HT_AMPHIBIOUS_WATER, FL_NONE, 10, ATTACK_ENERGY(6), + MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM +}, + { MONS_MERMAID, 'm', CYAN, "mermaid", M_SPELLCASTER | M_WARM_BLOOD | M_SPEAKS, diff --git a/crawl-ref/source/mon-gear.cc b/crawl-ref/source/mon-gear.cc index 01edc35951..9f284736d2 100644 --- a/crawl-ref/source/mon-gear.cc +++ b/crawl-ref/source/mon-gear.cc @@ -582,6 +582,27 @@ static item_make_species_type _give_weapon(monsters *mon, int level, } break; + case MONS_MERFOLK_GLADIATOR: + item_race = MAKE_ITEM_NO_RACE; + item.base_type = OBJ_WEAPONS; + // Weapon types are not strictly sorted by quality. This is intentional. + item.sub_type = random_choose_weighted(100, WPN_TRIDENT, + 45, WPN_BARDICHE, + 15, WPN_DEMON_TRIDENT, + 15, WPN_HALBERD, + 0); + if (coinflip()) + level = MAKE_GOOD_ITEM; + else if (coinflip()) + { + // Per dpeg request :) + item.special = SPWPN_REACHING; + item.plus = random_range(-1, 6, 2); + item.plus2 = random_range(-1, 5, 2); + force_item = true; + } + break; + case MONS_MERFOLK: if (one_chance_in(3)) { @@ -1028,6 +1049,16 @@ static void _give_ammo(monsters *mon, int level, qty = random_range(4, 7); break; + case MONS_MERFOLK_GLADIATOR: + // Gladiators rarely get javelins. + if (one_chance_in(4)) + { + weap_class = OBJ_MISSILES; + weap_type = MI_JAVELIN; + qty = random_range(3, 8, 2); + } + break; + case MONS_MERFOLK: if (!one_chance_in(3)) { @@ -1342,6 +1373,16 @@ void give_armour(monsters *mon, int level) break; } + case MONS_MERFOLK_GLADIATOR: + item_race = MAKE_ITEM_NO_RACE; + item.base_type = OBJ_ARMOUR; + item.sub_type = random_choose_weighted(100, ARM_ROBE, + 60, ARM_LEATHER_ARMOUR, + 5, ARM_TROLL_LEATHER_ARMOUR, + 5, ARM_STEAM_DRAGON_ARMOUR, + 0); + break; + case MONS_ANGEL: case MONS_SIGMUND: case MONS_WIGHT: diff --git a/crawl-ref/source/mon-pick.cc b/crawl-ref/source/mon-pick.cc index 84d540d8c8..e1a429c91b 100644 --- a/crawl-ref/source/mon-pick.cc +++ b/crawl-ref/source/mon-pick.cc @@ -1721,6 +1721,7 @@ int mons_shoals_level(int mcls) case MONS_CYCLOPS: // will have a sheep band case MONS_SIREN: case MONS_HARPY: + case MONS_MERFOLK_GLADIATOR: mlev += 3; break; @@ -1754,6 +1755,7 @@ int mons_shoals_rare(int mcls) return 50; case MONS_MERMAID: + case MONS_MERFOLK_GLADIATOR: return 40; case MONS_HIPPOGRIFF: -- cgit v1.2.3-54-g00ecf From da206768a436941bf7acfc67f005a518fb90ca7e Mon Sep 17 00:00:00 2001 From: Darshan Shaligram Date: Tue, 29 Dec 2009 04:08:08 +0530 Subject: Boost harpy attack damage. --- crawl-ref/source/mon-data.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h index efbb63d0b0..b65b314b65 100644 --- a/crawl-ref/source/mon-data.h +++ b/crawl-ref/source/mon-data.h @@ -2432,7 +2432,7 @@ static monsterentry mondata[] = { M_WARM_BLOOD | M_BATTY, MR_RES_POISON, 1000, 12, MONS_HARPY, MONS_HARPY, MH_NATURAL, -3, - { {AT_CLAW, AF_PLAIN, 10}, {AT_CLAW, AF_STEAL_FOOD, 8}, + { {AT_CLAW, AF_PLAIN, 19}, {AT_CLAW, AF_STEAL_FOOD, 14}, AT_NO_ATK, AT_NO_ATK }, { 7, 3, 5, 0 }, 2, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SCREECH, -- cgit v1.2.3-54-g00ecf From 22c9c1dd3fe93c8ccab01eec647fb002877018f8 Mon Sep 17 00:00:00 2001 From: Darshan Shaligram Date: Tue, 29 Dec 2009 08:26:24 +0530 Subject: Merfolk (water/ice) elementalists join the Shoals guard. --- crawl-ref/source/actor.h | 5 ++ crawl-ref/source/beam.cc | 191 ++++++++++++++++++++++++++++++++++------- crawl-ref/source/beam.h | 6 ++ crawl-ref/source/dgn-shoals.cc | 37 +------- crawl-ref/source/dungeon.cc | 41 +++++++++ crawl-ref/source/dungeon.h | 6 ++ crawl-ref/source/enum.h | 21 +++-- crawl-ref/source/fight.cc | 7 ++ crawl-ref/source/main.cc | 2 +- crawl-ref/source/mon-cast.cc | 18 +++- crawl-ref/source/mon-data.h | 16 +++- crawl-ref/source/mon-gear.cc | 9 ++ crawl-ref/source/mon-pick.cc | 2 + crawl-ref/source/mon-spll.h | 12 +++ crawl-ref/source/monster.cc | 21 ++++- crawl-ref/source/monster.h | 5 +- crawl-ref/source/ouch.cc | 7 ++ crawl-ref/source/player.cc | 13 +++ crawl-ref/source/player.h | 5 ++ crawl-ref/source/spl-cast.cc | 6 ++ crawl-ref/source/spl-data.h | 14 +++ crawl-ref/source/spl-util.cc | 2 + 22 files changed, 368 insertions(+), 78 deletions(-) diff --git a/crawl-ref/source/actor.h b/crawl-ref/source/actor.h index a6d4899bbb..e3b3ae4af6 100644 --- a/crawl-ref/source/actor.h +++ b/crawl-ref/source/actor.h @@ -37,6 +37,10 @@ public: // occupied. virtual bool move_to_pos(const coord_def &c) = 0; + virtual void apply_location_effects(const coord_def &oldpos, + killer_type killer = KILL_NONE, + int killernum = -1) = 0; + virtual void set_position(const coord_def &c); virtual const coord_def& pos() const { return position; } @@ -213,6 +217,7 @@ public: virtual int res_poison() const = 0; virtual int res_rotting() const = 0; virtual int res_asphyx() const = 0; + virtual int res_water_drowning() const = 0; virtual int res_sticky_flame() const = 0; virtual int res_holy_energy(const actor *attacker) const = 0; virtual int res_negative_energy() const = 0; diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index 8b05a833d9..abe97ceb66 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -28,6 +28,7 @@ #include "coord.h" #include "coordit.h" #include "delay.h" +#include "dungeon.h" #include "dgnevent.h" #include "effects.h" #include "env.h" @@ -517,6 +518,22 @@ const zap_info zap_data[] = { 6 }, + { + ZAP_PRIMAL_WAVE, + "great wave of water", + 200, + new calcdice_calculator<4, 14, 3, 5>, + new tohit_calculator<10, 1, 25>, + LIGHTBLUE, + false, + BEAM_WATER, + DCHAR_WAVY, + true, + false, + false, + 6 + }, + { ZAP_CONFUSION, "0", @@ -1915,6 +1932,13 @@ coord_def bolt::pos() const return ray.pos(); } +bool bolt::need_regress() const +{ + return ((is_explosion && !in_explosion_phase) + || drop_item + || origin_spell == SPELL_PRIMAL_WAVE); +} + // Returns true if the beam ended due to hitting the wall. bool bolt::hit_wall() { @@ -1976,8 +2000,7 @@ bool bolt::hit_wall() { // Regress for explosions: blow up in an open grid (if regressing // makes any sense). Also regress when dropping items. - if (pos() != source - && ((is_explosion && !in_explosion_phase) || drop_item)) + if (pos() != source && need_regress()) { do ray.regress(); @@ -2315,6 +2338,17 @@ int mons_adjust_flavoured(monsters *monster, bolt &pbolt, int hurted, } break; + case BEAM_WATER: + hurted = resist_adjust_damage(monster, pbolt.flavour, + monster->res_asphyx(), + hurted, true); + if (doFlavouredEffects) + { + if (!hurted) + simple_monster_message(monster, " shrugs off the wave."); + } + break; + case BEAM_COLD: hurted = resist_adjust_damage(monster, pbolt.flavour, monster->res_cold(), @@ -2926,6 +2960,31 @@ void mimic_alert(monsters *mimic) mimic->flags |= MF_KNOWN_MIMIC; } +void create_feat_at(coord_def center, + dungeon_feature_type overwriteable, + dungeon_feature_type newfeat) +{ + if (grd(center) == overwriteable) + dungeon_terrain_changed(center, newfeat, true, false, true); +} + +void create_feat_splash(coord_def center, + dungeon_feature_type overwriteable, + dungeon_feature_type newfeat, + int radius, + int nattempts) +{ + // Always affect center. + create_feat_at(center, overwriteable, newfeat); + for (int i = 0; i < nattempts; ++i) + { + const coord_def newp(dgn_random_point_visible_from(center, radius)); + if (newp.origin() || grd(newp) != overwriteable) + continue; + create_feat_at(newp, overwriteable, newfeat); + } +} + bool bolt::is_bouncy(dungeon_feature_type feat) const { if (real_flavour == BEAM_CHAOS && feat_is_solid(feat)) @@ -3009,6 +3068,24 @@ void bolt::affect_endpoint() if (is_tracer) return; + if (origin_spell == SPELL_PRIMAL_WAVE) // &&coinflip() + { + if (you.see_cell(pos())) + { + mprf("The wave splashes down."); + noisy(25, pos()); + } + else + { + noisy(25, pos(), "You hear a splash."); + } + create_feat_splash(pos(), + DNGN_FLOOR, + DNGN_SHALLOW_WATER, + 2, + random_range(1, 9, 2)); + } + // FIXME: why don't these just have is_explosion set? // They don't explode in tracers: why not? if (name == "orb of electricity" @@ -4312,6 +4389,9 @@ void bolt::affect_player() internal_ouch(hurted); range_used += range_used_on_hit(&you); + + if (flavour == BEAM_WATER) + water_hits_actor(&you); } int bolt::beam_source_as_target() const @@ -4678,6 +4758,23 @@ void bolt::monster_post_hit(monsters* mon, int dmg) mimic_alert(mon); else if (dmg) beogh_follower_convert(mon, true); + + if (flavour == BEAM_WATER) + water_hits_actor(mon); +} + +void bolt::water_hits_actor(actor *act) +{ + const coord_def oldpos(act->pos()); + if (knockback_actor(act)) + { + if (you.can_see(act)) + mprf("%s %s knocked back by the %s.", + act->name(DESC_CAP_THE).c_str(), + act->conj_verb("are").c_str(), + this->name.c_str()); + act->apply_location_effects(oldpos, killer(), beam_source); + } } // Return true if the block succeeded (including reflections.) @@ -4989,21 +5086,24 @@ void bolt::affect_monster(monsters* mon) // Apply flavoured specials. mons_adjust_flavoured(mon, *this, postac, true); - // If the beam is an actual missile or of the MMISSILE type (Earth magic) - // we might bleed on the floor. - if (!engulfs - && (flavour == BEAM_MISSILE || flavour == BEAM_MMISSILE) - && !mon->is_summoned() && !mon->submerged()) + // mons_adjust_flavoured may kill the monster directly. + if (mon->alive()) { - // Using raw_damage instead of the flavoured one! - // assumes DVORP_PIERCING, factor: 0.5 - const int blood = std::min(postac/2, mon->hit_points); - bleed_onto_floor(mon->pos(), mon->type, blood, true); + // If the beam is an actual missile or of the MMISSILE type + // (Earth magic) we might bleed on the floor. + if (!engulfs + && (flavour == BEAM_MISSILE || flavour == BEAM_MMISSILE) + && !mon->is_summoned() && !mon->submerged()) + { + // Using raw_damage instead of the flavoured one! + // assumes DVORP_PIERCING, factor: 0.5 + const int blood = std::min(postac/2, mon->hit_points); + bleed_onto_floor(mon->pos(), mon->type, blood, true); + } + // Now hurt monster. + mon->hurt(agent(), final, flavour, false); } - // Now hurt monster. - mon->hurt(agent(), final, flavour, false); - int corpse = -1; monsters orig = *mon; @@ -5541,6 +5641,34 @@ int bolt::range_used_on_hit(const actor* victim) const return (used); } +// Checks whether the beam knocks back the supplied actor. The actor +// should have already failed their EV check, so the save is entirely +// body-mass-based. +bool bolt::knockback_actor(actor *act) +{ + ASSERT(ray.pos() == act->pos()); + + const coord_def oldpos(ray.pos()); + const ray_def ray_copy(ray); + ray.advance(); + + const coord_def newpos(ray.pos()); + if (newpos == oldpos || actor_at(newpos) || feat_is_solid(grd(newpos)) + || !act->can_pass_through(newpos) + // Save is based on target's body weight. + || random2(2500) < act->body_weight()) + { + ray = ray_copy; + return false; + } + + act->move_to_pos(newpos); + + // Knockback cannot ever kill the actor directly - caller must do + // apply_location_effects after messaging. + return true; +} + // Takes a bolt and refines it for use in the explosion function. // Explosions which do not follow from beams (e.g., scrolls of // immolation) bypass this function. @@ -5717,7 +5845,6 @@ static sweep_type _radial_sweep(int r) } #define MAX_EXPLOSION_RADIUS 9 - // Returns true if we saw something happening. bool bolt::explode(bool show_more, bool hole_in_the_middle) { @@ -6048,21 +6175,24 @@ bool bolt::nice_to(const monsters *mon) const // // TODO: Eventually it'd be nice to have a proper factory for these things // (extended from setup_mons_cast() and zapping() which act as limited ones). -bolt::bolt() : range(-2), type('*'), colour(BLACK), flavour(BEAM_MAGIC), - real_flavour(BEAM_MAGIC), drop_item(false), item(NULL), source(), target(), - damage(0, 0), ench_power(0), hit(0), thrower(KILL_MISC), ex_size(0), - beam_source(MHITNOT), source_name(), name(), short_name(), hit_verb(), - loudness(0), noise_msg(), is_beam(false), is_explosion(false), - is_big_cloud(false), aimed_at_spot(false), aux_source(), - affects_nothing(false), affects_items(true), effect_known(true), - draw_delay(15), special_explosion(NULL), range_funcs(), damage_funcs(), - hit_funcs(), aoe_funcs(), obvious_effect(false), seen(false), heard(false), - path_taken(), range_used(0), is_tracer(false), aimed_at_feet(false), - msg_generated(false), passed_target(false), in_explosion_phase(false), - smart_monster(false), can_see_invis(false), attitude(ATT_HOSTILE), - foe_ratio(0), chose_ray(false), beam_cancelled(false), - dont_stop_player(false), bounces(false), bounce_pos(), reflections(0), - reflector(-1), auto_hit(false) +bolt::bolt() : origin_spell(SPELL_NO_SPELL), + range(-2), type('*'), colour(BLACK), flavour(BEAM_MAGIC), + real_flavour(BEAM_MAGIC), drop_item(false), item(NULL), + source(), target(), damage(0, 0), ench_power(0), hit(0), + thrower(KILL_MISC), ex_size(0), beam_source(MHITNOT), + source_name(), name(), short_name(), hit_verb(), + loudness(0), noise_msg(), is_beam(false), is_explosion(false), + is_big_cloud(false), aimed_at_spot(false), aux_source(), + affects_nothing(false), affects_items(true), effect_known(true), + draw_delay(15), special_explosion(NULL), range_funcs(), + damage_funcs(), hit_funcs(), aoe_funcs(), obvious_effect(false), + seen(false), heard(false), path_taken(), range_used(0), + is_tracer(false), aimed_at_feet(false), msg_generated(false), + passed_target(false), in_explosion_phase(false), + smart_monster(false), can_see_invis(false), + attitude(ATT_HOSTILE), foe_ratio(0), chose_ray(false), + beam_cancelled(false), dont_stop_player(false), bounces(false), + bounce_pos(), reflections(0), reflector(-1), auto_hit(false) { } @@ -6191,6 +6321,7 @@ std::string beam_type_name(beam_type type) case BEAM_POTION_COLD: // fall through case BEAM_COLD: return ("cold"); + case BEAM_WATER: return ("water"); case BEAM_MAGIC: return ("magic"); case BEAM_ELECTRICITY: return ("electricity"); diff --git a/crawl-ref/source/beam.h b/crawl-ref/source/beam.h index 61f5640d07..7c60170f41 100644 --- a/crawl-ref/source/beam.h +++ b/crawl-ref/source/beam.h @@ -62,6 +62,8 @@ typedef bool (*explosion_aoe_func)(bolt& beam, const coord_def& target); struct bolt { // INPUT parameters set by caller + spell_type origin_spell; // may be SPELL_NO_SPELL for non-spell + // beams. int range; unsigned type; // missile gfx int colour; @@ -192,6 +194,7 @@ public: // Return whether any affected cell was seen. bool explode(bool show_more = true, bool hole_in_the_middle = false); + bool knockback_actor(actor *actor); private: void do_fire(); @@ -213,6 +216,7 @@ private: bool nasty_to(const monsters* mon) const; bool nice_to(const monsters* mon) const; bool found_player() const; + bool need_regress() const; int beam_source_as_target() const; int range_used_on_hit(const actor* victim) const; @@ -241,6 +245,8 @@ public: void affect_place_explosion_clouds(); void affect_endpoint(); + void water_hits_actor(actor *act); + // Stuff when a monster or player is hit. void affect_player_enchantment(); void tracer_affect_player(); diff --git a/crawl-ref/source/dgn-shoals.cc b/crawl-ref/source/dgn-shoals.cc index 10b49fafb8..c72cd41bf6 100644 --- a/crawl-ref/source/dgn-shoals.cc +++ b/crawl-ref/source/dgn-shoals.cc @@ -61,11 +61,6 @@ enum tide_direction static tide_direction _shoals_tide_direction; -static double _to_radians(int degrees) -{ - return degrees * M_PI / 180; -} - static dungeon_feature_type _shoals_feature_by_height(int height) { return height >= SHT_STONE ? DNGN_STONE_WALL : @@ -122,33 +117,9 @@ static void _shoals_init_heights() shoals_heights(*ri) = SHT_SHALLOW_WATER - 3; } -static double _angle_fuzz() -{ - double fuzz = _to_radians(random2(15)); - return coinflip()? fuzz : -fuzz; -} - -static coord_def _random_point_from(const coord_def &c, int radius, - int directed_angle = -1) +static coord_def _random_point_from(const coord_def &c, int radius) { - const double directed_radians( - directed_angle == -1? 0.0 : _to_radians(directed_angle)); - int attempts = 70; - while (attempts-- > 0) - { - const double angle = - directed_angle == -1? _to_radians(random2(360)) - : ((coinflip()? directed_radians : -directed_radians) - + _angle_fuzz()); - coord_def res = c + coord_def(radius * cos(angle), - radius * sin(angle)); - if (res.x >= _shoals_margin && res.x < GXM - _shoals_margin - && res.y >= _shoals_margin && res.y < GYM - _shoals_margin) - { - return res; - } - } - return coord_def(); + return dgn_random_point_from(c, radius, _shoals_margin); } static coord_def _random_point(int offset = 0) @@ -228,7 +199,7 @@ static void _shoals_build_cliff() if (in_bounds(cliffc)) { const int length = random_range(6, 15); - double angle = _to_radians(random2(360)); + double angle = dgn_degrees_to_radians(random2(360)); for (int i = 0; i < length; i += 3) { int distance = i - length / 2; @@ -698,7 +669,7 @@ static coord_def _int_coord(const coord_dbl &c) static std::vector _shoals_windshadows(grid_bool &windy) { const int wind_angle_degrees = random2(360); - const double wind_angle(_to_radians(wind_angle_degrees)); + const double wind_angle(dgn_degrees_to_radians(wind_angle_degrees)); const coord_dbl wi(cos(wind_angle), sin(wind_angle)); const double epsilon = 1e-5; diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index 04ce67e162..1c1d27f642 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -13,6 +13,7 @@ #include #include #include +#include #include "abyss.h" #include "artefact.h" @@ -7619,6 +7620,46 @@ static coord_def _dgn_find_closest_to_stone_stairs(coord_def base_pos) return (np.nearest); } + +double dgn_degrees_to_radians(int degrees) +{ + return degrees * M_PI / 180; +} + +coord_def dgn_random_point_from(const coord_def &c, int radius, int margin) +{ + int attempts = 70; + while (attempts-- > 0) + { + const double angle = dgn_degrees_to_radians(random2(360)); + const coord_def res = c + coord_def(radius * cos(angle), + radius * sin(angle)); + if (res.x >= margin && res.x < GXM - margin + && res.y >= margin && res.y < GYM - margin) + { + return res; + } + } + return coord_def(); +} + +coord_def dgn_random_point_visible_from(const coord_def &c, + int radius, + int margin, + int tries) +{ + while (tries-- > 0) + { + const coord_def point = dgn_random_point_from(c, radius, margin); + if (point.origin()) + continue; + if (!cell_see_cell(c, point)) + continue; + return point; + } + return coord_def(); +} + coord_def dgn_find_feature_marker(dungeon_feature_type feat) { std::vector markers = env.markers.get_all(); diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h index f58c17355c..ded9cea53a 100644 --- a/crawl-ref/source/dungeon.h +++ b/crawl-ref/source/dungeon.h @@ -179,6 +179,12 @@ bool builder(int level_number, int level_type); void dgn_flush_map_memory(); +double dgn_degrees_to_radians(int degrees); +coord_def dgn_random_point_from(const coord_def &c, int radius, int margin = 1); +coord_def dgn_random_point_visible_from(const coord_def &c, + int radius, + int margin = 1, + int tries = 5); coord_def dgn_find_feature_marker(dungeon_feature_type feat); // Set floor/wall colour based on the mons_alloc array. Used for diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index 9bc022522f..bf570798f1 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -199,23 +199,24 @@ enum beam_type // beam[].flavour BEAM_MMISSILE, // and similarly irresistible things BEAM_FIRE, BEAM_COLD, - BEAM_MAGIC, // 5 + BEAM_WATER, + BEAM_MAGIC, BEAM_ELECTRICITY, BEAM_POISON, BEAM_NEG, BEAM_ACID, - BEAM_MIASMA, // 10 + BEAM_MIASMA, BEAM_SPORE, BEAM_POISON_ARROW, BEAM_HELLFIRE, BEAM_NAPALM, - BEAM_STEAM, // 15 + BEAM_STEAM, BEAM_ENERGY, BEAM_HOLY, BEAM_FRAG, BEAM_LAVA, - BEAM_ICE, // 20 + BEAM_ICE, BEAM_NUKE, BEAM_RANDOM, // currently translates into FIRE..ACID BEAM_CHAOS, @@ -223,22 +224,22 @@ enum beam_type // beam[].flavour // Enchantments BEAM_SLOW, BEAM_FIRST_ENCHANTMENT = BEAM_SLOW, - BEAM_HASTE, // 25 + BEAM_HASTE, BEAM_MIGHT, BEAM_HEALING, BEAM_PARALYSIS, BEAM_CONFUSION, - BEAM_INVISIBILITY, // 30 + BEAM_INVISIBILITY, BEAM_DIGGING, BEAM_TELEPORT, BEAM_POLYMORPH, BEAM_CHARM, - BEAM_BANISH, // 35 + BEAM_BANISH, BEAM_DEGENERATE, BEAM_ENSLAVE_UNDEAD, BEAM_ENSLAVE_SOUL, BEAM_PAIN, - BEAM_DISPEL_UNDEAD, // 40 + BEAM_DISPEL_UNDEAD, BEAM_DISINTEGRATION, BEAM_ENSLAVE_DEMON, BEAM_BLINK, @@ -1821,6 +1822,7 @@ enum monster_type // (int) menv[].type // Shoals guardians MONS_MERFOLK_GLADIATOR, + MONS_MERFOLK_ELEMENTALIST, //jmf: end new monsters MONS_WHITE_IMP = 220, // 220 @@ -2323,6 +2325,7 @@ enum mon_spellbook_type MST_HAROLD, MST_MARA, MST_MARA_FAKE, + MST_MERFOLK_ELEMENTALIST, MST_TEST_SPAWNER = 200, NUM_MSTYPES, @@ -2925,6 +2928,7 @@ enum spell_type SPELL_FAKE_MARA_SUMMON, SPELL_SUMMON_RAKSHASA, SPELL_SUMMON_PLAYER_GHOST, + SPELL_PRIMAL_WAVE, NUM_SPELLS }; @@ -3115,6 +3119,7 @@ enum zap_type ZAP_PARALYSIS, ZAP_FIRE, ZAP_COLD, + ZAP_PRIMAL_WAVE, ZAP_CONFUSION, ZAP_INVISIBILITY, ZAP_DIGGING, diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc index b2237a92cb..57254b012b 100644 --- a/crawl-ref/source/fight.cc +++ b/crawl-ref/source/fight.cc @@ -2158,6 +2158,8 @@ static bool is_boolean_resist(beam_type flavour) case BEAM_ELECTRICITY: case BEAM_MIASMA: // rotting case BEAM_NAPALM: + case BEAM_WATER: // water asphyxiation damage, + // bypassed by being water inhabitant. return (true); default: return (false); @@ -2170,6 +2172,11 @@ static inline int get_resistible_fraction(beam_type flavour) { switch (flavour) { + // Drowning damage from water is resistible by being a water thing, or + // otherwise asphyx resistant. + case BEAM_WATER: + return (40); + // Assume ice storm and throw icicle are mostly solid. case BEAM_ICE: return (25); diff --git a/crawl-ref/source/main.cc b/crawl-ref/source/main.cc index 9dcd774a00..7f3ccb2592 100644 --- a/crawl-ref/source/main.cc +++ b/crawl-ref/source/main.cc @@ -4631,7 +4631,7 @@ static void _compile_time_asserts() COMPILE_CHECK(SP_VAMPIRE == 30 , c3); COMPILE_CHECK(SPELL_DEBUGGING_RAY == 103 , c4); COMPILE_CHECK(SPELL_RETURNING_AMMUNITION == 162 , c5); - COMPILE_CHECK(NUM_SPELLS == 215 , c6); + COMPILE_CHECK(NUM_SPELLS == 216 , c6); //jmf: NEW ASSERTS: we ought to do a *lot* of these COMPILE_CHECK(NUM_SPECIES < SP_UNKNOWN , c7); diff --git a/crawl-ref/source/mon-cast.cc b/crawl-ref/source/mon-cast.cc index 7bbbd77862..42b7b52da5 100644 --- a/crawl-ref/source/mon-cast.cc +++ b/crawl-ref/source/mon-cast.cc @@ -217,6 +217,7 @@ bolt mons_spells( monsters *mons, spell_type spell_cast, int power, beam.type = dchar_glyph(DCHAR_FIRED_ZAP); // default beam.thrower = KILL_MON_MISSILE; + beam.origin_spell = real_spell; // FIXME: this should use the zap_data[] struct from beam.cc! switch (real_spell) @@ -361,6 +362,19 @@ bolt mons_spells( monsters *mons, spell_type spell_cast, int power, beam.is_beam = true; break; + case SPELL_PRIMAL_WAVE: + beam.name = "great wave of water"; + // Water attack is weaker than the pure elemental damage + // attacks, but also less resistible. + beam.damage = dice_def( 3, 6 + power / 12 ); + beam.colour = LIGHTBLUE; + beam.flavour = BEAM_WATER; + // Huge wave of water is hard to dodge. + beam.hit = 20 + power / 20; + beam.is_beam = false; + beam.type = dchar_glyph(DCHAR_WAVY); + break; + case SPELL_FREEZING_CLOUD: beam.name = "freezing blast"; beam.damage = dice_def( 2, 9 + power / 11 ); @@ -840,6 +854,8 @@ bool setup_mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, bolt theBeam = mons_spells(monster, spell_cast, power); + // [ds] remind me again why we're doing this piecemeal copying? + pbolt.origin_spell = theBeam.origin_spell; pbolt.colour = theBeam.colour; pbolt.range = theBeam.range; pbolt.hit = theBeam.hit; @@ -1821,7 +1837,7 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, if (created == -1) continue; - // Mara's clones are special; they have the same stats as him, and + // Mara's clones are special; they have the same stats as him, and // are exact clones, so they are created damaged if necessary, with // identical enchants and with the same items. monsters *new_fake = &menv[created]; diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h index b65b314b65..574a1b916d 100644 --- a/crawl-ref/source/mon-data.h +++ b/crawl-ref/source/mon-data.h @@ -1124,13 +1124,25 @@ static monsterentry mondata[] = { MR_NO_FLAGS, 500, 10, MONS_MERFOLK, MONS_MERFOLK, MH_NATURAL, -3, { {AT_HIT, AF_PLAIN, 35}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, - { 14, 5, 3, 0 }, + { 14, 6, 3, 0 }, // Gladiators prefer light armour, and are dodging experts. - 0, 16, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, + 0, 17, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL, HT_AMPHIBIOUS_WATER, FL_NONE, 10, ATTACK_ENERGY(6), MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM }, +{ + MONS_MERFOLK_ELEMENTALIST, 'm', LIGHTGREEN, "merfolk elementalist", + M_WARM_BLOOD | M_SPELLCASTER | M_ACTUAL_SPELLS, + MR_RES_COLD, + 500, 10, MONS_MERFOLK, MONS_MERFOLK, MH_NATURAL, -4, + { {AT_HIT, AF_PLAIN, 15}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, + { 15, 3, 3, 0 }, + 0, 12, MST_MERFOLK_ELEMENTALIST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, + I_NORMAL, HT_AMPHIBIOUS_WATER, FL_NONE, 10, DEFAULT_ENERGY, + MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM +}, + { MONS_MERMAID, 'm', CYAN, "mermaid", M_SPELLCASTER | M_WARM_BLOOD | M_SPEAKS, diff --git a/crawl-ref/source/mon-gear.cc b/crawl-ref/source/mon-gear.cc index 9f284736d2..c1a4dace95 100644 --- a/crawl-ref/source/mon-gear.cc +++ b/crawl-ref/source/mon-gear.cc @@ -412,6 +412,14 @@ static item_make_species_type _give_weapon(monsters *mon, int level, item.sub_type = WPN_LONGBOW; break; + case MONS_MERFOLK_ELEMENTALIST: + item_race = MAKE_ITEM_NO_RACE; + item.base_type = OBJ_WEAPONS; + item.sub_type = WPN_SABRE; + if (coinflip()) + level = MAKE_GOOD_ITEM; + break; + case MONS_DEEP_ELF_ANNIHILATOR: case MONS_DEEP_ELF_CONJURER: case MONS_DEEP_ELF_DEATH_MAGE: @@ -1489,6 +1497,7 @@ void give_armour(monsters *mon, int level) case MONS_WIZARD: case MONS_ILSUIW: case MONS_MARA: + case MONS_MERFOLK_ELEMENTALIST: if (item_race == MAKE_ITEM_RANDOM_RACE) item_race = MAKE_ITEM_NO_RACE; item.base_type = OBJ_ARMOUR; diff --git a/crawl-ref/source/mon-pick.cc b/crawl-ref/source/mon-pick.cc index e1a429c91b..a79945b990 100644 --- a/crawl-ref/source/mon-pick.cc +++ b/crawl-ref/source/mon-pick.cc @@ -1722,6 +1722,7 @@ int mons_shoals_level(int mcls) case MONS_SIREN: case MONS_HARPY: case MONS_MERFOLK_GLADIATOR: + case MONS_MERFOLK_ELEMENTALIST: mlev += 3; break; @@ -1766,6 +1767,7 @@ int mons_shoals_rare(int mcls) case MONS_SIREN: case MONS_YAKTAUR: + case MONS_MERFOLK_ELEMENTALIST: return 25; case MONS_CYCLOPS: diff --git a/crawl-ref/source/mon-spll.h b/crawl-ref/source/mon-spll.h index 526d37f378..76c561e352 100644 --- a/crawl-ref/source/mon-spll.h +++ b/crawl-ref/source/mon-spll.h @@ -1319,6 +1319,18 @@ } }, + { MST_MERFOLK_ELEMENTALIST, + { + SPELL_PRIMAL_WAVE, + SPELL_BOLT_OF_COLD, + // Ice form would be neat. + SPELL_THROW_ICICLE, + SPELL_NO_SPELL, + SPELL_NO_SPELL, + SPELL_BLINK + } + }, + { MST_TEST_SPAWNER, { SPELL_SHADOW_CREATURES, diff --git a/crawl-ref/source/monster.cc b/crawl-ref/source/monster.cc index f9d18c97d9..f6003c3b81 100644 --- a/crawl-ref/source/monster.cc +++ b/crawl-ref/source/monster.cc @@ -3308,6 +3308,21 @@ int monsters::res_asphyx() const return (res); } +int monsters::res_water_drowning() const +{ + const int res = res_asphyx(); + if (res) + return res; + switch (mons_habitat(this)) + { + case HT_WATER: + case HT_AMPHIBIOUS_WATER: + return 1; + default: + return 0; + } +} + int monsters::res_poison() const { int u = get_mons_resists(this).poison; @@ -5550,7 +5565,9 @@ void monsters::check_redraw(const coord_def &old) const } } -void monsters::apply_location_effects(const coord_def &oldpos) +void monsters::apply_location_effects(const coord_def &oldpos, + killer_type killer, + int killernum) { if (oldpos != pos()) dungeon_events.fire_position_event(DET_MONSTER_MOVED, pos()); @@ -5583,7 +5600,7 @@ void monsters::apply_location_effects(const coord_def &oldpos) ptrap->trigger(*this); if (alive()) - mons_check_pool(this, pos()); + mons_check_pool(this, pos(), killer, killernum); if (alive() && has_ench(ENCH_SUBMERGED) && (!monster_can_submerge(this, grd(pos())) diff --git a/crawl-ref/source/monster.h b/crawl-ref/source/monster.h index 109dc876fb..16ec367332 100644 --- a/crawl-ref/source/monster.h +++ b/crawl-ref/source/monster.h @@ -128,7 +128,9 @@ public: bool is_summoned(int* duration = NULL, int* summon_type = NULL) const; bool has_action_energy() const; void check_redraw(const coord_def &oldpos) const; - void apply_location_effects(const coord_def &oldpos); + void apply_location_effects(const coord_def &oldpos, + killer_type killer = KILL_NONE, + int killernum = -1); void moveto(const coord_def& c); bool move_to_pos(const coord_def &newpos); @@ -317,6 +319,7 @@ public: int res_poison() const; int res_rotting() const; int res_asphyx() const; + int res_water_drowning() const; int res_sticky_flame() const; int res_holy_energy(const actor *) const; int res_negative_energy() const; diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc index 40352ecc0c..34f8bc736c 100644 --- a/crawl-ref/source/ouch.cc +++ b/crawl-ref/source/ouch.cc @@ -91,6 +91,13 @@ int check_your_resists(int hurted, beam_type flavour) switch (flavour) { + case BEAM_WATER: + hurted = resist_adjust_damage(&you, flavour, + you.res_water_drowning(), hurted, true); + if (!hurted) + mpr("You shrug off the wave."); + break; + case BEAM_STEAM: hurted = resist_adjust_damage(&you, flavour, player_res_steam(), hurted, true); diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index 7ba87a20ff..8ebf0a0655 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -6452,6 +6452,12 @@ int player::res_elec() const return (player_res_electricity() * 2); } +int player::res_water_drowning() const +{ + return (res_asphyx() || + (you.species == SP_MERFOLK && !transform_changed_physiology())); +} + int player::res_asphyx() const { // The undead are immune to asphyxiation, or so we'll assume. @@ -7049,6 +7055,13 @@ bool player::move_to_pos(const coord_def &c) return false; } +void player::apply_location_effects(const coord_def &oldpos, + killer_type killer, + int killernum) +{ + move_player_to_grid(pos(), false, true, true, false); +} + void player::shiftto(const coord_def &c) { crawl_view.shift_player_to(c); diff --git a/crawl-ref/source/player.h b/crawl-ref/source/player.h index ee34bd703e..09b66c2053 100644 --- a/crawl-ref/source/player.h +++ b/crawl-ref/source/player.h @@ -464,6 +464,7 @@ public: int res_poison() const; int res_rotting() const; int res_asphyx() const; + int res_water_drowning() const; int res_sticky_flame() const; int res_holy_energy(const actor *) const; int res_negative_energy() const; @@ -513,6 +514,10 @@ public: bool do_shaft(); + void apply_location_effects(const coord_def &oldpos, + killer_type killer = KILL_NONE, + int killernum = -1); + //////////////////////////////////////////////////////////////// PlaceInfo& get_place_info() const ; // Current place info diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc index 9f875c298f..acaaa7ebca 100644 --- a/crawl-ref/source/spl-cast.cc +++ b/crawl-ref/source/spl-cast.cc @@ -1139,6 +1139,7 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail) dist spd; bolt beam; + beam.origin_spell = spell; // [dshaligram] Any action that depends on the spellcasting attempt to have // succeeded must be performed after the switch(). @@ -1419,6 +1420,11 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail) return (SPRET_ABORT); break; + case SPELL_PRIMAL_WAVE: + if (!zapping(ZAP_PRIMAL_WAVE, powc, beam, true)) + return (SPRET_ABORT); + break; + case SPELL_STONE_ARROW: if (!zapping(ZAP_STONE_ARROW, powc, beam, true)) return (SPRET_ABORT); diff --git a/crawl-ref/source/spl-data.h b/crawl-ref/source/spl-data.h index 303306cc83..6a62b9ed09 100644 --- a/crawl-ref/source/spl-data.h +++ b/crawl-ref/source/spl-data.h @@ -2641,6 +2641,20 @@ false }, +{ + SPELL_PRIMAL_WAVE, "Primal Wave", + SPTYP_CONJURATION | SPTYP_ICE, + SPFLAG_DIR_OR_TARGET, + 6, + 200, + 7, 7, + 0, + NULL, + true, + false +}, + + { SPELL_NO_SPELL, "nonexistent spell", 0, diff --git a/crawl-ref/source/spl-util.cc b/crawl-ref/source/spl-util.cc index 75d7264e07..4e61296b5b 100644 --- a/crawl-ref/source/spl-util.cc +++ b/crawl-ref/source/spl-util.cc @@ -997,6 +997,8 @@ spell_type zap_type_to_spell(zap_type zap) return(SPELL_BOLT_OF_FIRE); case ZAP_COLD: return(SPELL_BOLT_OF_COLD); + case ZAP_PRIMAL_WAVE: + return(SPELL_PRIMAL_WAVE); case ZAP_CONFUSION: return(SPELL_CONFUSE); case ZAP_INVISIBILITY: -- cgit v1.2.3-54-g00ecf From d85ce5fca3ae674e2437783a358dfc3eecd38a3c Mon Sep 17 00:00:00 2001 From: Darshan Shaligram Date: Tue, 29 Dec 2009 08:34:11 +0530 Subject: s/merfolk elementalist/merfolk aquamancer/ (sorear). --- crawl-ref/source/enum.h | 4 ++-- crawl-ref/source/mon-data.h | 4 ++-- crawl-ref/source/mon-gear.cc | 4 ++-- crawl-ref/source/mon-pick.cc | 4 ++-- crawl-ref/source/mon-spll.h | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index bf570798f1..4d8acfc69a 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -1822,7 +1822,7 @@ enum monster_type // (int) menv[].type // Shoals guardians MONS_MERFOLK_GLADIATOR, - MONS_MERFOLK_ELEMENTALIST, + MONS_MERFOLK_AQUAMANCER, //jmf: end new monsters MONS_WHITE_IMP = 220, // 220 @@ -2325,7 +2325,7 @@ enum mon_spellbook_type MST_HAROLD, MST_MARA, MST_MARA_FAKE, - MST_MERFOLK_ELEMENTALIST, + MST_MERFOLK_AQUAMANCER, MST_TEST_SPAWNER = 200, NUM_MSTYPES, diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h index 574a1b916d..7dcf33e759 100644 --- a/crawl-ref/source/mon-data.h +++ b/crawl-ref/source/mon-data.h @@ -1132,13 +1132,13 @@ static monsterentry mondata[] = { }, { - MONS_MERFOLK_ELEMENTALIST, 'm', LIGHTGREEN, "merfolk elementalist", + MONS_MERFOLK_AQUAMANCER, 'm', LIGHTGREEN, "merfolk aquamancer", M_WARM_BLOOD | M_SPELLCASTER | M_ACTUAL_SPELLS, MR_RES_COLD, 500, 10, MONS_MERFOLK, MONS_MERFOLK, MH_NATURAL, -4, { {AT_HIT, AF_PLAIN, 15}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, { 15, 3, 3, 0 }, - 0, 12, MST_MERFOLK_ELEMENTALIST, CE_CONTAMINATED, Z_SMALL, S_SHOUT, + 0, 12, MST_MERFOLK_AQUAMANCER, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL, HT_AMPHIBIOUS_WATER, FL_NONE, 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM }, diff --git a/crawl-ref/source/mon-gear.cc b/crawl-ref/source/mon-gear.cc index c1a4dace95..e0a9f54e8a 100644 --- a/crawl-ref/source/mon-gear.cc +++ b/crawl-ref/source/mon-gear.cc @@ -412,7 +412,7 @@ static item_make_species_type _give_weapon(monsters *mon, int level, item.sub_type = WPN_LONGBOW; break; - case MONS_MERFOLK_ELEMENTALIST: + case MONS_MERFOLK_AQUAMANCER: item_race = MAKE_ITEM_NO_RACE; item.base_type = OBJ_WEAPONS; item.sub_type = WPN_SABRE; @@ -1497,7 +1497,7 @@ void give_armour(monsters *mon, int level) case MONS_WIZARD: case MONS_ILSUIW: case MONS_MARA: - case MONS_MERFOLK_ELEMENTALIST: + case MONS_MERFOLK_AQUAMANCER: if (item_race == MAKE_ITEM_RANDOM_RACE) item_race = MAKE_ITEM_NO_RACE; item.base_type = OBJ_ARMOUR; diff --git a/crawl-ref/source/mon-pick.cc b/crawl-ref/source/mon-pick.cc index a79945b990..084d643d55 100644 --- a/crawl-ref/source/mon-pick.cc +++ b/crawl-ref/source/mon-pick.cc @@ -1722,7 +1722,7 @@ int mons_shoals_level(int mcls) case MONS_SIREN: case MONS_HARPY: case MONS_MERFOLK_GLADIATOR: - case MONS_MERFOLK_ELEMENTALIST: + case MONS_MERFOLK_AQUAMANCER: mlev += 3; break; @@ -1767,7 +1767,7 @@ int mons_shoals_rare(int mcls) case MONS_SIREN: case MONS_YAKTAUR: - case MONS_MERFOLK_ELEMENTALIST: + case MONS_MERFOLK_AQUAMANCER: return 25; case MONS_CYCLOPS: diff --git a/crawl-ref/source/mon-spll.h b/crawl-ref/source/mon-spll.h index 76c561e352..2137cbbacb 100644 --- a/crawl-ref/source/mon-spll.h +++ b/crawl-ref/source/mon-spll.h @@ -1319,7 +1319,7 @@ } }, - { MST_MERFOLK_ELEMENTALIST, + { MST_MERFOLK_AQUAMANCER, { SPELL_PRIMAL_WAVE, SPELL_BOLT_OF_COLD, -- cgit v1.2.3-54-g00ecf From cccb371a91d0fb0f1f1008bc1eff23e48418114a Mon Sep 17 00:00:00 2001 From: Darshan Shaligram Date: Tue, 29 Dec 2009 16:20:41 +0530 Subject: s/merfolk gladiator/merfolk impaler/ --- crawl-ref/source/enum.h | 2 +- crawl-ref/source/mon-data.h | 2 +- crawl-ref/source/mon-gear.cc | 6 +++--- crawl-ref/source/mon-pick.cc | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index 4d8acfc69a..4a37b027b6 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -1821,7 +1821,7 @@ enum monster_type // (int) menv[].type MONS_BALLISTOMYCETE, // 200 // Shoals guardians - MONS_MERFOLK_GLADIATOR, + MONS_MERFOLK_IMPALER, MONS_MERFOLK_AQUAMANCER, //jmf: end new monsters diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h index 7dcf33e759..5f8822a84b 100644 --- a/crawl-ref/source/mon-data.h +++ b/crawl-ref/source/mon-data.h @@ -1119,7 +1119,7 @@ static monsterentry mondata[] = { }, { - MONS_MERFOLK_GLADIATOR, 'm', LIGHTBLUE, "merfolk gladiator", + MONS_MERFOLK_IMPALER, 'm', LIGHTBLUE, "merfolk impaler", M_WARM_BLOOD, MR_NO_FLAGS, 500, 10, MONS_MERFOLK, MONS_MERFOLK, MH_NATURAL, -3, diff --git a/crawl-ref/source/mon-gear.cc b/crawl-ref/source/mon-gear.cc index e0a9f54e8a..a012972cc3 100644 --- a/crawl-ref/source/mon-gear.cc +++ b/crawl-ref/source/mon-gear.cc @@ -590,7 +590,7 @@ static item_make_species_type _give_weapon(monsters *mon, int level, } break; - case MONS_MERFOLK_GLADIATOR: + case MONS_MERFOLK_IMPALER: item_race = MAKE_ITEM_NO_RACE; item.base_type = OBJ_WEAPONS; // Weapon types are not strictly sorted by quality. This is intentional. @@ -1057,7 +1057,7 @@ static void _give_ammo(monsters *mon, int level, qty = random_range(4, 7); break; - case MONS_MERFOLK_GLADIATOR: + case MONS_MERFOLK_IMPALER: // Gladiators rarely get javelins. if (one_chance_in(4)) { @@ -1381,7 +1381,7 @@ void give_armour(monsters *mon, int level) break; } - case MONS_MERFOLK_GLADIATOR: + case MONS_MERFOLK_IMPALER: item_race = MAKE_ITEM_NO_RACE; item.base_type = OBJ_ARMOUR; item.sub_type = random_choose_weighted(100, ARM_ROBE, diff --git a/crawl-ref/source/mon-pick.cc b/crawl-ref/source/mon-pick.cc index 084d643d55..01df392e72 100644 --- a/crawl-ref/source/mon-pick.cc +++ b/crawl-ref/source/mon-pick.cc @@ -1721,7 +1721,7 @@ int mons_shoals_level(int mcls) case MONS_CYCLOPS: // will have a sheep band case MONS_SIREN: case MONS_HARPY: - case MONS_MERFOLK_GLADIATOR: + case MONS_MERFOLK_IMPALER: case MONS_MERFOLK_AQUAMANCER: mlev += 3; break; @@ -1756,7 +1756,7 @@ int mons_shoals_rare(int mcls) return 50; case MONS_MERMAID: - case MONS_MERFOLK_GLADIATOR: + case MONS_MERFOLK_IMPALER: return 40; case MONS_HIPPOGRIFF: -- cgit v1.2.3-54-g00ecf From fe97e90bb05bca87d2df81bf3a2d7ded964fd42c Mon Sep 17 00:00:00 2001 From: Darshan Shaligram Date: Tue, 29 Dec 2009 17:55:13 +0530 Subject: Fix warnings for double->int implicit conversion (Napkin). --- crawl-ref/source/dgn-shoals.cc | 9 +++++---- crawl-ref/source/dungeon.cc | 5 +++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/crawl-ref/source/dgn-shoals.cc b/crawl-ref/source/dgn-shoals.cc index c72cd41bf6..b88873d5b5 100644 --- a/crawl-ref/source/dgn-shoals.cc +++ b/crawl-ref/source/dgn-shoals.cc @@ -203,8 +203,9 @@ static void _shoals_build_cliff() for (int i = 0; i < length; i += 3) { int distance = i - length / 2; - coord_def place = cliffc + coord_def(distance * cos(angle), - distance * sin(angle)); + coord_def place = + cliffc + coord_def(static_cast(distance * cos(angle)), + static_cast(distance * sin(angle))); coord_def fuzz = coord_def(random_range(-2, 2), random_range(-2, 2)); place += fuzz; @@ -512,7 +513,7 @@ static coord_def _shoals_region_center( } } - const coord_def cgravity(cx, cy); + const coord_def cgravity(static_cast(cx), static_cast(cy)); coord_def closest_to_center; int closest_distance = 0; for (int i = 0, size = visit.size(); i < size; ++i) @@ -663,7 +664,7 @@ struct coord_dbl static coord_def _int_coord(const coord_dbl &c) { - return coord_def(c.x, c.y); + return coord_def(static_cast(c.x), static_cast(c.y)); } static std::vector _shoals_windshadows(grid_bool &windy) diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index 1c1d27f642..93e5086ef6 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -7632,8 +7632,9 @@ coord_def dgn_random_point_from(const coord_def &c, int radius, int margin) while (attempts-- > 0) { const double angle = dgn_degrees_to_radians(random2(360)); - const coord_def res = c + coord_def(radius * cos(angle), - radius * sin(angle)); + const coord_def res = + c + coord_def(static_cast(radius * cos(angle)), + static_cast(radius * sin(angle))); if (res.x >= margin && res.x < GXM - margin && res.y >= margin && res.y < GYM - margin) { -- cgit v1.2.3-54-g00ecf From cfdb6e14f51f38e104444acf22e17706fcda104d Mon Sep 17 00:00:00 2001 From: Darshan Shaligram Date: Tue, 29 Dec 2009 17:56:26 +0530 Subject: Add merfolk javelineers to the Shoals, add descriptions for the three new merfolk types. --- crawl-ref/source/dat/descript/monsters.txt | 14 ++++++++- crawl-ref/source/enum.h | 1 + crawl-ref/source/mon-act.cc | 7 ++++- crawl-ref/source/mon-data.h | 24 +++++++++++---- crawl-ref/source/mon-gear.cc | 49 ++++++++++++++++++------------ crawl-ref/source/mon-pick.cc | 4 ++- 6 files changed, 71 insertions(+), 28 deletions(-) diff --git a/crawl-ref/source/dat/descript/monsters.txt b/crawl-ref/source/dat/descript/monsters.txt index da05efc32f..579bbeb6a3 100644 --- a/crawl-ref/source/dat/descript/monsters.txt +++ b/crawl-ref/source/dat/descript/monsters.txt @@ -1048,7 +1048,19 @@ This tall and powerful demon is Mara, Lord of Illusions, mighty among dreamers. %%%% merfolk -Half fish, half man, the merfolk are citizens of both water and land, and they'll fiercely protect their chosen territory. +Half fish, half man, the merfolk are citizens of both water and land, and fierce protectors of their chosen territory. +%%%% +merfolk impaler + +A powerfully muscled merfolk warrior, bearing a great trident. +%%%% +merfolk aquamancer + +A slender merfolk mystic with unusually webby hands. Its form shifts and glistens as if seen through ocean spray. +%%%% +merfolk javelineer + +A sinewy merfolk fighter with a piercing gaze and a large bundle of javelins. %%%% mermaid diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index 4a37b027b6..08ae63c36e 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -1823,6 +1823,7 @@ enum monster_type // (int) menv[].type // Shoals guardians MONS_MERFOLK_IMPALER, MONS_MERFOLK_AQUAMANCER, + MONS_MERFOLK_JAVELINEER, //jmf: end new monsters MONS_WHITE_IMP = 220, // 220 diff --git a/crawl-ref/source/mon-act.cc b/crawl-ref/source/mon-act.cc index 3fc1cea5a0..31d1c990a7 100644 --- a/crawl-ref/source/mon-act.cc +++ b/crawl-ref/source/mon-act.cc @@ -1139,7 +1139,12 @@ static bool _mons_throw(struct monsters *monster, struct bolt &pbolt, { const mon_attack_def attk = mons_attack_spec(monster, 0); if (attk.type == AT_SHOOT) - ammoDamBonus += random2avg(attk.damage, 2); + { + if (projected == LRET_THROWN && wepClass == OBJ_MISSILES) + ammoHitBonus += random2avg(attk.damage, 2); + else + ammoDamBonus += random2avg(attk.damage, 2); + } } if (projected == LRET_THROWN) diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h index 5f8822a84b..e5e5fb7b98 100644 --- a/crawl-ref/source/mon-data.h +++ b/crawl-ref/source/mon-data.h @@ -1123,12 +1123,24 @@ static monsterentry mondata[] = { M_WARM_BLOOD, MR_NO_FLAGS, 500, 10, MONS_MERFOLK, MONS_MERFOLK, MH_NATURAL, -3, - { {AT_HIT, AF_PLAIN, 35}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, - { 14, 6, 3, 0 }, - // Gladiators prefer light armour, and are dodging experts. - 0, 17, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, + { {AT_HIT, AF_PLAIN, 40}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, + { 16, 5, 3, 0 }, + // Impalers prefer light armour, and are dodging experts. + 0, 23, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL, HT_AMPHIBIOUS_WATER, FL_NONE, 10, ATTACK_ENERGY(6), - MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM + MONUSE_MAGIC_ITEMS, MONEAT_NOTHING, SIZE_MEDIUM +}, + +{ + MONS_MERFOLK_JAVELINEER, 'm', LIGHTGREY, "merfolk javelineer", + M_WARM_BLOOD | M_ARCHER, + MR_NO_FLAGS, + 500, 10, MONS_MERFOLK, MONS_MERFOLK, MH_NATURAL, -4, + { {AT_SHOOT, AF_PLAIN, 18}, {AT_HIT, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK }, + { 16, 4, 2, 0 }, + 0, 15, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, + I_NORMAL, HT_AMPHIBIOUS_WATER, FL_NONE, 10, MISSILE_ENERGY(8), + MONUSE_MAGIC_ITEMS, MONEAT_NOTHING, SIZE_MEDIUM }, { @@ -1140,7 +1152,7 @@ static monsterentry mondata[] = { { 15, 3, 3, 0 }, 0, 12, MST_MERFOLK_AQUAMANCER, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL, HT_AMPHIBIOUS_WATER, FL_NONE, 10, DEFAULT_ENERGY, - MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM + MONUSE_MAGIC_ITEMS, MONEAT_NOTHING, SIZE_MEDIUM }, { diff --git a/crawl-ref/source/mon-gear.cc b/crawl-ref/source/mon-gear.cc index a012972cc3..393d4680b7 100644 --- a/crawl-ref/source/mon-gear.cc +++ b/crawl-ref/source/mon-gear.cc @@ -412,14 +412,6 @@ static item_make_species_type _give_weapon(monsters *mon, int level, item.sub_type = WPN_LONGBOW; break; - case MONS_MERFOLK_AQUAMANCER: - item_race = MAKE_ITEM_NO_RACE; - item.base_type = OBJ_WEAPONS; - item.sub_type = WPN_SABRE; - if (coinflip()) - level = MAKE_GOOD_ITEM; - break; - case MONS_DEEP_ELF_ANNIHILATOR: case MONS_DEEP_ELF_CONJURER: case MONS_DEEP_ELF_DEATH_MAGE: @@ -593,11 +585,8 @@ static item_make_species_type _give_weapon(monsters *mon, int level, case MONS_MERFOLK_IMPALER: item_race = MAKE_ITEM_NO_RACE; item.base_type = OBJ_WEAPONS; - // Weapon types are not strictly sorted by quality. This is intentional. item.sub_type = random_choose_weighted(100, WPN_TRIDENT, - 45, WPN_BARDICHE, 15, WPN_DEMON_TRIDENT, - 15, WPN_HALBERD, 0); if (coinflip()) level = MAKE_GOOD_ITEM; @@ -611,6 +600,23 @@ static item_make_species_type _give_weapon(monsters *mon, int level, } break; + + case MONS_MERFOLK_AQUAMANCER: + item_race = MAKE_ITEM_NO_RACE; + item.base_type = OBJ_WEAPONS; + item.sub_type = WPN_SABRE; + if (coinflip()) + level = MAKE_GOOD_ITEM; + break; + + case MONS_MERFOLK_JAVELINEER: + item_race = MAKE_ITEM_NO_RACE; + item.base_type = OBJ_WEAPONS; + item.sub_type = WPN_SPEAR; + if (!one_chance_in(3)) + level = MAKE_GOOD_ITEM; + break; + case MONS_MERFOLK: if (one_chance_in(3)) { @@ -1057,14 +1063,13 @@ static void _give_ammo(monsters *mon, int level, qty = random_range(4, 7); break; - case MONS_MERFOLK_IMPALER: - // Gladiators rarely get javelins. - if (one_chance_in(4)) - { - weap_class = OBJ_MISSILES; - weap_type = MI_JAVELIN; - qty = random_range(3, 8, 2); - } + case MONS_MERFOLK_JAVELINEER: + weap_class = OBJ_MISSILES; + weap_type = MI_JAVELIN; + item_race = MAKE_ITEM_NO_RACE; + qty = random_range(9, 23, 2); + if (one_chance_in(3)) + level = MAKE_GOOD_ITEM; break; case MONS_MERFOLK: @@ -1391,6 +1396,12 @@ void give_armour(monsters *mon, int level) 0); break; + case MONS_MERFOLK_JAVELINEER: + item_race = MAKE_ITEM_NO_RACE; + item.base_type = OBJ_ARMOUR; + item.sub_type = ARM_LEATHER_ARMOUR; + break; + case MONS_ANGEL: case MONS_SIGMUND: case MONS_WIGHT: diff --git a/crawl-ref/source/mon-pick.cc b/crawl-ref/source/mon-pick.cc index 01df392e72..edcb9a5ec7 100644 --- a/crawl-ref/source/mon-pick.cc +++ b/crawl-ref/source/mon-pick.cc @@ -1723,6 +1723,7 @@ int mons_shoals_level(int mcls) case MONS_HARPY: case MONS_MERFOLK_IMPALER: case MONS_MERFOLK_AQUAMANCER: + case MONS_MERFOLK_JAVELINEER: mlev += 3; break; @@ -1756,13 +1757,14 @@ int mons_shoals_rare(int mcls) return 50; case MONS_MERMAID: - case MONS_MERFOLK_IMPALER: return 40; case MONS_HIPPOGRIFF: case MONS_GIANT_BAT: case MONS_BUTTERFLY: case MONS_CENTAUR: + case MONS_MERFOLK_IMPALER: + case MONS_MERFOLK_JAVELINEER: return 35; case MONS_SIREN: -- cgit v1.2.3-54-g00ecf From 9cc1ba155f353a235d38e785c1eefc984f4d42c1 Mon Sep 17 00:00:00 2001 From: Darshan Shaligram Date: Tue, 29 Dec 2009 19:48:21 +0530 Subject: Boost Ilsuiw stats and give her Call Tide, which strongly boosts the tide in Shoals, pegs it towards high tide, and includes a local high tide maximum centered on Ilsuiw, which can be double the height of the normal high tide. --- crawl-ref/source/dgn-shoals.cc | 108 +++++++++++++++++++++++++++++++++++------ crawl-ref/source/dgn-shoals.h | 3 +- crawl-ref/source/enum.h | 2 + crawl-ref/source/main.cc | 2 +- crawl-ref/source/mon-abil.cc | 12 +---- crawl-ref/source/mon-cast.cc | 13 +++++ crawl-ref/source/mon-data.h | 2 +- crawl-ref/source/mon-gear.cc | 12 +++++ crawl-ref/source/mon-spll.h | 5 +- crawl-ref/source/mon-stuff.cc | 3 ++ crawl-ref/source/mon-util.cc | 7 +++ crawl-ref/source/monster.cc | 7 ++- crawl-ref/source/monster.h | 1 + crawl-ref/source/spl-data.h | 12 +++++ crawl-ref/source/view.cc | 13 +++++ crawl-ref/source/view.h | 1 + 16 files changed, 169 insertions(+), 34 deletions(-) diff --git a/crawl-ref/source/dgn-shoals.cc b/crawl-ref/source/dgn-shoals.cc index b88873d5b5..b91dc3a195 100644 --- a/crawl-ref/source/dgn-shoals.cc +++ b/crawl-ref/source/dgn-shoals.cc @@ -1,6 +1,7 @@ #include "AppHdr.h" #include "branch.h" +#include "colour.h" #include "coord.h" #include "coordit.h" #include "dungeon.h" @@ -10,10 +11,12 @@ #include "items.h" #include "maps.h" #include "mgen_data.h" +#include "mon-iter.h" #include "mon-place.h" #include "mon-util.h" #include "random.h" #include "terrain.h" +#include "view.h" #include #include @@ -42,6 +45,23 @@ const int N_PERTURB_OFFSET_HIGH = 45; const int PERTURB_OFFSET_RADIUS_LOW = 2; const int PERTURB_OFFSET_RADIUS_HIGH = 7; +// The raw tide height / TIDE_MULTIPLIER is the actual tide height. The higher +// the tide multiplier, the slower the tide advances and recedes. A multiplier +// of X implies that the tide will advance visibly about once in X turns. +const int TIDE_MULTIPLIER = 30; + +const int LOW_TIDE = -18 * TIDE_MULTIPLIER; +const int HIGH_TIDE = 25 * TIDE_MULTIPLIER; + +// The highest a tide can be called by a tide caller such as Ilsuiw. +const int HIGH_CALLED_TIDE = 25; +const int TIDE_DECEL_MARGIN = 8; +const int PEAK_TIDE_ACCEL = 2; + +// The area around the user of a call tide spell that is subject to +// local tide elevation. +const int TIDE_CALL_RADIUS = 8; + const int _shoals_margin = 6; enum shoals_height_thresholds @@ -60,6 +80,10 @@ enum tide_direction }; static tide_direction _shoals_tide_direction; +static monsters *tide_caller = NULL; +static coord_def tide_caller_pos; +static long tide_called_turns = 0L; +static int tide_called_peak = 0; static dungeon_feature_type _shoals_feature_by_height(int height) { @@ -816,18 +840,16 @@ void shoals_postprocess_level() } } -// The raw tide height / TIDE_MULTIPLIER is the actual tide height. The higher -// the tide multiplier, the slower the tide advances and recedes. A multiplier -// of X implies that the tide will advance visibly about once in X turns. -const int TIDE_MULTIPLIER = 30; - -const int LOW_TIDE = -18 * TIDE_MULTIPLIER; -const int HIGH_TIDE = 25 * TIDE_MULTIPLIER; -const int TIDE_DECEL_MARGIN = 8; -const int START_TIDE_RISE = 2; - static void _shoals_run_tide(int &tide, int &acc) { + // If someone is calling the tide, the acceleration is clamped high. + if (tide_caller) + acc = 15; + // If there's no tide caller and our acceleration is suspiciously high, + // reset it to a falling tide at peak acceleration. + else if (abs(acc) > PEAK_TIDE_ACCEL) + acc = -PEAK_TIDE_ACCEL; + tide += acc; tide = std::max(std::min(tide, HIGH_TIDE), LOW_TIDE); if ((tide == HIGH_TIDE && acc > 0) @@ -836,7 +858,7 @@ static void _shoals_run_tide(int &tide, int &acc) bool in_decel_margin = (abs(tide - HIGH_TIDE) < TIDE_DECEL_MARGIN) || (abs(tide - LOW_TIDE) < TIDE_DECEL_MARGIN); - if ((abs(acc) == 2) == in_decel_margin) + if ((abs(acc) > 1) == in_decel_margin) acc = in_decel_margin? acc / 2 : acc * 2; } @@ -956,6 +978,23 @@ static void _shoals_apply_tide_at(coord_def c, int tide) _shoals_apply_tide_feature_at(c, newfeat); } +static int _shoals_tide_at(coord_def pos, int base_tide) +{ + if (!tide_caller) + return base_tide; + + const int rl_distance = grid_distance(pos, tide_caller_pos); + if (rl_distance > TIDE_CALL_RADIUS) + return base_tide; + + const int distance = + static_cast(sqrt((pos - tide_caller->pos()).abs())); + if (distance > TIDE_CALL_RADIUS) + return base_tide; + + return (base_tide + std::max(0, tide_called_peak - distance * 3)); +} + static void _shoals_apply_tide(int tide) { std::vector pages[2]; @@ -980,7 +1019,7 @@ static void _shoals_apply_tide(int tide) coord_def c(cpage[i]); const bool was_wet(_shoals_tide_passable_feat(grd(c))); seen_points(c) = true; - _shoals_apply_tide_at(c, tide); + _shoals_apply_tide_at(c, _shoals_tide_at(c, tide)); const bool is_wet(feat_is_water(grd(c))); // Only squares that were wet (before applying tide @@ -1017,13 +1056,22 @@ static void _shoals_init_tide() if (!env.properties.exists(ENVP_SHOALS_TIDE_KEY)) { env.properties[ENVP_SHOALS_TIDE_KEY] = short(0); - env.properties[ENVP_SHOALS_TIDE_VEL] = short(2); + env.properties[ENVP_SHOALS_TIDE_VEL] = short(PEAK_TIDE_ACCEL); } } -void shoals_apply_tides(int turns_elapsed) +static monsters *_shoals_find_tide_caller() +{ + for (monster_iterator mi; mi; ++mi) + if (mi->has_ench(ENCH_TIDE)) + return *mi; + return NULL; +} + +void shoals_apply_tides(int turns_elapsed, bool force) { - if (!player_in_branch(BRANCH_SHOALS) || !turns_elapsed + if (!player_in_branch(BRANCH_SHOALS) + || (!turns_elapsed && !force) || !env.heightmap.get()) { return; @@ -1035,6 +1083,20 @@ void shoals_apply_tides(int turns_elapsed) turns_elapsed = turns_elapsed % TIDE_UNIT + TIDE_UNIT; _shoals_init_tide(); + + unwind_var tide_caller_unwind(tide_caller, + _shoals_find_tide_caller()); + if (tide_caller) + { + tide_called_turns = tide_caller->props[TIDE_CALL_TURN].get_long(); + tide_called_turns = you.num_turns - tide_called_turns; + if (tide_called_turns < 1L) + tide_called_turns = 1L; + tide_called_peak = std::min(HIGH_CALLED_TIDE, + int(tide_called_turns * 5)); + tide_caller_pos = tide_caller->pos(); + } + int tide = env.properties[ENVP_SHOALS_TIDE_KEY].get_short(); int acc = env.properties[ENVP_SHOALS_TIDE_VEL].get_short(); const int old_tide = tide; @@ -1042,10 +1104,24 @@ void shoals_apply_tides(int turns_elapsed) _shoals_run_tide(tide, acc); env.properties[ENVP_SHOALS_TIDE_KEY] = short(tide); env.properties[ENVP_SHOALS_TIDE_VEL] = short(acc); - if (old_tide / TIDE_MULTIPLIER != tide / TIDE_MULTIPLIER) + if (force + || tide_caller + || old_tide / TIDE_MULTIPLIER != tide / TIDE_MULTIPLIER) { _shoals_tide_direction = tide > old_tide ? TIDE_RISING : TIDE_FALLING; _shoals_apply_tide(tide / TIDE_MULTIPLIER); } } + +void shoals_release_tide(monsters *mons) +{ + if (player_in_branch(BRANCH_SHOALS) + && player_can_hear(you.pos())) + { + mprf(MSGCH_SOUND, "The tide is released from %s call.", + mons->name(DESC_NOCAP_YOUR, true).c_str()); + flash_view_delay(ETC_WATER, 150); + shoals_apply_tides(0, true); + } +} diff --git a/crawl-ref/source/dgn-shoals.h b/crawl-ref/source/dgn-shoals.h index f558f6606f..1d14c620f2 100644 --- a/crawl-ref/source/dgn-shoals.h +++ b/crawl-ref/source/dgn-shoals.h @@ -3,6 +3,7 @@ void prepare_shoals(int level_number); void shoals_postprocess_level(); -void shoals_apply_tides(int turns_elapsed); +void shoals_apply_tides(int turns_elapsed, bool force = false); +void shoals_release_tide(monsters *caller); #endif diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index 08ae63c36e..f770323cfc 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -1254,6 +1254,7 @@ enum enchant_type ENCH_SPORE_PRODUCTION, // 35 ENCH_SLOUCH, ENCH_SWIFT, + ENCH_TIDE, // Update enchantment names in mon-util.cc when adding or removing // enchantments. @@ -2930,6 +2931,7 @@ enum spell_type SPELL_SUMMON_RAKSHASA, SPELL_SUMMON_PLAYER_GHOST, SPELL_PRIMAL_WAVE, + SPELL_CALL_TIDE, NUM_SPELLS }; diff --git a/crawl-ref/source/main.cc b/crawl-ref/source/main.cc index 7f3ccb2592..1ad6e1af6c 100644 --- a/crawl-ref/source/main.cc +++ b/crawl-ref/source/main.cc @@ -4631,7 +4631,7 @@ static void _compile_time_asserts() COMPILE_CHECK(SP_VAMPIRE == 30 , c3); COMPILE_CHECK(SPELL_DEBUGGING_RAY == 103 , c4); COMPILE_CHECK(SPELL_RETURNING_AMMUNITION == 162 , c5); - COMPILE_CHECK(NUM_SPELLS == 216 , c6); + COMPILE_CHECK(NUM_SPELLS == 217 , c6); //jmf: NEW ASSERTS: we ought to do a *lot* of these COMPILE_CHECK(NUM_SPECIES < SP_UNKNOWN , c7); diff --git a/crawl-ref/source/mon-abil.cc b/crawl-ref/source/mon-abil.cc index 5325d3f27b..781778d6d3 100644 --- a/crawl-ref/source/mon-abil.cc +++ b/crawl-ref/source/mon-abil.cc @@ -303,17 +303,7 @@ static bool _do_merge(monsters *initial_slime, monsters *merge_to) merge_to->name(DESC_NOCAP_A).c_str()); } - flash_view(LIGHTGREEN); - - int flash_delay = 150; - // Scale delay to match change in arena_delay. - if (crawl_state.arena) - { - flash_delay *= Options.arena_delay; - flash_delay /= 600; - } - - delay(flash_delay); + flash_view_delay(LIGHTGREEN, 150); } else if (you.can_see(initial_slime)) mpr("A slime creature suddenly disappears!"); diff --git a/crawl-ref/source/mon-cast.cc b/crawl-ref/source/mon-cast.cc index 42b7b52da5..5190625c61 100644 --- a/crawl-ref/source/mon-cast.cc +++ b/crawl-ref/source/mon-cast.cc @@ -839,6 +839,7 @@ bool setup_mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, case SPELL_SUMMON_EYEBALLS: case SPELL_SUMMON_BUTTERFLIES: case SPELL_MISLEAD: + case SPELL_CALL_TIDE: return (true); default: if (check_validity) @@ -1678,6 +1679,18 @@ void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast, simple_monster_message(monster, " seems to move somewhat quicker."); return; + case SPELL_CALL_TIDE: + { + const int tide_duration = random_range(18, 50, 2); + monster->add_ench(mon_enchant(ENCH_TIDE, 0, KC_OTHER, + tide_duration * 10)); + monster->props[TIDE_CALL_TURN] = you.num_turns; + simple_monster_message(monster, + " sings a water chant to call the tide!"); + flash_view_delay(ETC_WATER, 300); + return; + } + case SPELL_SUMMON_SMALL_MAMMALS: case SPELL_VAMPIRE_SUMMON: if (spell_cast == SPELL_SUMMON_SMALL_MAMMALS) diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h index e5e5fb7b98..6ce2103a22 100644 --- a/crawl-ref/source/mon-data.h +++ b/crawl-ref/source/mon-data.h @@ -4626,7 +4626,7 @@ static monsterentry mondata[] = { MR_RES_POISON | MR_RES_COLD, 500, 10, MONS_MERFOLK, MONS_MERFOLK, MH_NATURAL, -7, { {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, - { 9, 0, 0, 54 }, + { 16, 0, 0, 150 }, 5, 18, MST_ILSUIW, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_NORMAL, HT_AMPHIBIOUS_WATER, FL_NONE, 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM diff --git a/crawl-ref/source/mon-gear.cc b/crawl-ref/source/mon-gear.cc index 393d4680b7..8affc9587f 100644 --- a/crawl-ref/source/mon-gear.cc +++ b/crawl-ref/source/mon-gear.cc @@ -12,6 +12,7 @@ #include "mon-gear.h" #include "artefact.h" +#include "colour.h" #include "dungeon.h" #include "env.h" #include "itemprop.h" @@ -582,6 +583,17 @@ static item_make_species_type _give_weapon(monsters *mon, int level, } break; + case MONS_ILSUIW: + item_race = MAKE_ITEM_NO_RACE; + item.base_type = OBJ_WEAPONS; + item.sub_type = WPN_TRIDENT; + item.special = SPWPN_FREEZING; + item.plus = random_range(-1, 6, 2); + item.plus2 = random_range(-1, 6, 2); + item.colour = ETC_ICE; + force_item = true; + break; + case MONS_MERFOLK_IMPALER: item_race = MAKE_ITEM_NO_RACE; item.base_type = OBJ_WEAPONS; diff --git a/crawl-ref/source/mon-spll.h b/crawl-ref/source/mon-spll.h index 2137cbbacb..344ae8e6b8 100644 --- a/crawl-ref/source/mon-spll.h +++ b/crawl-ref/source/mon-spll.h @@ -1043,8 +1043,8 @@ { MST_ILSUIW, { - SPELL_THROW_FROST, // was: SPELL_CONFUSED (jpeg) - SPELL_SLOW, + SPELL_THROW_ICICLE, + SPELL_CALL_TIDE, SPELL_INVISIBILITY, SPELL_BLINK, SPELL_WATER_ELEMENTALS, @@ -1323,7 +1323,6 @@ { SPELL_PRIMAL_WAVE, SPELL_BOLT_OF_COLD, - // Ice form would be neat. SPELL_THROW_ICICLE, SPELL_NO_SPELL, SPELL_NO_SPELL, diff --git a/crawl-ref/source/mon-stuff.cc b/crawl-ref/source/mon-stuff.cc index 3db902c13b..ca7b9cf12c 100644 --- a/crawl-ref/source/mon-stuff.cc +++ b/crawl-ref/source/mon-stuff.cc @@ -1422,6 +1422,9 @@ int monster_die(monsters *monster, killer_type killer, return (-1); } + // If the monster was calling the tide, let go now. + monster->del_ench(ENCH_TIDE); + crawl_state.inc_mon_acting(monster); ASSERT(!( YOU_KILL(killer) && crawl_state.arena )); diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 3687e1711c..5895a0c542 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -2390,6 +2390,13 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell ) // handled here as well. - bwr switch (monspell) { + case SPELL_CALL_TIDE: + return (!player_in_branch(BRANCH_SHOALS) + || mon->has_ench(ENCH_TIDE) + || !foe + || (grd(mon->pos()) == DNGN_DEEP_WATER + && grd(foe->pos()) == DNGN_DEEP_WATER)); + case SPELL_BRAIN_FEED: ret = (foe != &you); break; diff --git a/crawl-ref/source/monster.cc b/crawl-ref/source/monster.cc index f6003c3b81..2f83c01d6f 100644 --- a/crawl-ref/source/monster.cc +++ b/crawl-ref/source/monster.cc @@ -12,6 +12,7 @@ #include "coordit.h" #include "delay.h" #include "dgnevent.h" +#include "dgn-shoals.h" #include "directn.h" #include "env.h" #include "fight.h" @@ -4305,6 +4306,10 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet) { switch (me.ench) { + case ENCH_TIDE: + shoals_release_tide(this); + break; + case ENCH_BERSERK: scale_hp(2, 3); break; @@ -6031,7 +6036,7 @@ static const char *enchant_names[] = "short-lived", "paralysis", "sick", "sleep", "fatigue", "held", "blood-lust", "neutral", "petrifying", "petrified", "magic-vulnerable", "soul-ripe", "decay", "hungry", "flopping", "spore-producing", - "downtrodden", "swift", "bug" + "downtrodden", "swift", "tide", "bug" }; static const char *_mons_enchantment_name(enchant_type ench) diff --git a/crawl-ref/source/monster.h b/crawl-ref/source/monster.h index 16ec367332..b93ed65571 100644 --- a/crawl-ref/source/monster.h +++ b/crawl-ref/source/monster.h @@ -4,6 +4,7 @@ #include "actor.h" const int KRAKEN_TENTACLE_RANGE = 3; +#define TIDE_CALL_TURN "tide-call-turn" class mon_enchant { diff --git a/crawl-ref/source/spl-data.h b/crawl-ref/source/spl-data.h index 6a62b9ed09..db5979a031 100644 --- a/crawl-ref/source/spl-data.h +++ b/crawl-ref/source/spl-data.h @@ -2654,6 +2654,18 @@ false }, +{ + SPELL_CALL_TIDE, "Call Tide", + SPTYP_TRANSLOCATION, + SPFLAG_MONSTER, + 7, + 0, + -1, -1, + 0, + NULL, + false, + false +}, { SPELL_NO_SPELL, "nonexistent spell", diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index b8e6447a89..94ad2a572c 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -635,6 +635,19 @@ void flash_view(int colour) viewwindow(false, false); } +void flash_view_delay(int colour, long flash_delay) +{ + flash_view(colour); + // Scale delay to match change in arena_delay. + if (crawl_state.arena) + { + flash_delay *= Options.arena_delay; + flash_delay /= 600; + } + + delay(flash_delay); +} + static void _debug_pane_bounds() { #if DEBUG_PANE_BOUNDS diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h index 7a618c182b..70029c000d 100644 --- a/crawl-ref/source/view.h +++ b/crawl-ref/source/view.h @@ -37,6 +37,7 @@ std::string screenshot(bool fullscreen = false); bool view_update(); void view_update_at(const coord_def &pos); void flash_view(int colour = BLACK); // inside #ifndef USE_TILE? +void flash_view_delay(int colour = BLACK, long delay = 150); #ifndef USE_TILE void flash_monster_colour(const monsters *mon, unsigned char fmc_colour, int fmc_delay); -- cgit v1.2.3-54-g00ecf From 225b0e70b831304bdeb50cc9f123819dc9a2b6bc Mon Sep 17 00:00:00 2001 From: Darshan Shaligram Date: Tue, 29 Dec 2009 20:03:35 +0530 Subject: Weaken merfolk impalers and javelineers, give sirens and mermaids extra hp, and sirens extra HD, remove ettin and sheep from Shoals. --- crawl-ref/source/mon-data.h | 12 ++++++------ crawl-ref/source/mon-pick.cc | 4 ---- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h index 6ce2103a22..0db6c4e927 100644 --- a/crawl-ref/source/mon-data.h +++ b/crawl-ref/source/mon-data.h @@ -1123,8 +1123,8 @@ static monsterentry mondata[] = { M_WARM_BLOOD, MR_NO_FLAGS, 500, 10, MONS_MERFOLK, MONS_MERFOLK, MH_NATURAL, -3, - { {AT_HIT, AF_PLAIN, 40}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, - { 16, 5, 3, 0 }, + { {AT_HIT, AF_PLAIN, 34}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, + { 16, 4, 3, 0 }, // Impalers prefer light armour, and are dodging experts. 0, 23, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL, HT_AMPHIBIOUS_WATER, FL_NONE, 10, ATTACK_ENERGY(6), @@ -1136,8 +1136,8 @@ static monsterentry mondata[] = { M_WARM_BLOOD | M_ARCHER, MR_NO_FLAGS, 500, 10, MONS_MERFOLK, MONS_MERFOLK, MH_NATURAL, -4, - { {AT_SHOOT, AF_PLAIN, 18}, {AT_HIT, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK }, - { 16, 4, 2, 0 }, + { {AT_SHOOT, AF_PLAIN, 16}, {AT_HIT, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK }, + { 15, 4, 2, 0 }, 0, 15, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL, HT_AMPHIBIOUS_WATER, FL_NONE, 10, MISSILE_ENERGY(8), MONUSE_MAGIC_ITEMS, MONEAT_NOTHING, SIZE_MEDIUM @@ -1161,7 +1161,7 @@ static monsterentry mondata[] = { MR_NO_FLAGS, 500, 10, MONS_MERMAID, MONS_MERMAID, MH_NATURAL, -5, { {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, - { 8, 2, 3, 0 }, + { 8, 3, 3, 0 }, 4, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL, HT_AMPHIBIOUS_WATER, FL_NONE, 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM @@ -1173,7 +1173,7 @@ static monsterentry mondata[] = { MR_NO_FLAGS, 500, 12, MONS_MERMAID, MONS_SIREN, MH_NATURAL, -7, { {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, - { 8, 2, 3, 0 }, + { 13, 5, 3, 0 }, 4, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_NORMAL, HT_AMPHIBIOUS_WATER, FL_NONE, 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM diff --git a/crawl-ref/source/mon-pick.cc b/crawl-ref/source/mon-pick.cc index edcb9a5ec7..091650e0a0 100644 --- a/crawl-ref/source/mon-pick.cc +++ b/crawl-ref/source/mon-pick.cc @@ -1706,8 +1706,6 @@ int mons_shoals_level(int mcls) case MONS_MERFOLK: case MONS_MERMAID: case MONS_CENTAUR: - case MONS_ETTIN: - case MONS_SHEEP: case MONS_HIPPOGRIFF: mlev++; break; @@ -1751,8 +1749,6 @@ int mons_shoals_rare(int mcls) case MONS_PLANT: return 150; - case MONS_ETTIN: - case MONS_SHEEP: case MONS_MERFOLK: return 50; -- cgit v1.2.3-54-g00ecf From 8efdaf11a28299dda120a8afe78702686a6e2a47 Mon Sep 17 00:00:00 2001 From: Darshan Shaligram Date: Tue, 29 Dec 2009 20:14:23 +0530 Subject: Give Ilsuiw a more interesting band. --- crawl-ref/source/mon-place.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/crawl-ref/source/mon-place.cc b/crawl-ref/source/mon-place.cc index 27b6c8fe20..cb54b20982 100644 --- a/crawl-ref/source/mon-place.cc +++ b/crawl-ref/source/mon-place.cc @@ -598,7 +598,7 @@ static monster_type _resolve_monster_type(monster_type mon_type, mon_type = MONS_DANCING_WEAPON; else { - if (you.level_type == LEVEL_PORTAL_VAULT + if (you.level_type == LEVEL_PORTAL_VAULT && vault_mon_types.size() > 0) { int i = choose_random_weighted(vault_mon_weights.begin(), @@ -636,7 +636,7 @@ static monster_type _resolve_monster_type(monster_type mon_type, } else if (you.level_type == LEVEL_PORTAL_VAULT) { - // XXX: We don't have a random monster list here, so pick one + // XXX: We don't have a random monster list here, so pick one // from where we were. place.level_type = LEVEL_DUNGEON; *lev_mons = place.absdepth(); @@ -2401,7 +2401,12 @@ static monster_type _band_member(band_type band, int power) break; } case BAND_ILSUIW: - mon_type = coinflip()? MONS_MERFOLK : MONS_MERMAID; + mon_type = static_cast( + random_choose_weighted(30, MONS_MERMAID, + 15, MONS_MERFOLK, + 10, MONS_MERFOLK_JAVELINEER, + 10, MONS_MERFOLK_IMPALER, + 0)); break; case BAND_AZRAEL: -- cgit v1.2.3-54-g00ecf