File: spl-clouds.cc

package info (click to toggle)
crawl 2%3A0.34.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 100,188 kB
  • sloc: cpp: 363,709; ansic: 27,765; javascript: 9,516; python: 8,463; perl: 3,293; java: 3,132; xml: 2,380; makefile: 1,835; sh: 611; objc: 250; cs: 15; sed: 9; lisp: 3
file content (246 lines) | stat: -rw-r--r-- 7,589 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/**
 * @file
 * @brief Cloud creating spells.
**/

#include "AppHdr.h"

#include "spl-clouds.h"

#include <algorithm>

#include "cloud.h"
#include "coord.h"
#include "coordit.h"
#include "corpse.h"
#include "directn.h"
#include "english.h"
#include "env.h"
#include "fprop.h"
#include "fight.h"
#include "fineff.h" // explosion_fineff, etc
#include "items.h"
#include "level-state-type.h"
#include "message.h"
#include "mon-behv.h" // ME_WHACK
#include "ouch.h"
#include "random-pick.h"
#include "shout.h"
#include "spl-util.h"
#include "target.h"
#include "terrain.h"

spret cast_putrefaction(monster* target, int pow, bool fail)
{
    fail_check();

    // Place one miasma cloud immediately beneath the target.
    place_cloud(CLOUD_MIASMA, target->pos(), random_range(5, 9), &you);

    // Then start a spread of fiant miasma that will become proper miasma a
    // turn later.
    map_cloud_spreader_marker *marker =
    new map_cloud_spreader_marker(target->pos(), CLOUD_FAINT_MIASMA, 7,
                                        random_range(18, 28), 5, 2, &you);

    // Start the cloud at radius 1, regardless of the speed of the killing blow
    marker->speed_increment -= you.time_taken - 7;
    env.markers.add(marker);
    env.markers.clear_need_activate();

    mprf("Rot billows forth from %s wounds!", target->name(DESC_ITS).c_str());

    drain_player(75 - div_rand_round(pow * 4, 10), true, true);

    return spret::success;
}

spret kindle_blastmotes(int pow, bool fail)
{
    if (cloud_at(you.pos()))
    {
        mpr("There's already a cloud here!");
        return spret::abort;
    }

    fail_check();

    // Really should be per-cloud, but skeptical people are changing power
    // between successive blastmote casts that often.
    you.props[BLASTMOTE_POWER_KEY] = pow;
    // Longish duration to support setting up silly traps.
    you.props[BLASTMOTE_IMMUNE_KEY] = true;
    place_cloud(CLOUD_BLASTMOTES, you.pos(), random_range(20, 30), &you);
    mpr("A cloud of volatile blastmotes flares up around you! Run!");

    return spret::success;
}

void explode_blastmotes_at(coord_def p)
{
    // Assumes all blastmotes are created by the player.
    // We could fix this in future by checking the 'killer'
    // associated with the cloud being deleted.
    delete_cloud(p);

    bolt beam;
    zappy(ZAP_BLASTMOTE, you.props[BLASTMOTE_POWER_KEY], false, beam);

    beam.target        = p;
    beam.source        = p;
    beam.source_id     = MID_PLAYER;
    beam.attitude      = ATT_FRIENDLY;
    beam.thrower       = KILL_YOU_MISSILE;
    beam.is_explosion  = true;
    beam.ex_size       = 1;

    const string boom  = "The cloud of blastmotes explodes!";
    const string sanct = "By Zin's power, the fiery explosion is contained.";
    schedule_explosion_fineff(beam, boom, sanct, EXPLOSION_FINEFF_CONCUSSION,
                              nullptr, "");
}

