1 /**
2  * @file
3  * @brief Monster related debugging functions.
4 **/
5 
6 #include "AppHdr.h"
7 
8 #include "wiz-mon.h"
9 
10 #include <sstream>
11 
12 #include "abyss.h"
13 #include "act-iter.h"
14 #include "areas.h"
15 #include "cloud.h"
16 #include "colour.h"
17 #include "command.h"
18 #include "dbg-util.h"
19 #include "delay.h"
20 #include "directn.h"
21 #include "dungeon.h"
22 #include "english.h"
23 #include "files.h"
24 #include "ghost.h"
25 #include "god-blessing.h"
26 #include "invent.h"
27 #include "item-prop.h"
28 #include "items.h"
29 #include "jobs.h"
30 #include "libutil.h"
31 #include "macro.h"
32 #include "message.h"
33 #include "mon-death.h"
34 #include "mon-pathfind.h"
35 #include "mon-place.h"
36 #include "mon-poly.h"
37 #include "mon-speak.h"
38 #include "output.h"
39 #include "prompt.h"
40 #include "religion.h"
41 #include "shout.h"
42 #include "spl-miscast.h"
43 #include "state.h"
44 #include "stringutil.h"
45 #include "terrain.h"
46 #include "view.h"
47 #include "viewmap.h"
48 
49 #ifdef WIZARD
50 
51 // Creates a specific monster by name. Uses the same patterns as
52 // map definitions.
wizard_create_spec_monster_name()53 void wizard_create_spec_monster_name()
54 {
55     char specs[1024];
56     mprf(MSGCH_PROMPT, "Enter monster name (or MONS spec) (? for help): ");
57     if (cancellable_get_line_autohist(specs, sizeof specs) || !*specs)
58     {
59         canned_msg(MSG_OK);
60         return;
61     }
62 
63     if (!strcmp(specs, "?"))
64     {
65         show_specific_help("wiz-monster");
66         return;
67     }
68 
69     mons_list mlist;
70     string err = mlist.add_mons(specs);
71 
72     if (!err.empty())
73     {
74         string newerr = "yes";
75         // Try for a partial match, but not if the user accidentally entered
76         // only a few letters.
77         monster_type partial = get_monster_by_name(specs, true);
78         if (strlen(specs) >= 3 && partial != MONS_PROGRAM_BUG)
79         {
80             mlist.clear();
81             newerr = mlist.add_mons(mons_type_name(partial, DESC_PLAIN));
82         }
83 
84         if (!newerr.empty())
85         {
86             mpr(err);
87             return;
88         }
89     }
90 
91     mons_spec mspec = mlist.get_monster(0);
92     if (mspec.type == MONS_NO_MONSTER)
93     {
94         mprf(MSGCH_DIAGNOSTICS, "Such a monster couldn't be found.");
95         return;
96     }
97 
98     monster_type type =
99         fixup_zombie_type(static_cast<monster_type>(mspec.type),
100                           mspec.monbase);
101 
102     coord_def place = find_newmons_square(type, you.pos());
103     if (!in_bounds(place))
104     {
105         // Try again with habitat HT_LAND.
106         // (Will be changed to the necessary terrain type in dgn_place_monster.)
107         place = find_newmons_square(MONS_NO_MONSTER, you.pos());
108     }
109 
110     if (!in_bounds(place))
111     {
112         mprf(MSGCH_DIAGNOSTICS, "Found no space to place monster.");
113         return;
114     }
115 
116     // Wizmode users should be able to conjure up uniques even if they
117     // were already created. Yay, you can meet 3 Sigmunds at once! :p
118     if (mons_is_unique(type) && you.unique_creatures[type])
119         you.unique_creatures.set(type, false);
120 
121     if (mons_class_requires_band(type) && !mspec.band)
122     {
123         mprf(MSGCH_DIAGNOSTICS,
124              "That monster can only be created with a band.");
125         return;
126     }
127 
128     if (!dgn_place_monster(mspec, place, true, false))
129     {
130         mprf(MSGCH_DIAGNOSTICS, "Unable to place monster.");
131         return;
132     }
133 
134     // FIXME: This is a bit useless, seeing how you cannot set the
135     // ghost's stats, brand or level, among other things.
136     if (mspec.type == MONS_PLAYER_GHOST)
137     {
138         unsigned short idx = env.mgrid(place);
139 
140         if (idx >= MAX_MONSTERS || env.mons[idx].type != MONS_PLAYER_GHOST)
141         {
142             for (idx = 0; idx < MAX_MONSTERS; idx++)
143             {
144                 if (env.mons[idx].type == MONS_PLAYER_GHOST
145                     && env.mons[idx].alive())
146                 {
147                     break;
148                 }
149             }
150         }
151 
152         if (idx >= MAX_MONSTERS)
153         {
154             mpr("Couldn't find player ghost, probably going to crash.");
155             more();
156             return;
157         }
158 
159         monster    &mon = env.mons[idx];
160         ghost_demon ghost;
161 
162         ghost.name = "John Doe";
163 
164         char input_str[80];
165         msgwin_get_line("Make player ghost which species? (case-sensitive) ",
166                         input_str, sizeof(input_str));
167 
168         species_type sp_id = species::from_abbrev(input_str);
169         if (sp_id == SP_UNKNOWN)
170             sp_id = species::from_str(input_str);
171         if (sp_id == SP_UNKNOWN)
172         {
173             mpr("No such species, making it Human.");
174             sp_id = SP_HUMAN;
175         }
176         ghost.species = static_cast<species_type>(sp_id);
177 
178         msgwin_get_line("Give player ghost which background? ",
179                         input_str, sizeof(input_str));
180 
181         int job_id = get_job_by_abbrev(input_str);
182 
183         if (job_id == JOB_UNKNOWN)
184             job_id = get_job_by_name(input_str);
185 
186         if (job_id == JOB_UNKNOWN)
187         {
188             mpr("No such background, making it a Fighter.");
189             job_id = JOB_FIGHTER;
190         }
191         ghost.job = static_cast<job_type>(job_id);
192         ghost.xl = 7;
193         ghost.max_hp = 20;
194         ASSERT(debug_check_ghost(ghost));
195 
196         mon.set_ghost(ghost);
197     }
198 }
199 
_sort_monster_list(int a,int b)200 static bool _sort_monster_list(int a, int b)
201 {
202     const monster* m1 = &env.mons[a];
203     const monster* m2 = &env.mons[b];
204 
205     if (m1->alive() != m2->alive())
206         return m1->alive();
207     else if (!m1->alive())
208         return a < b;
209 
210     if (m1->type == m2->type)
211     {
212         if (!m1->alive() || !m2->alive())
213             return false;
214 
215         return m1->name(DESC_PLAIN, true) < m2->name(DESC_PLAIN, true);
216     }
217 
218     const unsigned glyph1 = mons_char(m1->type);
219     const unsigned glyph2 = mons_char(m2->type);
220     if (glyph1 != glyph2)
221         return glyph1 < glyph2;
222 
223     return m1->type < m2->type;
224 }
225 
debug_list_monsters()226 void debug_list_monsters()
227 {
228     vector<string> mons;
229     int nfound = 0;
230 
231     int mon_nums[MAX_MONSTERS];
232 
233     for (int i = 0; i < MAX_MONSTERS; ++i)
234         mon_nums[i] = i;
235 
236     sort(mon_nums, mon_nums + MAX_MONSTERS, _sort_monster_list);
237 
238     int total_exp = 0, total_adj_exp = 0, total_nonuniq_exp = 0;
239 
240     string prev_name = "";
241     int    count     = 0;
242 
243     for (int i = 0; i < MAX_MONSTERS; ++i)
244     {
245         const int idx = mon_nums[i];
246         if (invalid_monster_index(idx))
247             continue;
248 
249         const monster* mi(&env.mons[idx]);
250         if (!mi->alive())
251             continue;
252 
253         string name = mi->name(DESC_PLAIN, true);
254 
255         if (prev_name != name && count > 0)
256         {
257             char buf[80];
258             if (count > 1)
259             {
260                 snprintf(buf, sizeof(buf), "%d %s", count,
261                          pluralise_monster(prev_name).c_str());
262             }
263             else
264                 snprintf(buf, sizeof(buf), "%s", prev_name.c_str());
265             mons.push_back(buf);
266 
267             count = 0;
268         }
269         nfound++;
270         count++;
271         prev_name = name;
272 
273         int exp = exper_value(*mi);
274         total_exp += exp;
275         if (!mons_is_unique(mi->type))
276             total_nonuniq_exp += exp;
277 
278         if ((mi->flags & (MF_WAS_NEUTRAL | MF_NO_REWARD))
279             || mi->has_ench(ENCH_ABJ))
280         {
281             continue;
282         }
283         if (mi->flags & MF_PACIFIED)
284             exp /= 2;
285 
286         total_adj_exp += exp;
287     }
288 
289     char buf[80];
290     if (count > 1)
291     {
292         snprintf(buf, sizeof(buf), "%d %s", count,
293                  pluralise_monster(prev_name).c_str());
294     }
295     else
296         snprintf(buf, sizeof(buf), "%s", prev_name.c_str());
297     mons.emplace_back(buf);
298 
299     mpr_comma_separated_list("Monsters: ", mons);
300 
301     if (total_adj_exp == total_exp)
302     {
303         mprf("%d monsters, %d total exp value (%d non-uniq)",
304              nfound, total_exp, total_nonuniq_exp);
305     }
306     else
307     {
308         mprf("%d monsters, %d total exp value (%d non-uniq, %d adjusted)",
309              nfound, total_exp, total_nonuniq_exp, total_adj_exp);
310     }
311 }
312 
wizard_spawn_control()313 void wizard_spawn_control()
314 {
315     mprf(MSGCH_PROMPT, "(c)hange spawn rate or (s)pawn monsters? ");
316     const int c = toalower(getchm());
317 
318     char specs[256];
319     bool done = false;
320 
321     if (c == 'c')
322     {
323         mprf(MSGCH_PROMPT, "Set monster spawn rate to what? (now %d, lower value = higher rate) ",
324              env.spawn_random_rate);
325 
326         if (!cancellable_get_line(specs, sizeof(specs)))
327         {
328             const int rate = atoi(specs);
329             if (rate || specs[0] == '0')
330             {
331                 mprf("Setting monster spawn rate to %i.", rate);
332                 env.spawn_random_rate = rate;
333                 done = true;
334             }
335         }
336     }
337     else if (c == 's')
338     {
339         // 50 spots are reserved for non-wandering monsters.
340         int max_spawn = MAX_MONSTERS - 50;
341         for (monster_iterator mi; mi; ++mi)
342             if (mi->alive())
343                 max_spawn--;
344 
345         if (max_spawn <= 0)
346         {
347             mprf(MSGCH_PROMPT, "Level already filled with monsters, "
348                                "get rid of some of them first.");
349             return;
350         }
351 
352         mprf(MSGCH_PROMPT, "Spawn how many random monsters (max %d)? ",
353              max_spawn);
354 
355         if (!cancellable_get_line(specs, sizeof(specs)))
356         {
357             const int num = min(atoi(specs), max_spawn);
358             if (num > 0)
359             {
360                 mprf("Spawning %i monster%s.", num, num == 1 ? "" : "s");
361                 int curr_rate = env.spawn_random_rate;
362                 // Each call to spawn_random_monsters() will spawn one with
363                 // the rate at 5 or less.
364                 env.spawn_random_rate = 5;
365 
366                 for (int i = 0; i < num; ++i)
367                     spawn_random_monsters();
368 
369                 env.spawn_random_rate = curr_rate;
370                 done = true;
371             }
372         }
373     }
374 
375     if (!done)
376         canned_msg(MSG_OK);
377 }
378 
379 static const char* ht_names[] =
380 {
381     "land",
382     "amphibious",
383     "water",
384     "lava",
385     "amphibious_lava",
386 };
387 
388 // Prints a number of useful (for debugging, that is) stats on monsters.
debug_stethoscope(int mon)389 void debug_stethoscope(int mon)
390 {
391     dist stth;
392     coord_def stethpos;
393 
394     int i;
395 
396     if (mon != RANDOM_MONSTER)
397         i = mon;
398     else
399     {
400         mprf(MSGCH_PROMPT, "Which monster?");
401 
402         direction(stth, direction_chooser_args());
403 
404         if (!stth.isValid)
405             return;
406 
407         if (stth.isTarget)
408             stethpos = stth.target;
409         else
410             stethpos = you.pos() + stth.delta;
411 
412         if (cloud_struct* cloud = cloud_at(stethpos))
413         {
414             mprf(MSGCH_DIAGNOSTICS, "cloud type: %d delay: %d",
415                  cloud->type, cloud->decay);
416         }
417 
418         if (!monster_at(stethpos))
419         {
420             mprf(MSGCH_DIAGNOSTICS, "item grid = %d", env.igrid(stethpos));
421             return;
422         }
423 
424         i = env.mgrid(stethpos);
425     }
426 
427     monster& mons(env.mons[i]);
428 
429     // Print type of monster.
430     mprf(MSGCH_DIAGNOSTICS, "%s (id #%d; type=%d loc=(%d,%d) align=%s)",
431          mons.name(DESC_THE, true).c_str(),
432          i, mons.type, mons.pos().x, mons.pos().y,
433          ((mons.attitude == ATT_HOSTILE)        ? "hostile" :
434           (mons.attitude == ATT_FRIENDLY)       ? "friendly" :
435           (mons.attitude == ATT_NEUTRAL)        ? "neutral" :
436           (mons.attitude == ATT_GOOD_NEUTRAL)   ? "good neutral":
437           (mons.attitude == ATT_STRICT_NEUTRAL) ? "strictly neutral"
438                                                 : "unknown alignment"));
439 
440     // Print stats and other info.
441     mprf(MSGCH_DIAGNOSTICS,
442          "HD=%d/%d (%u) HP=%d/%d AC=%d(%d) EV=%d(%d) WL=%d XP=%d SP=%d "
443          "energy=%d%s%s mid=%u num=%d stealth=%d flags=%04" PRIx64,
444          mons.get_hit_dice(),
445          mons.get_experience_level(),
446          mons.experience,
447          mons.hit_points, mons.max_hit_points,
448          mons.base_armour_class(), mons.armour_class(),
449          mons.base_evasion(), mons.evasion(),
450          mons.willpower(),
451          exper_value(mons),
452          mons.speed, mons.speed_increment,
453          mons.base_monster != MONS_NO_MONSTER ? " base=" : "",
454          mons.base_monster != MONS_NO_MONSTER ?
455          get_monster_data(mons.base_monster)->name : "",
456          mons.mid, mons.number, mons.stealth(), mons.flags.flags);
457 
458     if (mons.damage_total)
459     {
460         mprf(MSGCH_DIAGNOSTICS,
461              "pdam=%1.1f/%d (%d%%)",
462              0.5 * mons.damage_friendly, mons.damage_total,
463              50 * mons.damage_friendly / mons.damage_total);
464     }
465 
466     // Print habitat and behaviour information.
467     const habitat_type hab = mons_habitat(mons);
468 
469     COMPILE_CHECK(ARRAYSZ(ht_names) == NUM_HABITATS);
470     const actor * const summoner = actor_by_mid(mons.summoner);
471     mprf(MSGCH_DIAGNOSTICS,
472          "hab=%s beh=%s(%d) foe=%s(%d) mem=%d target=(%d,%d) "
473          "firing_pos=(%d,%d) patrol_point=(%d,%d) god=%s%s",
474          (hab >= 0 && hab < NUM_HABITATS) ? ht_names[hab] : "INVALID",
475          mons.asleep()                    ? "sleep"
476          : mons_is_wandering(mons)       ? "wander"
477          : mons_is_seeking(mons)         ? "seek"
478          : mons_is_fleeing(mons)         ? "flee"
479          : mons.behaviour == BEH_RETREAT  ? "retreat"
480          : mons_is_cornered(mons)        ? "cornered"
481          : mons.behaviour == BEH_WITHDRAW ? "withdraw"
482          :                                  "unknown",
483          mons.behaviour,
484          mons.foe == MHITYOU                      ? "you"
485          : mons.foe == MHITNOT                    ? "none"
486          : env.mons[mons.foe].type == MONS_NO_MONSTER ? "unassigned monster"
487          : env.mons[mons.foe].name(DESC_PLAIN, true).c_str(),
488          mons.foe,
489          mons.foe_memory,
490          mons.target.x, mons.target.y,
491          mons.firing_pos.x, mons.firing_pos.y,
492          mons.patrol_point.x, mons.patrol_point.y,
493          god_name(mons.god).c_str(),
494          (summoner ? make_stringf(" summoner=%s(%d)",
495                                   summoner->name(DESC_PLAIN, true).c_str(),
496                                   summoner->mindex()).c_str()
497                    : ""));
498 
499     // Print resistances.
500     mprf(MSGCH_DIAGNOSTICS, "resist: fire=%d cold=%d elec=%d pois=%d neg=%d "
501                             "acid=%d sticky=%s miasma=%s",
502          mons.res_fire(),
503          mons.res_cold(),
504          mons.res_elec(),
505          mons.res_poison(),
506          mons.res_negative_energy(),
507          mons.res_acid(),
508          mons.res_sticky_flame() ? "yes" : "no",
509          mons.res_miasma() ? "yes" : "no");
510 
511     mprf(MSGCH_DIAGNOSTICS, "ench: %s",
512          mons.describe_enchantments().c_str());
513 
514     mprf(MSGCH_DIAGNOSTICS, "props: %s",
515          mons.describe_props().c_str());
516 
517     ostringstream spl;
518     const monster_spells &hspell_pass = mons.spells;
519     bool found_spell = false;
520     for (unsigned int k = 0; k < hspell_pass.size(); ++k)
521     {
522         if (found_spell)
523             spl << ", ";
524 
525         found_spell = true;
526 
527         spl << k << ": ";
528 
529         if (hspell_pass[k].spell >= NUM_SPELLS)
530             spl << "buggy spell";
531         else
532             spl << spell_title(hspell_pass[k].spell);
533 
534         spl << "." << (int)hspell_pass[k].freq;
535         for (const auto flag : mon_spell_slot_flags::range())
536         {
537             if (!(hspell_pass[k].flags & flag))
538                 continue;
539 
540             // this is arguably redundant with mons_list::parse_mons_spells
541             // specificially the bit that turns names into flags
542             static const map<mon_spell_slot_flag, string> flagnames = {
543                 { MON_SPELL_EMERGENCY,  "E" },
544                 { MON_SPELL_NATURAL,    "N" },
545                 { MON_SPELL_MAGICAL,    "M" },
546                 { MON_SPELL_WIZARD,     "W" },
547                 { MON_SPELL_PRIEST,     "P" },
548                 { MON_SPELL_VOCAL,      "V" },
549                 { MON_SPELL_BREATH,     "br" },
550                 { MON_SPELL_INSTANT,    "in" },
551                 { MON_SPELL_NOISY,      "noi" },
552             };
553             spl << "." << lookup(flagnames, flag, "bug");
554         }
555 
556         spl << " (#" << static_cast<int>(hspell_pass[k].spell) << ")";
557     }
558     if (found_spell)
559         mprf(MSGCH_DIAGNOSTICS, "spells: %s", spl.str().c_str());
560 
561     ostringstream inv;
562     bool found_item = false;
563     for (mon_inv_iterator ii(mons); ii; ++ii)
564     {
565         if (found_item)
566             inv << ", ";
567 
568         found_item = true;
569 
570         inv << ii.slot() << ": ";
571 
572         inv << item_base_name(*ii);
573 
574         inv << " (" << static_cast<int>(ii->index()) << ")";
575     }
576     if (found_item)
577         mprf(MSGCH_DIAGNOSTICS, "inv: %s", inv.str().c_str());
578 
579     if (mons_is_ghost_demon(mons.type))
580     {
581         ASSERT(mons.ghost);
582         const ghost_demon &ghost = *mons.ghost;
583         mprf(MSGCH_DIAGNOSTICS, "Ghost damage: %d; brand: %d; att_type: %d; "
584                                 "att_flav: %d",
585              ghost.damage, ghost.brand, ghost.att_type, ghost.att_flav);
586     }
587 }
588 
589 // Detects all monsters on the level, using their exact positions.
wizard_detect_creatures()590 void wizard_detect_creatures()
591 {
592     int count = 0;
593     for (monster_iterator mi; mi; ++mi)
594     {
595         env.map_knowledge(mi->pos()).set_monster(monster_info(*mi));
596         env.map_knowledge(mi->pos()).set_detected_monster(mi->type);
597 #ifdef USE_TILE
598         tiles.update_minimap(mi->pos());
599 #endif
600         count++;
601     }
602     mprf("Detected %i monster%s.", count, count == 1 ? "" : "s");
603 }
604 
605 // Dismisses all monsters on the level or all monsters that match a user
606 // specified regex.
wizard_dismiss_all_monsters(bool force_all)607 void wizard_dismiss_all_monsters(bool force_all)
608 {
609     char buf[1024] = "";
610     if (!force_all)
611     {
612         mprf(MSGCH_PROMPT, "What monsters to dismiss (ENTER for all, "
613                            "\"harmful\", \"mobile\", \"los\" or a regex, "
614                            "\"keepitem\" to leave items)? ");
615         bool validline = !cancellable_get_line_autohist(buf, sizeof buf);
616 
617         if (!validline)
618         {
619             canned_msg(MSG_OK);
620             return;
621         }
622     }
623 
624     int count = dismiss_monsters(buf);
625     mprf("Dismissed %i monster%s.", count, count == 1 ? "" : "s");
626     // If it was turned off turn autopickup back on if all monsters went away.
627     if (!*buf)
628         autotoggle_autopickup(false);
629 }
630 
debug_make_monster_shout(monster * mon)631 void debug_make_monster_shout(monster* mon)
632 {
633     mprf(MSGCH_PROMPT, "Make the monster (S)hout or (T)alk? ");
634 
635     char type = (char) getchm(KMC_DEFAULT);
636     type = toalower(type);
637 
638     if (type != 's' && type != 't')
639     {
640         canned_msg(MSG_OK);
641         return;
642     }
643 
644     int num_times = prompt_for_int("How many times? ", false);
645 
646     if (num_times <= 0)
647     {
648         canned_msg(MSG_OK);
649         return;
650     }
651 
652     if (type == 's')
653         for (int i = 0; i < num_times; ++i)
654             monster_shout(mon, mons_shouts(mon->type, false));
655     else
656     {
657         if (mon->invisible())
658             mpr("The monster is invisible and likely won't speak.");
659 
660         if (silenced(you.pos()) && !silenced(mon->pos()))
661         {
662             mpr("You are silenced but the monster isn't; you will "
663                 "probably hear/see nothing.");
664         }
665         else if (!silenced(you.pos()) && silenced(mon->pos()))
666             mpr("The monster is silenced and likely won't say anything.");
667         else if (silenced(you.pos()) && silenced(mon->pos()))
668         {
669             mpr("Both you and the monster are silenced, so you likely "
670                 "won't hear anything.");
671         }
672 
673         for (int i = 0; i< num_times; ++i)
674             mons_speaks(mon);
675     }
676 
677     mpr("== Done ==");
678 }
679 
wizard_gain_monster_level(monster * mon)680 void wizard_gain_monster_level(monster* mon)
681 {
682     // Give monster as much experience as it can hold,
683     // but cap the levels gained to just 1.
684     bool worked = mon->gain_exp(INT_MAX - mon->experience, 1);
685     if (!worked)
686         simple_monster_message(*mon, " seems unable to mature further.", MSGCH_WARN);
687 
688     // (The gain_exp() method will chop the monster's experience down
689     // to half-way between its new level and the next, so we needn't
690     // worry about it being left with too much experience.)
691 }
692 
wizard_apply_monster_blessing(monster * mon)693 void wizard_apply_monster_blessing(monster* mon)
694 {
695     mprf(MSGCH_PROMPT, "Apply blessing of (B)eogh, The (S)hining One, or (R)andomly? ");
696 
697     char type = (char) getchm(KMC_DEFAULT);
698     type = toalower(type);
699 
700     if (type != 'b' && type != 's' && type != 'r')
701     {
702         canned_msg(MSG_OK);
703         return;
704     }
705     god_type god = GOD_NO_GOD;
706     if (type == 'b' || type == 'r' && coinflip())
707         god = GOD_BEOGH;
708     else
709         god = GOD_SHINING_ONE;
710 
711     if (!bless_follower(mon, god, true))
712         mprf("%s won't bless this monster for you!", god_name(god).c_str());
713 }
714 
wizard_give_monster_item(monster * mon)715 void wizard_give_monster_item(monster* mon)
716 {
717     mon_itemuse_type item_use = mons_itemuse(*mon);
718     if (item_use < MONUSE_STARTING_EQUIPMENT)
719     {
720         mpr("That type of monster can't use any items.");
721         return;
722     }
723 
724     int player_slot = prompt_invent_item("Give which item to monster?",
725                                           menu_type::drop, OSEL_ANY);
726 
727     if (prompt_failed(player_slot))
728         return;
729 
730     item_def &item = you.inv[player_slot];
731 
732     if (item_is_equipped(item))
733     {
734         mpr("Can't give equipped items to a monster.");
735         return;
736     }
737 
738     mon_inv_type mon_slot = item_to_mslot(item);
739 
740     if (mon_slot == NUM_MONSTER_SLOTS)
741     {
742         mpr("You can't give that type of item to a monster.");
743         return;
744     }
745 
746     if (mon_slot == MSLOT_WEAPON
747         && item.inscription.find("alt") != string::npos)
748     {
749         mon_slot = MSLOT_ALT_WEAPON;
750     }
751 
752     if (!mon->take_item(player_slot, mon_slot))
753         mpr("Error: monster failed to take item.");
754 }
755 
_move_player(const coord_def & where)756 static void _move_player(const coord_def& where)
757 {
758     if (!you.can_pass_through_feat(env.grid(where)))
759     {
760         env.grid(where) = DNGN_FLOOR;
761         set_terrain_changed(where);
762     }
763     move_player_to_grid(where, false);
764     // If necessary, update the Abyss.
765     if (player_in_branch(BRANCH_ABYSS))
766         maybe_shift_abyss_around_player();
767 }
768 
_move_monster(const coord_def & where,int idx1)769 static void _move_monster(const coord_def& where, int idx1)
770 {
771     dist moves;
772     direction_chooser_args args;
773     args.unrestricted = true;
774     args.top_prompt = "Move monster to where?";
775     args.default_place = where;
776     direction(moves, args);
777 
778     if (!moves.isValid || !in_bounds(moves.target))
779         return;
780 
781     monster* mon1 = &env.mons[idx1];
782 
783     const int idx2 = env.mgrid(moves.target);
784     monster* mon2 = monster_at(moves.target);
785 
786     mon1->moveto(moves.target);
787     env.mgrid(moves.target) = idx1;
788     mon1->check_redraw(moves.target);
789 
790     env.mgrid(where) = idx2;
791 
792     if (mon2 != nullptr)
793     {
794         mon2->moveto(where);
795         mon1->check_redraw(where);
796     }
797     if (!you.see_cell(moves.target))
798     {
799         mon1->flags &= ~(MF_WAS_IN_VIEW | MF_SEEN);
800         mon1->seen_context = SC_NONE;
801     }
802 }
803 
wizard_move_player_or_monster(const coord_def & where)804 void wizard_move_player_or_monster(const coord_def& where)
805 {
806     crawl_state.cancel_cmd_again();
807     crawl_state.cancel_cmd_repeat();
808 
809     static bool already_moving = false;
810 
811     if (already_moving)
812     {
813         mpr("Already doing a move command.");
814         return;
815     }
816 
817     already_moving = true;
818 
819     int idx = env.mgrid(where);
820 
821     if (idx == NON_MONSTER)
822     {
823         if (crawl_state.arena_suspended)
824         {
825             mpr("You can't move yourself into the arena.");
826             more();
827             return;
828         }
829         _move_player(where);
830     }
831     else
832         _move_monster(where, idx);
833 
834     already_moving = false;
835 }
836 
wizard_make_monster_summoned(monster * mon)837 void wizard_make_monster_summoned(monster* mon)
838 {
839     int summon_type = 0;
840     if (mon->is_summoned(nullptr, &summon_type) || summon_type != 0)
841     {
842         mprf(MSGCH_PROMPT, "Monster is already summoned.");
843         return;
844     }
845 
846     int dur = prompt_for_int("What summon longevity (1 to 6)? ", true);
847 
848     if (dur < 1 || dur > 6)
849     {
850         canned_msg(MSG_OK);
851         return;
852     }
853 
854     mprf(MSGCH_PROMPT, "[a] clone [b] animated [c] chaos [d] miscast [e] zot");
855     mprf(MSGCH_PROMPT, "[f] wrath [h] aid   [m] misc    [s] spell");
856 
857     mprf(MSGCH_PROMPT, "Which summon type? ");
858 
859     char choice = toalower(getchm());
860 
861     if (!(choice >= 'a' && choice <= 'h') && choice != 'm' && choice != 's')
862     {
863         canned_msg(MSG_OK);
864         return;
865     }
866 
867     int type = 0;
868 
869     switch (choice)
870     {
871         case 'a': type = MON_SUMM_CLONE; break;
872         case 'b': type = MON_SUMM_ANIMATE; break;
873         case 'c': type = MON_SUMM_CHAOS; break;
874         case 'd': type = MON_SUMM_MISCAST; break;
875         case 'e': type = MON_SUMM_ZOT; break;
876         case 'f': type = MON_SUMM_WRATH; break;
877         case 'h': type = MON_SUMM_AID; break;
878         case 'm': type = 0; break;
879 
880         case 's':
881         {
882             char specs[80];
883 
884             msgwin_get_line("Cast which spell by name? ",
885                             specs, sizeof(specs));
886 
887             if (specs[0] == '\0')
888             {
889                 canned_msg(MSG_OK);
890                 return;
891             }
892 
893             spell_type spell = spell_by_name(specs, true);
894             if (spell == SPELL_NO_SPELL)
895             {
896                 mprf(MSGCH_PROMPT, "No such spell.");
897                 return;
898             }
899             type = (int) spell;
900             break;
901         }
902 
903         default:
904             die("Invalid summon type choice.");
905             break;
906     }
907 
908     mon->mark_summoned(dur, true, type);
909     mpr("Monster is now summoned.");
910 }
911 
wizard_polymorph_monster(monster * mon)912 void wizard_polymorph_monster(monster* mon)
913 {
914     monster_type old_type =  mon->type;
915     monster_type type     = debug_prompt_for_monster();
916 
917     if (type == NUM_MONSTERS)
918     {
919         canned_msg(MSG_OK);
920         return;
921     }
922 
923     if (invalid_monster_type(type))
924     {
925         mprf(MSGCH_PROMPT, "Invalid monster type.");
926         return;
927     }
928 
929     if (type == old_type)
930     {
931         mpr("Old type and new type are the same, not polymorphing.");
932         return;
933     }
934 
935     if (mons_species(type) == mons_species(old_type))
936     {
937         mpr("Target species must be different from current species.");
938         return;
939     }
940 
941     monster_polymorph(mon, type, PPT_SAME);
942 
943     if (!mon->alive())
944     {
945         mprf(MSGCH_ERROR, "Polymorph killed monster?");
946         return;
947     }
948 
949     mon->check_redraw(mon->pos());
950 
951     if (mon->type == old_type)
952     {
953         mpr("Trying harder");
954         change_monster_type(mon, type);
955         if (!mon->alive())
956         {
957             mprf(MSGCH_ERROR, "Polymorph killed monster?");
958             return;
959         }
960 
961         mon->check_redraw(mon->pos());
962     }
963 
964     if (mon->type == old_type)
965         mpr("Polymorph failed.");
966     else if (mon->type != type)
967         mpr("Monster turned into something other than the desired type.");
968 }
969 
debug_pathfind(int idx)970 void debug_pathfind(int idx)
971 {
972     if (idx == NON_MONSTER)
973         return;
974 
975     mpr("Choose a destination!");
976 #ifndef USE_TILE_LOCAL
977     more();
978 #endif
979     coord_def dest;
980     level_pos ldest;
981     bool chose = show_map(ldest, false, false);
982     dest = ldest.pos;
983     redraw_screen();
984     update_screen();
985     if (!chose)
986     {
987         canned_msg(MSG_OK);
988         return;
989     }
990 
991     monster& mon = env.mons[idx];
992     mprf("Attempting to calculate a path from (%d, %d) to (%d, %d)...",
993          mon.pos().x, mon.pos().y, dest.x, dest.y);
994     monster_pathfind mp;
995     bool success = mp.init_pathfind(&mon, dest, true, true);
996     if (success)
997     {
998         vector<coord_def> path = mp.backtrack();
999         env.travel_trail = path;
1000 #ifdef USE_TILE_WEB
1001         for (coord_def pos : env.travel_trail)
1002             tiles.update_minimap(pos);
1003 #endif
1004         string path_str;
1005         mpr("Here's the shortest path: ");
1006         for (coord_def pos : path)
1007             path_str += make_stringf("(%d, %d)  ", pos.x, pos.y);
1008         mpr(path_str);
1009         mprf("-> path length: %u", (unsigned int)path.size());
1010 
1011         mpr("");
1012         path = mp.calc_waypoints();
1013         path_str = "";
1014         mpr("");
1015         mpr("And here are the needed waypoints: ");
1016         for (coord_def pos : path)
1017             path_str += make_stringf("(%d, %d)  ", pos.x, pos.y);
1018         mpr(path_str);
1019         mprf("-> #waypoints: %u", (unsigned int)path.size());
1020     }
1021 }
1022 
_miscast_screen_update()1023 static void _miscast_screen_update()
1024 {
1025     viewwindow();
1026 
1027     you.redraw_status_lights = true;
1028     print_stats();
1029     update_screen();
1030 
1031 #ifndef USE_TILE_LOCAL
1032     update_monster_pane();
1033 #endif
1034 }
1035 
debug_miscast(int target_index)1036 void debug_miscast(int target_index)
1037 {
1038     crawl_state.cancel_cmd_repeat();
1039 
1040     actor* target;
1041     if (target_index == NON_MONSTER)
1042         target = &you;
1043     else
1044         target = &env.mons[target_index];
1045 
1046     if (!target->alive())
1047     {
1048         mpr("Can't make already dead target miscast.");
1049         return;
1050     }
1051 
1052     char specs[100];
1053     mprf(MSGCH_PROMPT, "Miscast which school or spell, by name? ");
1054     if (cancellable_get_line_autohist(specs, sizeof specs) || !*specs)
1055     {
1056         canned_msg(MSG_OK);
1057         return;
1058     }
1059 
1060     spell_type spell  = spell_by_name(specs, true);
1061     spschool school   = school_by_name(specs);
1062 
1063     // Prefer exact matches for school name over partial matches for
1064     // spell name.
1065     if (school != spschool::none
1066         && (strcasecmp(specs, spelltype_short_name(school)) == 0
1067             || strcasecmp(specs, spelltype_long_name(school)) == 0))
1068     {
1069         spell = SPELL_NO_SPELL;
1070     }
1071 
1072     if (spell == SPELL_NO_SPELL && school == spschool::none)
1073     {
1074         mpr("No matching spell or spell school.");
1075         return;
1076     }
1077     else if (spell != SPELL_NO_SPELL && school != spschool::none)
1078     {
1079         mprf("Ambiguous: can be spell '%s' or school '%s'.",
1080             spell_title(spell), spelltype_short_name(school));
1081         return;
1082     }
1083 
1084     spschools_type disciplines = spschool::none;
1085     if (spell != SPELL_NO_SPELL)
1086     {
1087         disciplines = get_spell_disciplines(spell);
1088 
1089         if (!disciplines)
1090         {
1091             mprf("Spell '%s' has no disciplines.", spell_title(spell));
1092             return;
1093         }
1094     }
1095 
1096     if (spell != SPELL_NO_SPELL)
1097         mprf("Miscasting spell %s.", spell_title(spell));
1098     else
1099         mprf("Miscasting school %s.", spelltype_long_name(school));
1100 
1101     if (spell != SPELL_NO_SPELL)
1102         mprf(MSGCH_PROMPT, "Enter fail: ");
1103     else
1104         mprf(MSGCH_PROMPT, "Enter level, fail: ");
1105 
1106     if (cancellable_get_line_autohist(specs, sizeof specs) || !*specs)
1107     {
1108         canned_msg(MSG_OK);
1109         return;
1110     }
1111 
1112     int level = -1, fail = -1;
1113 
1114     if (strchr(specs, ','))
1115     {
1116         vector<string> nums = split_string(",", specs);
1117         level  = atoi(nums[0].c_str());
1118         fail = atoi(nums[1].c_str());
1119 
1120         if (level <= 0 || fail <= 0)
1121         {
1122             canned_msg(MSG_OK);
1123             return;
1124         }
1125     }
1126     else
1127     {
1128         if (spell != SPELL_NO_SPELL)
1129         {
1130             mpr("Can only enter spell level for schools, not spells.");
1131             return;
1132         }
1133 
1134         level = atoi(specs);
1135         if (level < 0)
1136         {
1137             canned_msg(MSG_OK);
1138             return;
1139         }
1140         else if (level > 9)
1141         {
1142             mpr("Spell level can be at most 9.");
1143             return;
1144         }
1145     }
1146 
1147     // Handle repeats ourselves since miscasts are likely to interrupt
1148     // command repetions, especially if the player is the target.
1149     int repeats = prompt_for_int("Number of repetitions? ", true);
1150     if (repeats < 1)
1151     {
1152         canned_msg(MSG_OK);
1153         return;
1154     }
1155 
1156     while (target->alive() && repeats-- > 0)
1157     {
1158         if (kbhit())
1159         {
1160             mpr("Key pressed, interrupting miscast testing.");
1161             getchm();
1162             break;
1163         }
1164 
1165         if (spell != SPELL_NO_SPELL)
1166             miscast_effect(spell, fail);
1167         else
1168         {
1169             miscast_effect(*target, target, {miscast_source::wizard}, school,
1170                            level, fail, "testing miscast");
1171         }
1172 
1173         _miscast_screen_update();
1174     }
1175 }
1176 
1177 #ifdef DEBUG_BONES
debug_ghosts()1178 void debug_ghosts()
1179 {
1180     mprf(MSGCH_PROMPT, "(C)reate, create (T)emporary, or (L)oad bones file?");
1181     const char c = toalower(getchm());
1182 
1183     if (c == 'c')
1184         save_ghosts(ghost_demon::find_ghosts(), true, true);
1185     else if (c == 't')
1186         save_ghosts(ghost_demon::find_ghosts(), true, false);
1187     else if (c == 'l')
1188         load_ghosts(MAX_GHOSTS, false);
1189     else
1190         canned_msg(MSG_OK);
1191 }
1192 #endif
1193 
1194 #endif
1195