Add minor cosmetic fixes.
[crawl:rriegs-crawl.git] / crawl-ref / source / dactions.cc
1 /**
2  * @file
3  * @brief Delayed level actions.
4 **/
5
6 #include "AppHdr.h"
7
8 #include "dactions.h"
9
10 #include "coordit.h"
11 #include "debug.h"
12 #include "decks.h"
13 #include "dungeon.h"
14 #include "env.h"
15 #include "libutil.h"
16 #include "mon-behv.h"
17 #include "mon-iter.h"
18 #include "mon-stuff.h"
19 #include "mon-transit.h"
20 #include "mon-util.h"
21 #include "player.h"
22 #include "religion.h"
23 #include "travel.h"
24 #include "view.h"
25
26 #ifdef DEBUG_DIAGNOSTICS
27 static const char *daction_names[] =
28 {
29     "holy beings go hostile",
30     "unholy/evil go hostile",
31     "unclean/chaotic go hostile",
32     "spellcasters go hostile",
33     "yred slaves go hostile",
34     "beogh orcs and their summons go hostile",
35     "fellow slimes go hostile",
36     "plants go hostile (allowing reconversion)",
37     0, 0, 0, 0, 0, 0, 0, 0,
38
39     // Actions not needing a counter.
40     "old enslaved souls go poof",
41     "holy beings allow another conversion attempt",
42 #if TAG_MAJOR_VERSION > 34
43     "slimes allow another conversion attempt",
44 #endif
45     "holy beings go neutral",
46     "Trog's gifts go hostile",
47     "shuffle decks",
48     "reapply passive mapping",
49     "remove Jiyva altars",
50     "Pikel's slaves go good-neutral",
51     "corpses rot",
52     "Tomb loses -cTele",
53 #if TAG_MAJOR_VERSION == 34
54     "slimes allow another conversion attempt",
55 #endif
56 };
57 #endif
58
59 bool mons_matches_daction(const monster* mon, daction_type act)
60 {
61     if (!mon || !mon->alive())
62         return false;
63
64     switch (act)
65     {
66     case DACT_ALLY_HOLY:
67         return (mon->wont_attack() && is_good_god(mon->god));
68     case DACT_ALLY_UNHOLY_EVIL:
69         return (mon->wont_attack() && (mon->is_unholy() || mon->is_evil()));
70     case DACT_ALLY_UNCLEAN_CHAOTIC:
71         return (mon->wont_attack() && (mon->is_unclean() || mon->is_chaotic()));
72     case DACT_ALLY_SPELLCASTER:
73         return (mon->wont_attack() && mon->is_actual_spellcaster());
74     case DACT_ALLY_YRED_SLAVE:
75         // Changed: we don't force enslavement of those merely marked.
76         return is_yred_undead_slave(mon);
77     case DACT_ALLY_BEOGH: // both orcs and demons summoned by high priests
78         return (mon->wont_attack() && mons_is_god_gift(mon, GOD_BEOGH));
79     case DACT_ALLY_SLIME:
80         return is_fellow_slime(mon);
81     case DACT_ALLY_PLANT:
82         // No check for friendliness since we pretend all plants became friendly
83         // the moment you converted to Fedhas.
84         return mons_is_plant(mon);
85
86     // Not a stored counter:
87     case DACT_ALLY_TROG:
88         return (mon->friendly() && mons_is_god_gift(mon, GOD_TROG));
89     case DACT_HOLY_PETS_GO_NEUTRAL:
90         return (mon->friendly()
91                 && !mon->has_ench(ENCH_CHARM)
92                 && mon->is_holy()
93                 && mons_is_god_gift(mon, GOD_SHINING_ONE));
94     case DACT_PIKEL_SLAVES:
95         return (mon->type == MONS_SLAVE
96                 && testbits(mon->flags, MF_BAND_MEMBER)
97                 && mon->props.exists("pikel_band")
98                 && mon->mname != "freed slave");
99
100     case DACT_OLD_ENSLAVED_SOULS_POOF:
101         return mons_enslaved_soul(mon);
102
103     case DACT_HOLY_NEW_ATTEMPT:
104         return mon->is_holy();
105
106     case DACT_SLIME_NEW_ATTEMPT:
107         return mons_is_slime(mon);
108
109     default:
110         return false;
111     }
112 }
113
114 void update_da_counters(LevelInfo *lev)
115 {
116     for (int act = 0; act < NUM_DA_COUNTERS; act++)
117         lev->da_counters[act] = 0;
118
119     for (monster_iterator mi; mi; ++mi)
120         for (int act = 0; act < NUM_DA_COUNTERS; act++)
121             if (mons_matches_daction(*mi, static_cast<daction_type>(act)))
122                 lev->da_counters[act]++;
123 }
124
125 void add_daction(daction_type act)
126 {
127 #ifdef DEBUG_DIAGNOSTICS
128     COMPILE_CHECK(ARRAYSZ(daction_names) == NUM_DACTIONS);
129 #endif
130
131     dprf("scheduling delayed action: %s", daction_names[act]);
132     you.dactions.push_back(act);
133
134     // If we're removing a counted monster type, zero the counter even though
135     // it hasn't been actually removed from the levels yet.
136     if (act < NUM_DA_COUNTERS)
137         travel_cache.clear_da_counter(act);
138
139     // Immediately apply it to the current level.
140     catchup_dactions();
141
142     // And now to any monsters in transit.
143     apply_daction_to_transit(act);
144
145 }
146
147 void apply_daction_to_mons(monster* mon, daction_type act, bool local)
148 {
149     switch (act)
150     {
151         case DACT_ALLY_HOLY:
152         case DACT_ALLY_UNHOLY_EVIL:
153         case DACT_ALLY_UNCLEAN_CHAOTIC:
154         case DACT_ALLY_SPELLCASTER:
155         case DACT_ALLY_YRED_SLAVE:
156         case DACT_ALLY_BEOGH:
157         case DACT_ALLY_SLIME:
158         case DACT_ALLY_PLANT:
159         case DACT_ALLY_TROG:
160             dprf("going hostile: %s", mi->name(DESC_PLAIN, true).c_str());
161             mon->attitude = ATT_HOSTILE;
162             mon->del_ench(ENCH_CHARM, true);
163             if (local)
164                 behaviour_event(mon, ME_ALERT, &you);
165             // For now CREATED_FRIENDLY/WAS_NEUTRAL stays.
166             mons_att_changed(mon);
167
168             // If you reconvert to Fedhas/Jiyva, plants/slimes will
169             // love you again.
170             if (act == DACT_ALLY_PLANT || act == DACT_ALLY_SLIME)
171                 mon->flags &= ~MF_ATT_CHANGE_ATTEMPT;
172
173             // No global message for Trog.
174             if (act == DACT_ALLY_TROG && local)
175                 simple_monster_message(mon, " turns against you!");
176             break;
177
178         case DACT_OLD_ENSLAVED_SOULS_POOF:
179             simple_monster_message(mon, " is freed.");
180             // The monster disappears.
181             monster_die(mon, KILL_DISMISSED, NON_MONSTER);
182             break;
183
184         case DACT_HOLY_NEW_ATTEMPT:
185         case DACT_SLIME_NEW_ATTEMPT:
186             mon->flags &= ~MF_ATT_CHANGE_ATTEMPT;
187             break;
188
189         case DACT_HOLY_PETS_GO_NEUTRAL:
190         case DACT_PIKEL_SLAVES:
191             // monster changes attitude
192             mon->attitude = ATT_GOOD_NEUTRAL;
193             mons_att_changed(mon);
194
195             if (act == DACT_PIKEL_SLAVES)
196             {
197                 mon->flags |= MF_NAME_REPLACE | MF_NAME_DESCRIPTOR |
198                                 MF_NAME_NOCORPSE;
199                 mon->mname = "freed slave";
200             }
201             else if (local)
202                 simple_monster_message(mon, " becomes indifferent.");
203             mon->behaviour = BEH_WANDER;
204             break;
205
206         // The other dactions do not affect monsters directly
207         default:
208             break;
209     }
210 }
211
212 static void _apply_daction(daction_type act)
213 {
214     ASSERT(act >= 0 && act < NUM_DACTIONS);
215     dprf("applying delayed action: %s", daction_names[act]);
216
217     switch (act)
218     {
219     case DACT_ALLY_HOLY:
220     case DACT_ALLY_UNHOLY_EVIL:
221     case DACT_ALLY_UNCLEAN_CHAOTIC:
222     case DACT_ALLY_SPELLCASTER:
223     case DACT_ALLY_YRED_SLAVE:
224     case DACT_ALLY_BEOGH:
225     case DACT_ALLY_SLIME:
226     case DACT_ALLY_PLANT:
227     case DACT_ALLY_TROG:
228     case DACT_OLD_ENSLAVED_SOULS_POOF:
229     case DACT_HOLY_NEW_ATTEMPT:
230     case DACT_SLIME_NEW_ATTEMPT:
231     case DACT_HOLY_PETS_GO_NEUTRAL:
232     case DACT_PIKEL_SLAVES:
233         for (monster_iterator mi; mi; ++mi)
234         {
235             if (mons_matches_daction(*mi, act))
236                 apply_daction_to_mons(*mi, act, true);
237         }
238         break;
239
240     case DACT_SHUFFLE_DECKS:
241         shuffle_all_decks_on_level();
242         break;
243     case DACT_REAUTOMAP:
244         reautomap_level();
245         break;
246     case DACT_REMOVE_JIYVA_ALTARS:
247         for (rectangle_iterator ri(1); ri; ++ri)
248         {
249             if (grd(*ri) == DNGN_ALTAR_JIYVA)
250                 grd(*ri) = DNGN_FLOOR;
251         }
252         break;
253     case DACT_ROT_CORPSES:
254         for (int i = 0; i < MAX_ITEMS; i++)
255             if (mitm[i].base_type == OBJ_CORPSES && mitm[i].sub_type == CORPSE_BODY)
256                 mitm[i].special = 1; // thoroughly rotten
257         break;
258     case DACT_TOMB_CTELE:
259         if (player_in_branch(BRANCH_TOMB))
260             unset_level_flags(LFLAG_NO_TELE_CONTROL, you.depth != 3);
261         break;
262     case NUM_DA_COUNTERS:
263     case NUM_DACTIONS:
264         ;
265     }
266 }
267
268 void catchup_dactions()
269 {
270     while (env.dactions_done < you.dactions.size())
271         _apply_daction(you.dactions[env.dactions_done++]);
272 }
273
274 unsigned int query_da_counter(daction_type c)
275 {
276     return travel_cache.query_da_counter(c) + count_daction_in_transit(c);
277 }