summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/effects.cc
diff options
context:
space:
mode:
authorj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2009-06-29 19:44:39 +0000
committerj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2009-06-29 19:44:39 +0000
commite66c77b50df3c0c91837b52b9e61c8235a96c685 (patch)
treee780b4b6696564f4cf3a5763987bd776ff064537 /crawl-ref/source/effects.cc
parent4dc30336a62ec7e8261253fc0b9c0674efda1555 (diff)
downloadcrawl-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.cc202
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)