diff options
author | j-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573> | 2009-06-29 19:44:39 +0000 |
---|---|---|
committer | j-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573> | 2009-06-29 19:44:39 +0000 |
commit | e66c77b50df3c0c91837b52b9e61c8235a96c685 (patch) | |
tree | e780b4b6696564f4cf3a5763987bd776ff064537 /crawl-ref/source/effects.cc | |
parent | 4dc30336a62ec7e8261253fc0b9c0674efda1555 (diff) | |
download | crawl-ref-e66c77b50df3c0c91837b52b9e61c8235a96c685.tar.gz crawl-ref-e66c77b50df3c0c91837b52b9e61c8235a96c685.zip |
Apply caotto's neat patch to make toadstools grow on or around corpses.
Obviously, this might affect food balance and Necromancy. Tweaks may be
necessary, but overall this looks good.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@10077 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/effects.cc')
-rw-r--r-- | crawl-ref/source/effects.cc | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc index 2244402d48..7ef9ec7a2a 100644 --- a/crawl-ref/source/effects.cc +++ b/crawl-ref/source/effects.cc @@ -15,6 +15,9 @@ REVISION("$Rev$"); #include <string.h> #include <stdio.h> #include <algorithm> +#include <queue> +#include <set> +#include <cmath> #include "externs.h" @@ -3733,6 +3736,202 @@ static void _maybe_restart_fountain_flow(const coord_def& where, } } +// Spawn a ring of mushrooms around the input corpse (radius=1). +// Could try different radii/check for largest available but doesn't right now. +// Maybe there should be a message for this. +static int _mushroom_ring(item_def &corpse) +{ + ::adjacent_iterator adj(corpse.pos); + + int spawned_count=0; + for ( ; adj; ++adj) + { + if (mons_class_can_pass(MONS_TOADSTOOL, grd(*adj)) + && !actor_at(*adj)) + { + const int mushroom = create_monster( + mgen_data(MONS_TOADSTOOL, + BEH_HOSTILE, + 0, + 0, + *adj, + MHITNOT, + MG_FORCE_PLACE, + GOD_NO_GOD, + MONS_PROGRAM_BUG, + 0, + corpse.colour), + false); + + if (mushroom != -1) + spawned_count++; + } + } + return spawned_count; +} + +// Try to spawn 'target_count' mushrooms around the position of 'corpse'. +// Returns the number of mushrooms actually spawned. +// Mushrooms radiate outwards from the corpse following bfs with 8-connectivity. +// Could change the expansion pattern by using a priority queue for +// sequencing (priority = distance from origin under some metric). +int spawn_corpse_mushrooms(item_def &corpse, int target_count = 1) +{ + if (target_count == 0) + return 0; + + int x_offset[] = {-1,-1,-1, 0, 0, 1, 1, 1}; + int y_offset[] = {-1, 0, 1,-1, 1,-1, 0, 1}; + + + int placed_targets = 0; + + std::queue<coord_def> fringe; + std::set<int> visited_indices; + + // Slight chance of spawning a ring of mushrooms around the corpse (and + // skeletonizing it) if the corpse square is unoccupied. + if (!actor_at(corpse.pos) && one_chance_in(100)) + { + if (see_grid(corpse.pos)) + mpr("A ring of toadstools grow before your very eyes."); + + corpse.special = 0; + return _mushroom_ring(corpse); + } + + // Can't figure out how to query the size of the xdim of the grid but who + // cares. + visited_indices.insert(10000*corpse.pos.y + corpse.pos.x); + fringe.push(corpse.pos); + + while (!fringe.empty()) + { + coord_def current = fringe.front(); + + fringe.pop(); + + actor * occupant = NULL; + // is this square occupied by a non mushroom? + if((occupant = actor_at(current)) + && occupant->mons_species() != MONS_TOADSTOOL) + { + continue; + } + + if (!occupant) + { + const int mushroom = create_monster( + mgen_data(MONS_TOADSTOOL, + BEH_HOSTILE, + 0, + 0, + current, + MHITNOT, + MG_FORCE_PLACE, + GOD_NO_GOD, + MONS_PROGRAM_BUG, + 0, + corpse.colour), + false); + + if (mushroom != -1) + { + placed_targets++; + if (see_grid(current)) + { + if (see_grid(corpse.pos)) + mpr("A toadstool grows from a nearby corpse."); + else + mpr("A toadstool springs up from the ground."); + } + } + else + continue; + } + + // We're done here if we place the desired number of mushrooms. + if (placed_targets == target_count) + break; + + // Randomize the order in which children are processed to a certain + // extent. + int idx = rand() % 8; + + for (int count = 0; count < 8; ++count) + { + idx= (idx + 1) % 8; + coord_def temp(current.x + x_offset[idx], current.y + y_offset[idx]); + + int index = temp.x + temp.y * 10000; + + if (visited_indices.find(index) == visited_indices.end() + && in_bounds(temp) + && mons_class_can_pass(MONS_TOADSTOOL, grd(temp))) + { + + visited_indices.insert(index); + fringe.push(temp); + } + } + } + + return placed_targets; +} + + +// Randomly decide whether or not to spawn a mushroom over the given corpse +// Assumption: this is called before the rotting away logic in update_corpses. +// Some conditions in this function may set the corpse timer to 0, assuming +// that the corpse will be turned into a skeleton/destroyed on this update. +static void _maybe_spawn_mushroom(item_def & corpse, int rot_time) +{ + // We won't spawn a mushroom within 10 turns of the corpse being created + // or rotting away. + int low_threshold = 5; + int high_threshold = FRESHEST_CORPSE - 5; + + if (corpse.special < low_threshold) + return; + + int spawn_time = (rot_time > corpse.special ? corpse.special : rot_time); + + if (spawn_time > high_threshold) + spawn_time = high_threshold; + + // So we're going to spawn one or more mushrooms over the lifetime of a + // corpse here. For convenience we follow a binomial distribution. I think + // the most useful analysis is in terms of the probability of a corpse + // producing no mushrooms, although trial probability should just be hard + // coded once a value is agreed on. + + + // Expect this many trials over a corpse's lifetime since this function + // is called once for every 10 units of rot_time. + int step_size = 10; + float total_trials = (high_threshold - low_threshold) / step_size; + + // chance of producing no mushrooms + float p_failure = .5; + + float trial_prob_f = 1 - powf(p_failure,1.0f/total_trials); + + // The chance of producing mushrooms depends on the weight of the + // corpse involved. Humans weigh 550 so we will take that as the + // base factor here. + float weight_factor = item_mass(corpse)/550.0f; + + trial_prob_f *= weight_factor; + + int trial_prob = static_cast<int>(100*trial_prob_f); + + int current_trials = spawn_time/step_size; + + int success_count = binomial_generator(current_trials, trial_prob); + + spawn_corpse_mushrooms(corpse, success_count); +} + //--------------------------------------------------------------- // // update_corpses @@ -3762,6 +3961,9 @@ void update_corpses(double elapsedTime) continue; } + if (it.sub_type == CORPSE_BODY) + _maybe_spawn_mushroom(it, rot_time); + if (rot_time >= it.special && !is_being_butchered(it)) { if (it.base_type == OBJ_FOOD) |