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
KZWOHH536QBWAPWROR32EOXEK5LRY6I5VHVL7HHI7GOFKCMQTCSQC OVYFNBS6TZ7DGYA3TYM7N244T4M6JE6ISAPOZKOMRRAQEEIVPXBQC LHYTGOCNDWX3CVD2HSQ6LAYC6NLKKI6ZKKNWZ5IQWP6YP5PQEVWQC 25CH7HH4LKXFIZ75YNMXS3TSXO6O27DYSOPLOD45K4OCNFWLS4LQC 5XNQ3SSNBFXFNWA6DPM74W6FH65NX665P3DMH6YCWVFOPZTJSYCQC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC SH6NU4H5TG4O7CRXRHZ7MDHABZLWWXQ77NJDBHI7KCVHXHQYK46QC N5FAAVHNKQZJV2G3JFRW7WKTXB3A4YY6GTVIMBCG5RSA65TKVBGQC ASH5CK6CPBKMLGGIRJ5GKTWMS5W3OBVHTL66RTYZIPFM6KFBYA3QC PDOFPXD2X6VI23AHKCGQ5RVDBG74CNP2E3YOHKXLOARHHBXEK3HQC X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC 4UXFU3FZOCBSLDQ4S7MJKAE2H7VUHCNRDQMIY6NJ3PHYXWNGISDQC 2G7MZ653N3JUHJ4DA5Q7VRO3S5T27DLPKDCJEKB6DGYSTXULUVWAC 5XSXMOBGXFLTIQE6WDXWWFVDOTUPZSIQ2FWT3YI5QMVU6D76IUYQC 3WHI3KM43ZCN4ITJLFQQBQBC4OJPRS7QTBPIQ6QBCUVKRSK476SAC KQNMFSLV62B4ANDKTUZ7LQH2MD2NDGNCP55MKM5YAATQ4T52H2PQC T4FNOPMWYYJHJBTTY33PB43HTJPKEC46L62YERTWIX73HYZSELXQC NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC J7GPW2YXLT6FGSKJ24FGQ24GTRZ6A2BDYM6CIXV4R6YBEHP6BGPAC OONYLF4DAPLIYLBNNRW74IVT5BBTWI4XHQBXSNSPVRX3FTKJBTRAC HIRKGUMNJPWKSVTR6TVBPD3MWNA63CEHCLCIPWEMGDFHVB3NPLDQC QCUMH3C7GXV7ZW444WT5SFAXQOJKJSE2YCQCEHMRYXCWF4QI7UMAC I7QLYOTE6DLQZM7YWUWYLKHRJRB2A3STQ42ALSRGQICEWKD2QTEQC 4RFKVDJKTCRBZU6WPJ2E5OVI5IRPY3UTRPOBLC5QHY4CQJJTLZKQC Y56C5OMUQ5XF2G6DKDV4R5MED44UOIUPTBBQVWQBUHYIXYA5MOZAC // Generate samples from a binomial distribution with n_trials and trial_prob// probability of success per trial. trial_prob is a integer less than 100// representing the % chancee of success.// This just evaluates all n trials, there is probably an efficient way of// doing this but I'm not much of a statistician. -CAOint binomial_generator(unsigned n_trials, unsigned trial_prob){int count = 0;for (unsigned i = 0; i < n_trials; ++i)if (::x_chance_in_y(trial_prob, 100))count++;return count;}
if (mg.cls == MONS_TOADSTOOL){// This enchantment is a timer that counts down until death.// These mushrooms should last longer than the lifespan of a corpse// (to avoid spawning mushrooms in the same place over and over), aside// from that the value is slightly randomized to avoid simultaneous// die-offs of mushroom rings.menv[id].add_ench(ENCH_SLOWLY_DYING);}
{MONS_TOADSTOOL, 'f', BROWN, "toadstool",M_NO_EXP_GAIN | M_STATIONARY,MR_RES_POISON,0, 10, MONS_PLANT, MONS_TOADSTOOL, MH_PLANT, MAG_IMMUNE,{ AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },{ 1, 2,2, 0 },1, 0, MST_NO_SPELLS, CE_NOCORPSE, Z_NOZOMBIE, S_SILENT, I_PLANT,HT_LAND, 10, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_TINY},
}// 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.");elsempr("A toadstool springs up from the ground.");}}elsecontinue;}// 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 mushroomsfloat 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);}