spret cast_freezing_cloud(int pow, bolt &beam, bool fail)
{
    if (grid_distance(beam.target, you.pos()) > beam.range
        || !in_bounds(beam.target))
    {
        mpr("That is beyond the maximum range.");
        return spret::abort;
    }

    if (cell_is_solid(beam.target))
    {
        const char *feat = feat_type_name(env.grid(beam.target));
        mprf("You can't place clouds on %s.", article_a(feat).c_str());
        return spret::abort;
    }

    if (is_sanctuary(beam.target))
    {
        mpr("You can't place harmful clouds in a sanctuary.");
        return spret::abort;
    }

    beam.thrower           = KILL_YOU;
    beam.hit               = AUTOMATIC_HIT;
    beam.damage            = CONVENIENT_NONZERO_DAMAGE;
    beam.use_target_as_pos = true;
    beam.origin_spell      = SPELL_FREEZING_CLOUD;
    beam.flavour           = BEAM_COLD;
    beam.name              = "freezing blast";
    player_beam_tracer tracer;
    beam.affect_endpoint(tracer);
    if (cancel_beam_prompt(beam, tracer))
        return spret::abort;

    fail_check();

    big_cloud(CLOUD_COLD, &you, beam.target, pow, 8 + random2(3), -1);
    noisy(spell_effect_noise(SPELL_FREEZING_CLOUD), beam.target);
    return spret::success;
}

/*
 * A cloud_func that places an individual cloud as part of a cloud area. This
 * function is called by apply_area_cloud();
 *
 * @param where       The location of the cloud.
 * @param pow         The spellpower of the spell placing the clouds, which
 *                    determines how long the cloud will last.
 * @param spread_rate How quickly the cloud spreads.
 * @param ctype       The type of cloud to place.
 * @param agent       Any agent that may have caused the cloud. If this is the
 *                    player, god conducts are applied.
 * @param excl_rad    How large of an exclusion radius to make around the
 *                    cloud.
 * @returns           The number of clouds made, which is always 1.
 *
*/
static int _make_a_normal_cloud(coord_def where, int pow, int spread_rate,
                                cloud_type ctype, const actor *agent,
                                int excl_rad)
{
    place_cloud(ctype, where,
                (3 + random2(pow / 4) + random2(pow / 4) + random2(pow / 4)),
                agent, spread_rate, excl_rad);

    return 1;
}

/*
 * Make a large area of clouds centered on a given place. This never creates
 * player exclusions.
 *
 * @param ctype       The type of cloud to place.
 * @param agent       Any agent that may have caused the cloud. If this is the
 *                    player, god conducts are applied.
 * @param where       The location of the cloud.
 * @param pow         The spellpower of the spell placing the clouds, which
 *                    determines how long the cloud will last.
 * @param size        How large a radius of clouds to place from the `where'
 *                    argument.
 * @param spread_rate How quickly the cloud spreads.
*/
void big_cloud(cloud_type cl_type, const actor *agent,
               const coord_def& where, int pow, int size, int spread_rate)
{
    // The starting point _may_ be a place no cloud can be placed on.
    apply_area_cloud(_make_a_normal_cloud, where, pow, size,
                     cl_type, agent, spread_rate, -1);
}

void holy_flames(monster* caster, actor* defender)
{
    const coord_def pos = defender->pos();
    int cloud_count = 0;
    const int dur = 8 + random2avg(caster->get_hit_dice() * 3, 2);

    for (adjacent_iterator ai(pos); ai; ++ai)
    {
        if (monster_at(*ai))
            continue;

        if (place_cloud(CLOUD_HOLY, *ai, dur, caster))
            cloud_count++;
    }

    if (cloud_count)
    {
        if (defender->is_player())
            mpr("Blessed fire suddenly surrounds you!");
        else
            simple_monster_message(*defender->as_monster(),
                                   " is surrounded by blessed fire!");
    }
}

spret scroll_of_poison(bool scroll_unknown)
{
    int created = 0;
    bool unknown_unseen = false;
    for (radius_iterator ri(you.pos(), LOS_NO_TRANS); ri; ++ri)
    {
        if (const actor* act = actor_at(*ri))
        {
            unknown_unseen = unknown_unseen || !you.can_see(*act);
            continue;
        }

        if (place_cloud(CLOUD_POISON, *ri, 10 + random2(11), &you))
            ++created;
    }

    if (created > 0)
    {
        mpr("The air fills with toxic fumes!");
        return spret::success;
    }
    if (!scroll_unknown && !unknown_unseen)
    {
        mpr("There's no open space to fill with poison.");
        return spret::abort;
    }
    canned_msg(MSG_NOTHING_HAPPENS);
    return spret::fail;
}