1 /**
2 * @file
3 * @brief Misc function related to player transformations.
4 **/
5
6 #include "AppHdr.h"
7
8 #include "transform.h"
9
10 #include <cstdio>
11 #include <cstring>
12
13 #include "artefact.h"
14 #include "art-enum.h"
15 #include "delay.h"
16 #include "english.h"
17 #include "env.h"
18 #include "god-item.h"
19 #include "god-passive.h" // passive_t::resist_polymorph
20 #include "invent.h" // check_old_item_warning
21 #include "item-use.h"
22 #include "item-name.h"
23 #include "item-prop.h"
24 #include "items.h"
25 #include "message.h"
26 #include "mon-death.h"
27 #include "mutation.h"
28 #include "output.h"
29 #include "player-equip.h"
30 #include "player-stats.h"
31 #include "prompt.h"
32 #include "religion.h"
33 #include "spl-cast.h"
34 #include "state.h"
35 #include "stringutil.h"
36 #include "tag-version.h"
37 #include "terrain.h"
38 #include "traps.h"
39 #include "xom.h"
40
41 // transform slot enums into flags
42 #define SLOTF(s) (1 << s)
43
44 static const int EQF_NONE = 0;
45 // "hand" slots (not rings)
46 static const int EQF_HANDS = SLOTF(EQ_WEAPON) | SLOTF(EQ_SHIELD)
47 | SLOTF(EQ_GLOVES);
48 // head and feet (beastly appendage);
49 static const int EQF_HEAD_FOOT = SLOTF(EQ_BOOTS) | SLOTF(EQ_HELMET);
50 // core body slots (statue form)
51 static const int EQF_STATUE = SLOTF(EQ_GLOVES) | SLOTF(EQ_BOOTS)
52 | SLOTF(EQ_BODY_ARMOUR);
53 // more core body slots (Lear's Hauberk)
54 static const int EQF_LEAR = EQF_STATUE | SLOTF(EQ_HELMET);
55 // everything you can (W)ear
56 static const int EQF_WEAR = EQF_LEAR | SLOTF(EQ_CLOAK) | SLOTF(EQ_SHIELD);
57 // everything but jewellery
58 static const int EQF_PHYSICAL = EQF_HANDS | EQF_WEAR;
59 // all rings (except for the macabre finger amulet's)
60 static const int EQF_RINGS = SLOTF(EQ_LEFT_RING) | SLOTF(EQ_RIGHT_RING)
61 | SLOTF(EQ_RING_ONE) | SLOTF(EQ_RING_TWO)
62 | SLOTF(EQ_RING_THREE) | SLOTF(EQ_RING_FOUR)
63 | SLOTF(EQ_RING_FIVE) | SLOTF(EQ_RING_SIX)
64 | SLOTF(EQ_RING_SEVEN) | SLOTF(EQ_RING_EIGHT);
65 // amulet & pal
66 static const int EQF_AMULETS = SLOTF(EQ_AMULET) | SLOTF(EQ_RING_AMULET);
67 // everything
68 static const int EQF_ALL = EQF_PHYSICAL | EQF_RINGS | EQF_AMULETS;
69
melding_description() const70 string Form::melding_description() const
71 {
72 // this is a bit rough and ready...
73 // XX simplify slot melding rather than complicate this function?
74 if (blocked_slots == EQF_ALL)
75 return "Your equipment is entirely melded.";
76 else if (blocked_slots == EQF_PHYSICAL)
77 return "Your armour is entirely melded.";
78 else if ((blocked_slots & EQF_PHYSICAL) == EQF_PHYSICAL)
79 return "Your equipment is almost entirely melded.";
80 else if ((blocked_slots & EQF_STATUE) == EQF_STATUE
81 && (you_can_wear(EQ_GLOVES, false)
82 || you_can_wear(EQ_BOOTS, false)
83 || you_can_wear(EQ_BODY_ARMOUR, false)))
84 {
85 return "Your equipment is partially melded.";
86 }
87 // otherwise, rely on the form description to convey what is melded.
88 return "";
89 }
90
91 static const FormAttackVerbs DEFAULT_VERBS = FormAttackVerbs(nullptr, nullptr,
92 nullptr, nullptr);
93 static const FormAttackVerbs ANIMAL_VERBS = FormAttackVerbs("hit", "bite",
94 "maul", "maul");
95
96 static const FormDuration DEFAULT_DURATION = FormDuration(20, PS_DOUBLE, 100);
97 static const FormDuration BAD_DURATION = FormDuration(15, PS_ONE_AND_A_HALF,
98 100);
99
100 // Class form_entry and the formdata array
101 #include "form-data.h"
102
_find_form_entry(transformation form)103 static const form_entry &_find_form_entry(transformation form)
104 {
105 for (const form_entry &entry : formdata)
106 if (entry.tran == form)
107 return entry;
108 die("No formdata entry found for form %d", (int)form);
109 }
110
Form(const form_entry & fe)111 Form::Form(const form_entry &fe)
112 : short_name(fe.short_name), wiz_name(fe.wiz_name),
113 duration(fe.duration),
114 str_mod(fe.str_mod), dex_mod(fe.dex_mod),
115 blocked_slots(fe.blocked_slots), size(fe.size), hp_mod(fe.hp_mod),
116 can_cast(fe.can_cast), spellcasting_penalty(fe.spellcasting_penalty),
117 unarmed_hit_bonus(fe.unarmed_hit_bonus), uc_colour(fe.uc_colour),
118 uc_attack_verbs(fe.uc_attack_verbs),
119 can_bleed(fe.can_bleed),
120 keeps_mutations(fe.keeps_mutations),
121 shout_verb(fe.shout_verb),
122 shout_volume_modifier(fe.shout_volume_modifier),
123 hand_name(fe.hand_name), foot_name(fe.foot_name),
124 flesh_equivalent(fe.flesh_equivalent),
125 long_name(fe.long_name), description(fe.description),
126 resists(fe.resists),
127 base_unarmed_damage(fe.base_unarmed_damage),
128 can_fly(fe.can_fly), can_swim(fe.can_swim),
129 flat_ac(fe.flat_ac), power_ac(fe.power_ac), xl_ac(fe.xl_ac),
130 uc_brand(fe.uc_brand), uc_attack(fe.uc_attack),
131 prayer_action(fe.prayer_action), equivalent_mons(fe.equivalent_mons),
132 fakemuts(fe.fakemuts)
133 { }
134
Form(transformation tran)135 Form::Form(transformation tran)
136 : Form(_find_form_entry(tran))
137 { }
138 /**
139 * Is the given equipment slot available for use in this form?
140 *
141 * @param slot The equipment slot in question. (May be a weird fake
142 * slot - EQ_STAFF or EQ_ALL_ARMOUR.)
143 * @return Whether at least some items can be worn in this slot in
144 * this form.
145 * (The player's race, or mutations, may still block the
146 * slot, or it may be restricted to subtypes.)
147 */
slot_available(int slot) const148 bool Form::slot_available(int slot) const
149 {
150 if (slot == EQ_ALL_ARMOUR)
151 return !all_blocked(EQF_WEAR);
152 if (slot == EQ_RINGS || slot == EQ_RINGS_PLUS)
153 return !all_blocked(EQF_RINGS);
154
155 if (slot == EQ_STAFF)
156 slot = EQ_WEAPON;
157 return !(blocked_slots & SLOTF(slot));
158 }
159
160 /**
161 * Can the player wear the given item while in this form?
162 *
163 * Does not take mutations into account.
164 *
165 * @param item The item in question
166 * @return Whether this form prevents the player from wearing the
167 * item. (Other things may also prevent it, of course)
168 */
can_wear_item(const item_def & item) const169 bool Form::can_wear_item(const item_def& item) const
170 {
171 if (item.base_type == OBJ_JEWELLERY)
172 {
173 if (jewellery_is_amulet(item))
174 return slot_available(EQ_AMULET);
175 return !all_blocked(EQF_RINGS);
176 }
177
178 if (is_unrandom_artefact(item, UNRAND_LEAR))
179 return !(blocked_slots & EQF_LEAR); // ok if no body slots blocked
180
181 return slot_available(get_armour_slot(item));
182 }
183
184 /**
185 * Get the bonus to form duration granted for a given (spell)power.
186 *
187 * @param pow The spellpower/equivalent of the form.
188 * @return A bonus to form duration.
189 */
power_bonus(int pow) const190 int FormDuration::power_bonus(int pow) const
191 {
192 switch (scaling_type)
193 {
194 case PS_NONE:
195 return 0;
196 case PS_SINGLE:
197 return random2(pow);
198 case PS_ONE_AND_A_HALF:
199 return random2(pow) + random2(pow/2);
200 case PS_DOUBLE:
201 return random2(pow) + random2(pow);
202 default:
203 die("Unknown scaling type!");
204 return -1;
205 }
206 }
207
208 /**
209 * Get the duration for this form, when newly entered.
210 *
211 * @param pow The power of the effect creating this form. (Spellpower, etc.)
212 * @return The duration of the form. (XXX: in turns...?)
213 */
get_duration(int pow) const214 int Form::get_duration(int pow) const
215 {
216 return min(duration.base + duration.power_bonus(pow), duration.max);
217 }
218
219 /**
220 * Get a verbose description for the form.
221 *
222 * @param past_tense Whether the description should be in past or present
223 * tense.
224 * @return A description for the form.
225 */
get_description(bool past_tense) const226 string Form::get_description(bool past_tense) const
227 {
228 return make_stringf("You %s %s",
229 past_tense ? "were" : "are",
230 get_transform_description().c_str());
231 }
232
233 /**
234 * Get a message for transforming into this form, based on your current
235 * situation (e.g. in water...)
236 *
237 * @return The message for turning into this form.
238 */
transform_message(transformation previous_trans) const239 string Form::transform_message(transformation previous_trans) const
240 {
241 // XXX: refactor this into a second function (and also rethink the logic)
242 string start = "Buggily, y";
243 if (you.in_water() && player_can_fly())
244 start = "You fly out of the water as y";
245 else if (get_form(previous_trans)->player_can_fly()
246 && player_can_swim()
247 && feat_is_water(env.grid(you.pos())))
248 start = "As you dive into the water, y";
249 else
250 start = "Y";
251
252 return make_stringf("%sou turn into %s", start.c_str(),
253 get_transform_description().c_str());
254 }
255
256 /**
257 * Get a message for untransforming from this form.
258 *
259 * @return "Your transform has ended."
260 */
get_untransform_message() const261 string Form::get_untransform_message() const
262 {
263 return "Your transformation has ended.";
264 }
265
266 /**
267 * What AC bonus does the player get while in this form?
268 *
269 * Many forms are power-dependent, so the answer given may be strange if the
270 * player isn't currently in the form in question.
271 *
272 * @return The AC bonus currently granted by the form, multiplied by 100 to
273 * allow for pseudo-decimal flexibility (& to match
274 * player::armour_class())
275 */
get_ac_bonus() const276 int Form::get_ac_bonus() const
277 {
278 return flat_ac * 100
279 + power_ac * you.props[TRANSFORM_POW_KEY].get_int()
280 + xl_ac * you.experience_level;
281 }
282
283 /**
284 * (freeze)
285 */
_brand_suffix(brand_type brand)286 static string _brand_suffix(brand_type brand)
287 {
288 if (brand == SPWPN_NORMAL)
289 return "";
290 return make_stringf(" (%s)", brand_type_name(brand, true));
291 }
292
293 /**
294 * What name should be used for the player's means of unarmed attack while
295 * in this form?
296 *
297 * (E.g. for display in the top-right of the UI.)
298 *
299 * @param The player's UC weapon when not in a form (claws, etc)
300 * @return A string describing the form's UC attack 'weapon'.
301 */
get_uc_attack_name(string default_name) const302 string Form::get_uc_attack_name(string default_name) const
303 {
304 const string brand_suffix = _brand_suffix(get_uc_brand());
305 if (uc_attack.empty())
306 return default_name + brand_suffix;
307 return uc_attack + brand_suffix;
308 }
309
310 /**
311 * How many levels of resistance against fire does this form provide?
312 */
res_fire() const313 int Form::res_fire() const
314 {
315 return get_resist(resists, MR_RES_FIRE);
316 }
317
318 /**
319 * How many levels of resistance against cold does this form provide?
320 */
res_cold() const321 int Form::res_cold() const
322 {
323 return get_resist(resists, MR_RES_COLD);
324 }
325
326 /**
327 * How many levels of resistance against negative energy does this form give?
328 */
res_neg() const329 int Form::res_neg() const
330 {
331 return get_resist(resists, MR_RES_NEG);
332 }
333
334 /**
335 * Does this form provide resistance to electricity?
336 */
res_elec() const337 bool Form::res_elec() const
338 {
339 return get_resist(resists, MR_RES_ELEC);
340 }
341
342 /**
343 * How many levels of resistance against poison does this form give?
344 */
res_pois() const345 int Form::res_pois() const
346 {
347 return get_resist(resists, MR_RES_POISON);
348 }
349
350 /**
351 * Does this form provide resistance to miasma?
352 */
res_miasma() const353 bool Form::res_miasma() const
354 {
355 return get_resist(resists, MR_RES_MIASMA);
356 }
357
358 /**
359 * Does this form provide resistance against acid?
360 */
res_acid() const361 bool Form::res_acid() const
362 {
363 return get_resist(resists, MR_RES_ACID);
364 }
365
366 /**
367 * Does this form provide resistance to sticky flame?
368 */
res_sticky_flame() const369 bool Form::res_sticky_flame() const
370 {
371 return get_resist(resists, MR_RES_STICKY_FLAME);
372 }
373
374 /**
375 * Does this form provide resistance to petrification?
376 */
res_petrify() const377 bool Form::res_petrify() const
378 {
379 return get_resist(resists, MR_RES_PETRIFY);
380 }
381
382
383 /**
384 * Does this form enable flight?
385 *
386 * @return Whether this form allows flight for characters which don't already
387 * have access to it.
388 */
enables_flight() const389 bool Form::enables_flight() const
390 {
391 return can_fly == FC_ENABLE;
392 }
393
394 /**
395 * Does this form disable flight?
396 *
397 * @return Whether flight is always impossible while in this form.
398 */
forbids_flight() const399 bool Form::forbids_flight() const
400 {
401 return can_fly == FC_FORBID;
402 }
403
404 /**
405 * Does this form disable swimming?
406 *
407 * @return Whether swimming is always impossible while in this form.
408 */
forbids_swimming() const409 bool Form::forbids_swimming() const
410 {
411 return can_swim == FC_FORBID;
412 }
413
414 /**
415 * Can the player fly, if in this form?
416 *
417 * DOES consider player state besides form.
418 * @return Whether the player will be able to fly in this form.
419 */
player_can_fly() const420 bool Form::player_can_fly() const
421 {
422 return !forbids_flight()
423 && (enables_flight()
424 || you.racial_permanent_flight()); // XX other cases??
425 }
426
427 /**
428 * Can the player swim, if in this form?
429 *
430 * DOES consider player state besides form.
431 * @return Whether the player will be able to swim in this form.
432 */
player_can_swim() const433 bool Form::player_can_swim() const
434 {
435 // XX this is kind of a mess w.r.t. player::can_swim
436 const size_type player_size = size == SIZE_CHARACTER ?
437 you.body_size(PSIZE_BODY, true) :
438 size;
439 return can_swim == FC_ENABLE
440 || species::can_swim(you.species)
441 && can_swim != FC_FORBID
442 || player_size >= SIZE_GIANT;
443 }
444
445 /**
446 * Are all of the given equipment slots blocked while in this form?
447 *
448 * @param slotflags A set of flags, corresponding to the union of
449 (1 << the slot enum) for each slot in question.
450 * @return Whether all of the given slots are blocked.
451 */
all_blocked(int slotflags) const452 bool Form::all_blocked(int slotflags) const
453 {
454 return slotflags == (blocked_slots & slotflags);
455 }
456
457 /**
458 * What message should be printed when the player prays at an altar?
459 * To be inserted into "You %s the altar of foo."
460 *
461 * If the form has a valid custom action, print that; otherwise, default to the
462 * 'flying' or species-specific actions, as appropriate.
463 *
464 * @return An action to be printed when the player prays at an altar.
465 * E.g., "perch on", "crawl onto", "sway towards", etc.
466 */
player_prayer_action() const467 string Form::player_prayer_action() const
468 {
469 // If the form is naturally flying & specifies an action, use that.
470 if (can_fly == FC_ENABLE && !prayer_action.empty())
471 return prayer_action;
472 // Otherwise, if you're flying, use the generic flying action.
473 // XXX: if we ever get a default-permaflying species again that wants to
474 // have a separate verb, we'll want to check for that right here.
475 if (you.airborne())
476 return "hover solemnly before";
477 // Otherwise, if you have a verb, use that...
478 if (!prayer_action.empty())
479 return prayer_action;
480 // Finally, default to your species' verb.
481 return species::prayer_action(you.species);
482 }
483
get_fakemuts(bool terse) const484 vector<string> Form::get_fakemuts(bool terse) const
485 {
486 vector<string> result;
487 for (const auto &p : fakemuts)
488 result.push_back(terse ? p.first : p.second);
489 return result;
490 }
491
492
493 class FormNone : public Form
494 {
495 private:
FormNone()496 FormNone() : Form(transformation::none) { }
497 DISALLOW_COPY_AND_ASSIGN(FormNone);
498 public:
instance()499 static const FormNone &instance() { static FormNone inst; return inst; }
500
501 /**
502 * Get a string describing the form you're turning into. (If not the same
503 * as the one used to describe this form in @.
504 */
get_transform_description() const505 string get_transform_description() const override { return "your old self."; }
506 };
507
508 class FormSpider : public Form
509 {
510 private:
FormSpider()511 FormSpider() : Form(transformation::spider) { }
512 DISALLOW_COPY_AND_ASSIGN(FormSpider);
513 public:
instance()514 static const FormSpider &instance() { static FormSpider inst; return inst; }
515 };
516
517 class FormBlade : public Form
518 {
519 private:
FormBlade()520 FormBlade() : Form(transformation::blade_hands) { }
521 DISALLOW_COPY_AND_ASSIGN(FormBlade);
522 public:
instance()523 static const FormBlade &instance() { static FormBlade inst; return inst; }
524
525 /**
526 * % screen description
527 */
get_long_name() const528 string get_long_name() const override
529 {
530 return you.base_hand_name(true, true);
531 }
532
533 /**
534 * @ description
535 */
get_description(bool past_tense) const536 string get_description(bool past_tense) const override
537 {
538 return make_stringf("You %s blades for %s.",
539 past_tense ? "had" : "have",
540 blade_parts().c_str());
541 }
542
543 /**
544 * Get a message for transforming into this form.
545 */
transform_message(transformation) const546 string transform_message(transformation /*previous_trans*/) const override
547 {
548 const bool singular = you.arm_count() == 1;
549
550 // XXX: a little ugly
551 return make_stringf("Your %s turn%s into%s razor-sharp scythe blade%s.",
552 blade_parts().c_str(), singular ? "s" : "",
553 singular ? " a" : "", singular ? "" : "s");
554 }
555
556 /**
557 * Get a message for untransforming from this form.
558 */
get_untransform_message() const559 string get_untransform_message() const override
560 {
561 const bool singular = you.arm_count() == 1;
562
563 // XXX: a little ugly
564 return make_stringf("Your %s revert%s to %s normal proportions.",
565 blade_parts().c_str(), singular ? "s" : "",
566 singular ? "its" : "their");
567 }
568
can_offhand_punch() const569 bool can_offhand_punch() const override { return true; }
570
571 /**
572 * Get the name displayed in the UI for the form's unarmed-combat 'weapon'.
573 */
get_uc_attack_name(string) const574 string get_uc_attack_name(string /*default_name*/) const override
575 {
576 return "Blade " + blade_parts(true);
577 }
578 };
579
580 class FormStatue : public Form
581 {
582 private:
FormStatue()583 FormStatue() : Form(transformation::statue) { }
584 DISALLOW_COPY_AND_ASSIGN(FormStatue);
585 public:
instance()586 static const FormStatue &instance() { static FormStatue inst; return inst; }
587
588 /**
589 * Get a message for transforming into this form.
590 */
transform_message(transformation previous_trans) const591 string transform_message(transformation previous_trans) const override
592 {
593 if (you.species == SP_DEEP_DWARF && one_chance_in(10))
594 return "You inwardly fear your resemblance to a lawn ornament.";
595 else if (you.species == SP_GARGOYLE)
596 return "Your body stiffens and grows slower.";
597 else
598 return Form::transform_message(previous_trans);
599 }
600
601 /**
602 * Get a string describing the form you're turning into. (If not the same
603 * as the one used to describe this form in @.
604 */
get_transform_description() const605 string get_transform_description() const override
606 {
607 return "a living statue of rough stone.";
608 }
609
610 /**
611 * Get a message for untransforming from this form.
612 */
get_untransform_message() const613 string get_untransform_message() const override
614 {
615 // This only handles lava orcs going statue -> stoneskin.
616 if (you.species == SP_GARGOYLE)
617 return "You revert to a slightly less stony form.";
618 return "You revert to your normal fleshy form.";
619 }
620
621 /**
622 * Get the name displayed in the UI for the form's unarmed-combat 'weapon'.
623 */
get_uc_attack_name(string) const624 string get_uc_attack_name(string /*default_name*/) const override
625 {
626 // there's special casing in base_hand_name to get "fists"
627 string hand = you.base_hand_name(true, true);
628 return make_stringf("Stone %s", hand.c_str());
629 }
630 };
631
632 class FormIce : public Form
633 {
634 private:
FormIce()635 FormIce() : Form(transformation::ice_beast) { }
636 DISALLOW_COPY_AND_ASSIGN(FormIce);
637 public:
instance()638 static const FormIce &instance() { static FormIce inst; return inst; }
639
640 /**
641 * Get a message for untransforming from this form.
642 */
get_untransform_message() const643 string get_untransform_message() const override
644 {
645 return "You warm up again.";
646 }
647
648 /**
649 * Get the name displayed in the UI for the form's unarmed-combat 'weapon'.
650 */
get_uc_attack_name(string) const651 string get_uc_attack_name(string /*default_name*/) const override
652 {
653 const bool singular = you.get_mutation_level(MUT_MISSING_HAND);
654 // paws for consistency with form-data and the tile
655 // XX does this imply the behavior of feline paws?
656 return make_stringf("Ice paw%s", singular ? "" : "s");
657 }
658 };
659
660 class FormDragon : public Form
661 {
662 private:
FormDragon()663 FormDragon() : Form(transformation::dragon) { }
664 DISALLOW_COPY_AND_ASSIGN(FormDragon);
665 public:
instance()666 static const FormDragon &instance() { static FormDragon inst; return inst; }
667
668 /**
669 * Get an monster type corresponding to the transformation.
670 *
671 * (Used for console player glyphs.)
672 *
673 * @return A monster type corresponding to the player in this form.
674 */
get_equivalent_mons() const675 monster_type get_equivalent_mons() const override
676 {
677 return species::dragon_form(you.species);
678 }
679
get_transform_description() const680 string get_transform_description() const override
681 {
682 if (species::is_draconian(you.species))
683 {
684 return make_stringf("a fearsome %s!",
685 mons_class_name(get_equivalent_mons()));
686 }
687 else
688 return description;
689 }
690
691 /**
692 * The AC bonus of the form, multiplied by 100 to match
693 * player::armour_class().
694 */
get_ac_bonus() const695 int get_ac_bonus() const override
696 {
697 if (species::is_draconian(you.species))
698 return 1000;
699 return Form::get_ac_bonus();
700 }
701
702 /**
703 * How many levels of resistance against fire does this form provide?
704 */
res_fire() const705 int res_fire() const override
706 {
707 switch (species::dragon_form(you.species))
708 {
709 case MONS_FIRE_DRAGON:
710 return 2;
711 case MONS_ICE_DRAGON:
712 return -1;
713 default:
714 return 0;
715 }
716 }
717
718 /**
719 * How many levels of resistance against cold does this form provide?
720 */
res_cold() const721 int res_cold() const override
722 {
723 switch (species::dragon_form(you.species))
724 {
725 case MONS_ICE_DRAGON:
726 return 2;
727 case MONS_FIRE_DRAGON:
728 return -1;
729 default:
730 return 0;
731 }
732 }
733
can_offhand_punch() const734 bool can_offhand_punch() const override { return true; }
735 };
736
737 class FormLich : public Form
738 {
739 private:
FormLich()740 FormLich() : Form(transformation::lich) { }
741 DISALLOW_COPY_AND_ASSIGN(FormLich);
742 public:
instance()743 static const FormLich &instance() { static FormLich inst; return inst; }
744
745 /**
746 * Get a message for transforming into this form.
747 */
transform_message(transformation) const748 string transform_message(transformation /*previous_trans*/) const override
749 {
750 return "Your body is suffused with negative energy!";
751 }
752
753 /**
754 * Get a message for untransforming from this form.
755 */
get_untransform_message() const756 string get_untransform_message() const override
757 {
758 if (you.undead_state() == US_ALIVE)
759 return "You feel yourself come back to life.";
760 return "You feel your undeath return to normal.";
761 // ^^^ vampires only, probably
762 }
763 };
764
765 class FormBat : public Form
766 {
767 private:
FormBat()768 FormBat() : Form(transformation::bat) { }
769 DISALLOW_COPY_AND_ASSIGN(FormBat);
770 public:
instance()771 static const FormBat &instance() { static FormBat inst; return inst; }
772
773 /**
774 * Get an monster type corresponding to the transformation.
775 *
776 * (Used for console player glyphs.)
777 *
778 * @return A monster type corresponding to the player in this form.
779 */
get_equivalent_mons() const780 monster_type get_equivalent_mons() const override
781 {
782 return you.has_mutation(MUT_VAMPIRISM) ? MONS_VAMPIRE_BAT : MONS_BAT;
783 }
784
785 /**
786 * Get a string describing the form you're turning into. (If not the same
787 * as the one used to describe this form in @.
788 */
get_transform_description() const789 string get_transform_description() const override
790 {
791 return make_stringf("a %sbat.",
792 you.has_mutation(MUT_VAMPIRISM) ? "vampire " : "");
793 }
794 };
795
796 class FormPig : public Form
797 {
798 private:
FormPig()799 FormPig() : Form(transformation::pig) { }
800 DISALLOW_COPY_AND_ASSIGN(FormPig);
801 public:
instance()802 static const FormPig &instance() { static FormPig inst; return inst; }
803 };
804
805 class FormAppendage : public Form
806 {
807 private:
FormAppendage()808 FormAppendage() : Form(transformation::appendage) { }
809 DISALLOW_COPY_AND_ASSIGN(FormAppendage);
810 public:
instance()811 static const FormAppendage &instance()
812 {
813 static FormAppendage inst;
814 return inst;
815 }
816
get_description(bool past_tense) const817 string get_description(bool past_tense) const override
818 {
819 ostringstream desc;
820 bool spike = false;
821 vector<string> muts;
822 for (auto app : you.props[APPENDAGE_KEY].get_vector())
823 {
824 mutation_type mut = static_cast<mutation_type>(app.get_int());
825 if (mut == MUT_TENTACLE_SPIKE)
826 spike = true;
827 else
828 muts.push_back(mutation_name(mut));
829 }
830
831 if (spike)
832 {
833 string tense = past_tense ? "had" : "has";
834 desc << "One of your tentacles " << tense;
835 desc << " grown a beastly spike";
836 if (muts.empty())
837 desc << ".";
838 else
839 desc << ", and you ";
840 }
841 else if (!muts.empty())
842 desc << "You ";
843
844 if (!muts.empty())
845 {
846 string tense = past_tense ? "had" : "have";
847 desc << tense << " temporarily grown beastly ";
848 desc << comma_separated_line(muts.begin(), muts.end()) << ".";
849 }
850
851 return trimmed_string(desc.str());
852 }
853
854 /**
855 * Get a message for transforming into this form.
856 */
transform_message(transformation) const857 string transform_message(transformation /*previous_trans*/) const override
858 {
859 ostringstream msg;
860 for (auto app : you.props[APPENDAGE_KEY].get_vector())
861 {
862 mutation_type mut = static_cast<mutation_type>(app.get_int());
863 switch (mut)
864 {
865 case MUT_HORNS:
866 msg << "You grow a pair of large bovine horns. ";
867 break;
868 case MUT_TENTACLE_SPIKE:
869 msg << "One of your tentacles grows a vicious spike. ";
870 break;
871 case MUT_TALONS:
872 msg << "Your feet morph into talons. ";
873 break;
874 default:
875 die("Unknown appendage type");
876 break;
877 }
878 }
879
880 return trimmed_string(msg.str());
881 }
882
883 /**
884 * Get a message for untransforming from this form. (Handled elsewhere.)
885 */
get_untransform_message() const886 string get_untransform_message() const override { return ""; }
887 };
888
889 class FormTree : public Form
890 {
891 private:
FormTree()892 FormTree() : Form(transformation::tree) { }
893 DISALLOW_COPY_AND_ASSIGN(FormTree);
894 public:
instance()895 static const FormTree &instance() { static FormTree inst; return inst; }
896
897 /**
898 * Get a message for untransforming from this form.
899 */
get_untransform_message() const900 string get_untransform_message() const override { return "You feel less wooden."; }
901 };
902
903 #if TAG_MAJOR_VERSION == 34
904 class FormPorcupine : public Form
905 {
906 private:
FormPorcupine()907 FormPorcupine() : Form(transformation::porcupine) { }
908 DISALLOW_COPY_AND_ASSIGN(FormPorcupine);
909 public:
instance()910 static const FormPorcupine &instance()
911 {
912 static FormPorcupine inst;
913 return inst;
914 }
915 };
916 #endif
917
918 class FormWisp : public Form
919 {
920 private:
FormWisp()921 FormWisp() : Form(transformation::wisp) { }
922 DISALLOW_COPY_AND_ASSIGN(FormWisp);
923 public:
instance()924 static const FormWisp &instance() { static FormWisp inst; return inst; }
925 };
926
927 #if TAG_MAJOR_VERSION == 34
928 class FormJelly : public Form
929 {
930 private:
FormJelly()931 FormJelly() : Form(transformation::jelly) { }
932 DISALLOW_COPY_AND_ASSIGN(FormJelly);
933 public:
instance()934 static const FormJelly &instance() { static FormJelly inst; return inst; }
935 };
936 #endif
937
938 class FormFungus : public Form
939 {
940 private:
FormFungus()941 FormFungus() : Form(transformation::fungus) { }
942 DISALLOW_COPY_AND_ASSIGN(FormFungus);
943 public:
instance()944 static const FormFungus &instance() { static FormFungus inst; return inst; }
945
946 /**
947 * Get a message for untransforming from this form.
948 */
get_untransform_message() const949 string get_untransform_message() const override { return "You stop sporulating."; }
950 };
951
952 class FormShadow : public Form
953 {
954 private:
FormShadow()955 FormShadow() : Form(transformation::shadow) { }
956 DISALLOW_COPY_AND_ASSIGN(FormShadow);
957 public:
instance()958 static const FormShadow &instance() { static FormShadow inst; return inst; }
959
960 /**
961 * Get a message for untransforming from this form.
962 */
get_untransform_message() const963 string get_untransform_message() const override
964 {
965 if (you.invisible())
966 return "You feel less shadowy.";
967 return "You emerge from the shadows.";
968 }
969 };
970
set_airform_power(int pow)971 void set_airform_power(int pow)
972 {
973 you.props[AIRFORM_POWER_KEY] = pow;
974 }
975
976 class FormStorm : public Form
977 {
978 private:
FormStorm()979 FormStorm() : Form(transformation::storm) { }
980 DISALLOW_COPY_AND_ASSIGN(FormStorm);
981 public:
instance()982 static const FormStorm &instance() { static FormStorm inst; return inst; }
983
984 /**
985 * Find the player's base unarmed damage in this form.
986 */
get_base_unarmed_damage() const987 int get_base_unarmed_damage() const override
988 {
989 int power = 0;
990 if (you.props.exists(AIRFORM_POWER_KEY))
991 power = you.props[AIRFORM_POWER_KEY].get_int();
992 return 2 + div_rand_round(power * 2, 5);
993 }
994
can_offhand_punch() const995 bool can_offhand_punch() const override { return true; }
996 };
997
998 #if TAG_MAJOR_VERSION == 34
999
1000 /**
1001 * Set the number of hydra heads that the player currently has.
1002 *
1003 * @param heads the new number of heads you should have.
1004 */
set_hydra_form_heads(int heads)1005 void set_hydra_form_heads(int heads)
1006 {
1007 you.props[HYDRA_FORM_HEADS_KEY] = min(MAX_HYDRA_HEADS, max(1, heads));
1008 you.wield_change = true;
1009 }
1010
1011 class FormHydra : public Form
1012 {
1013 private:
FormHydra()1014 FormHydra() : Form(transformation::hydra) { }
1015 DISALLOW_COPY_AND_ASSIGN(FormHydra);
1016 public:
instance()1017 static const FormHydra &instance() { static FormHydra inst; return inst; }
1018
1019 /**
1020 * Get a string describing the form you're turning into.
1021 */
get_transform_description() const1022 string get_transform_description() const override
1023 {
1024 const auto heads = you.heads();
1025 const string headstr = (heads < 11 ? number_in_words(heads)
1026 : to_string(heads))
1027 + "-headed hydra.";
1028 return article_a(headstr);
1029 }
1030
1031 /**
1032 * @ description
1033 */
get_description(bool past_tense) const1034 string get_description(bool past_tense) const override
1035 {
1036 return make_stringf("You %s %s",
1037 past_tense ? "were" : "are",
1038 get_transform_description().c_str());
1039 }
1040
1041 /**
1042 * Get the name displayed in the UI for the form's unarmed-combat 'weapon'.
1043 */
get_uc_attack_name(string) const1044 string get_uc_attack_name(string /*default_name*/) const override
1045 {
1046 return make_stringf("Bite (x%d)", you.heads());
1047 }
1048
1049 /**
1050 * Find the player's base unarmed damage in this form.
1051 */
get_base_unarmed_damage() const1052 int get_base_unarmed_damage() const override
1053 {
1054 // 3 damage per head for 1-10
1055 const int normal_heads_damage = min(you.heads(), 10) * 3;
1056 // 3/2 damage per head for 11-20 (they get in each-other's way)
1057 // (and also a 62-base-damage form scares me)
1058 const int too_many_heads_damage = max(0, you.heads() - 10)
1059 * 3 / 2;
1060 // 2-47 (though more like 14-32 in practical ranges...)
1061 return 2 + normal_heads_damage + too_many_heads_damage;
1062 }
1063
1064 };
1065 #endif
1066
1067 static const Form* forms[] =
1068 {
1069 &FormNone::instance(),
1070 &FormSpider::instance(),
1071 &FormBlade::instance(),
1072 &FormStatue::instance(),
1073
1074 &FormIce::instance(),
1075 &FormDragon::instance(),
1076 &FormLich::instance(),
1077 &FormBat::instance(),
1078
1079 &FormPig::instance(),
1080 &FormAppendage::instance(),
1081 &FormTree::instance(),
1082 #if TAG_MAJOR_VERSION == 34
1083 &FormPorcupine::instance(),
1084 #endif
1085
1086 &FormWisp::instance(),
1087 #if TAG_MAJOR_VERSION == 34
1088 &FormJelly::instance(),
1089 #endif
1090 &FormFungus::instance(),
1091 &FormShadow::instance(),
1092 #if TAG_MAJOR_VERSION == 34
1093 &FormHydra::instance(),
1094 #endif
1095 &FormStorm::instance(),
1096 };
1097
get_form(transformation xform)1098 const Form* get_form(transformation xform)
1099 {
1100 COMPILE_CHECK(ARRAYSZ(forms) == NUM_TRANSFORMS);
1101 const int form = static_cast<int>(xform);
1102 ASSERT_RANGE(form, 0, NUM_TRANSFORMS);
1103 return forms[form];
1104 }
1105
1106
1107 /**
1108 * Get the wizmode name of a form.
1109 *
1110 * @param form The form in question.
1111 * @return The form's casual, wizmode name.
1112 */
transform_name(transformation form)1113 const char* transform_name(transformation form)
1114 {
1115 return get_form(form)->wiz_name.c_str();
1116 }
1117
1118 /**
1119 * Can the player (w)ield weapons when in the given form?
1120 *
1121 * @param form The form in question.
1122 * @return Whether the player can wield items when in that form.
1123 */
form_can_wield(transformation form)1124 bool form_can_wield(transformation form)
1125 {
1126 return get_form(form)->can_wield();
1127 }
1128
1129 /**
1130 * Can the player (W)ear armour when in the given form?
1131 *
1132 * @param form The form in question.
1133 * @return Whether the player can wear armour when in that form.
1134 */
form_can_wear(transformation form)1135 bool form_can_wear(transformation form)
1136 {
1137 return !testbits(get_form(form)->blocked_slots, EQF_WEAR);
1138 }
1139
1140 /**
1141 * Can the player fly, if in this form?
1142 *
1143 * DOES consider player state besides form.
1144 * @param form The form in question.
1145 * @return Whether the player will be able to fly in this form.
1146 */
form_can_fly(transformation form)1147 bool form_can_fly(transformation form)
1148 {
1149 return get_form(form)->player_can_fly();
1150 }
1151
1152
1153 /**
1154 * Can the player swim, if in this form?
1155 *
1156 * (Swimming = traversing deep & shallow water without penalties; includes
1157 * floating (ice form) and wading forms (giants - currently just dragon form,
1158 * which normally flies anyway...))
1159 *
1160 * DOES consider player state besides form.
1161 * @param form The form in question.
1162 * @return Whether the player will be able to swim in this form.
1163 */
form_can_swim(transformation form)1164 bool form_can_swim(transformation form)
1165 {
1166 return get_form(form)->player_can_swim();
1167 }
1168
1169 /**
1170 * Can the player survive in deep water when in the given form?
1171 *
1172 * Doesn't count flight or beogh water-walking.
1173 *
1174 * @param form The form in question.
1175 * @return Whether the player won't be killed when entering deep water
1176 * in that form.
1177 */
form_likes_water(transformation form)1178 bool form_likes_water(transformation form)
1179 {
1180 // Grey dracs can't swim, so can't statue form merfolk/octopodes
1181 // -- yet they can still survive in water.
1182 if (species::likes_water(you.species)
1183 && (form == transformation::statue
1184 || !get_form(form)->forbids_swimming()))
1185 {
1186 return true;
1187 }
1188
1189 // otherwise, you gotta swim to survive!
1190 return form_can_swim(form);
1191 }
1192
1193 // Used to mark transformations which override species intrinsics.
form_changed_physiology(transformation form)1194 bool form_changed_physiology(transformation form)
1195 {
1196 return form != transformation::none
1197 && form != transformation::appendage
1198 && form != transformation::blade_hands;
1199 }
1200
1201 /**
1202 * Does this form have blood?
1203 *
1204 * @param form The form in question.
1205 * @return Whether the form can bleed, sublime, etc.
1206 */
form_can_bleed(transformation form)1207 bool form_can_bleed(transformation form)
1208 {
1209 return get_form(form)->can_bleed != FC_FORBID;
1210 }
1211
1212 // Used to mark forms which keep most form-based mutations.
form_keeps_mutations(transformation form)1213 bool form_keeps_mutations(transformation form)
1214 {
1215 return get_form(form)->keeps_mutations;
1216 }
1217
1218 static set<equipment_type>
_init_equipment_removal(transformation form)1219 _init_equipment_removal(transformation form)
1220 {
1221 set<equipment_type> result;
1222 if (!form_can_wield(form) && you.weapon() || you.melded[EQ_WEAPON])
1223 result.insert(EQ_WEAPON);
1224
1225 // Liches can't wield holy weapons.
1226 if (form == transformation::lich && you.weapon()
1227 && is_holy_item(*you.weapon()))
1228 {
1229 result.insert(EQ_WEAPON);
1230 }
1231
1232 for (int i = EQ_FIRST_EQUIP; i < NUM_EQUIP; ++i)
1233 {
1234 if (i == EQ_WEAPON)
1235 continue;
1236 const equipment_type eq = static_cast<equipment_type>(i);
1237 const item_def *pitem = you.slot_item(eq, true);
1238
1239 if (pitem && (get_form(form)->blocked_slots & SLOTF(i)
1240 || (i != EQ_RING_AMULET
1241 && !get_form(form)->can_wear_item(*pitem))))
1242 {
1243 result.insert(eq);
1244 }
1245 }
1246 return result;
1247 }
1248
_remove_equipment(const set<equipment_type> & removed,transformation form,bool meld=true,bool mutation=false)1249 static void _remove_equipment(const set<equipment_type>& removed,
1250 transformation form,
1251 bool meld = true, bool mutation = false)
1252 {
1253 // Meld items into you in (reverse) order. (set is a sorted container)
1254 for (const equipment_type e : removed)
1255 {
1256 item_def *equip = you.slot_item(e, true);
1257 if (equip == nullptr)
1258 continue;
1259
1260 bool unequip = !meld;
1261 if (!unequip && e == EQ_WEAPON)
1262 {
1263 if (form_can_wield(form))
1264 unequip = true;
1265 if (!is_weapon(*equip))
1266 unequip = true;
1267 }
1268
1269 const string msg = make_stringf("%s %s%s %s",
1270 equip->name(DESC_YOUR).c_str(),
1271 unequip ? "fall" : "meld",
1272 equip->quantity > 1 ? "" : "s",
1273 unequip ? "away" : "into your body.");
1274
1275 if (you_worship(GOD_ASHENZARI) && unequip && equip->cursed())
1276 mprf(MSGCH_GOD, "%s, shattering the curse!", msg.c_str());
1277 else if (unequip)
1278 mprf("%s!", msg.c_str());
1279 else
1280 mpr(msg);
1281
1282 if (unequip)
1283 {
1284 if (e == EQ_WEAPON)
1285 {
1286 unwield_item(!you.berserk());
1287 canned_msg(MSG_EMPTY_HANDED_NOW);
1288 }
1289 else
1290 unequip_item(e);
1291
1292 if (mutation)
1293 {
1294 // A mutation made us not only lose an equipment slot
1295 // but actually removed a worn item: Funny!
1296 xom_is_stimulated(is_artefact(*equip) ? 200 : 100);
1297 }
1298 }
1299 else
1300 meld_slot(e);
1301 }
1302
1303 if (meld)
1304 {
1305 for (const equipment_type e : removed)
1306 if (you.slot_item(e, true) != nullptr)
1307 unequip_effect(e, you.equip[e], true, true);
1308 }
1309 }
1310
_unmeld_equipment_type(equipment_type e)1311 static void _unmeld_equipment_type(equipment_type e)
1312 {
1313 item_def& item = you.inv[you.equip[e]];
1314 bool force_remove = false;
1315
1316 if (e == EQ_WEAPON)
1317 {
1318 if (you.slot_item(EQ_SHIELD)
1319 && is_shield_incompatible(item, you.slot_item(EQ_SHIELD)))
1320 {
1321 force_remove = true;
1322 }
1323 }
1324 else if (item.base_type != OBJ_JEWELLERY)
1325 {
1326 // This could happen if the player was mutated during the form.
1327 if (!can_wear_armour(item, false, true))
1328 force_remove = true;
1329
1330 // If you switched weapons during the transformation, make
1331 // sure you can still wear your shield.
1332 // (This is only possible with Statue Form.)
1333 if (e == EQ_SHIELD && you.weapon()
1334 && is_shield_incompatible(*you.weapon(), &item))
1335 {
1336 force_remove = true;
1337 }
1338 }
1339
1340 if (force_remove)
1341 {
1342 mprf("%s is pushed off your body!", item.name(DESC_YOUR).c_str());
1343 unequip_item(e);
1344 }
1345 else
1346 {
1347 mprf("%s unmelds from your body.", item.name(DESC_YOUR).c_str());
1348 unmeld_slot(e);
1349 }
1350 }
1351
_unmeld_equipment(const set<equipment_type> & melded)1352 static void _unmeld_equipment(const set<equipment_type>& melded)
1353 {
1354 // Unmeld items in order.
1355 for (const equipment_type e : melded)
1356 {
1357 if (you.equip[e] == -1)
1358 continue;
1359
1360 _unmeld_equipment_type(e);
1361 }
1362
1363 for (const equipment_type e : melded)
1364 if (you.equip[e] != -1)
1365 equip_effect(e, you.equip[e], true, true);
1366 }
1367
_lears_takes_slot(equipment_type eq)1368 static bool _lears_takes_slot(equipment_type eq)
1369 {
1370 return eq >= EQ_HELMET && eq <= EQ_BOOTS
1371 || eq == EQ_BODY_ARMOUR;
1372 }
1373
_form_melds_lears(transformation which_trans)1374 static bool _form_melds_lears(transformation which_trans)
1375 {
1376 for (equipment_type eq : _init_equipment_removal(which_trans))
1377 if (_lears_takes_slot(eq))
1378 return true;
1379 return false;
1380 }
1381
unmeld_one_equip(equipment_type eq)1382 void unmeld_one_equip(equipment_type eq)
1383 {
1384 if (_lears_takes_slot(eq))
1385 {
1386 const item_def* arm = you.slot_item(EQ_BODY_ARMOUR, true);
1387 if (arm && is_unrandom_artefact(*arm, UNRAND_LEAR))
1388 {
1389 // Don't unmeld lears when de-fishtailing if you're in
1390 // a form that should keep it melded.
1391 if (_form_melds_lears(you.form))
1392 return;
1393 eq = EQ_BODY_ARMOUR;
1394 }
1395 }
1396
1397 set<equipment_type> e;
1398 e.insert(eq);
1399 _unmeld_equipment(e);
1400 }
1401
remove_one_equip(equipment_type eq,bool meld,bool mutation)1402 void remove_one_equip(equipment_type eq, bool meld, bool mutation)
1403 {
1404 if (player_equip_unrand(UNRAND_LEAR) && _lears_takes_slot(eq))
1405 eq = EQ_BODY_ARMOUR;
1406
1407 set<equipment_type> r;
1408 r.insert(eq);
1409 _remove_equipment(r, you.form, meld, mutation);
1410 }
1411
1412 /**
1413 * Get an monster type corresponding to the player's current form.
1414 *
1415 * (Used for console player glyphs.)
1416 *
1417 * @return A monster type corresponding to the player in the form.
1418 */
transform_mons()1419 monster_type transform_mons()
1420 {
1421 return get_form()->get_equivalent_mons();
1422 }
1423
1424 /**
1425 * What is the name of the player parts that will become blades?
1426 */
blade_parts(bool terse)1427 string blade_parts(bool terse)
1428 {
1429 // there's special casing in base_hand_name to use "blade" everywhere, so
1430 // use the non-temp name
1431 string str = you.base_hand_name(true, false);
1432
1433 // creatures with paws (aka felids) have four paws, but only two of them
1434 // turn into blades.
1435 if (!terse && you.has_mutation(MUT_PAWS, false))
1436 str = "front " + str;
1437 else if (!terse && you.arm_count() > 2)
1438 str = "main " + str; // Op have four main tentacles
1439
1440 return str;
1441 }
1442
1443 // with a denominator of 10
form_hp_mod()1444 int form_hp_mod()
1445 {
1446 return get_form()->hp_mod;
1447 }
1448
_flying_in_new_form(transformation which_trans)1449 static bool _flying_in_new_form(transformation which_trans)
1450 {
1451 if (get_form(which_trans)->forbids_flight())
1452 return false;
1453
1454 // sources of permanent flight besides equipment
1455 if (you.permanent_flight(false))
1456 return true;
1457
1458 // not airborne right now (XX does this handle emergency flight correctly?)
1459 if (!you.duration[DUR_FLIGHT] && !you.attribute[ATTR_PERM_FLIGHT])
1460 return false;
1461
1462 // Finally, do the calculation about what would be melded: are there equip
1463 // sources left?
1464 int sources = you.equip_flight();
1465 int sources_removed = 0;
1466 for (auto eq : _init_equipment_removal(which_trans))
1467 {
1468 item_def *item = you.slot_item(eq, true);
1469 if (item == nullptr)
1470 continue;
1471 item_def inf = get_item_known_info(*item);
1472
1473 //similar code to safe_to_remove from item-use.cc
1474 if (inf.is_type(OBJ_JEWELLERY, RING_FLIGHT))
1475 sources_removed++;
1476 if (inf.base_type == OBJ_ARMOUR && inf.brand == SPARM_FLYING)
1477 sources_removed++;
1478 if (is_artefact(inf) && artefact_known_property(inf, ARTP_FLY))
1479 sources_removed++;
1480 }
1481
1482 return sources > sources_removed;
1483 }
1484
1485 /**
1486 * Check if it'd be lethal for the player to enter a form in a given terrain.
1487 *
1488 * In addition to checking whether the feature is dangerous for the form
1489 * itself (form_likes_*), the function checks to see if the player is safe
1490 * due to flying or similar effects.
1491 *
1492 * @param which_trans The form being checked.
1493 * @param feat The dungeon feature to be checked for danger.
1494 * @return If the feat is lethal for the player in the form.
1495 */
feat_dangerous_for_form(transformation which_trans,dungeon_feature_type feat)1496 bool feat_dangerous_for_form(transformation which_trans,
1497 dungeon_feature_type feat)
1498 {
1499 // Everything is okay if we can fly.
1500 if (form_can_fly(which_trans) || _flying_in_new_form(which_trans))
1501 return false;
1502
1503 if (feat == DNGN_LAVA)
1504 return true;
1505
1506 if (feat == DNGN_DEEP_WATER)
1507 return !you.can_water_walk() && !form_likes_water(which_trans);
1508
1509 return false;
1510 }
1511
1512 static mutation_type appendages[] =
1513 {
1514 MUT_HORNS,
1515 MUT_TENTACLE_SPIKE,
1516 MUT_TALONS,
1517 };
1518
_beastly_level(mutation_type mut)1519 static int _beastly_level(mutation_type mut)
1520 {
1521 switch (mut)
1522 {
1523 case MUT_TENTACLE_SPIKE:
1524 return 3;
1525 default:
1526 return 2;
1527 }
1528 }
1529
_transformation_is_safe(transformation which_trans,dungeon_feature_type feat,string * fail_reason)1530 static bool _transformation_is_safe(transformation which_trans,
1531 dungeon_feature_type feat,
1532 string *fail_reason)
1533 {
1534 if (!feat_dangerous_for_form(which_trans, feat) || you.duration[DUR_FLIGHT])
1535 return true;
1536
1537 if (fail_reason)
1538 {
1539 *fail_reason = make_stringf("You would %s in your new form.",
1540 feat == DNGN_DEEP_WATER ? "drown" : "burn");
1541 }
1542
1543 return false;
1544 }
1545
1546 /**
1547 * If we transform into the given form, will all of our stats remain above 0,
1548 * based purely on the stat modifiers of the current & destination form?
1549 *
1550 * May prompt the player.
1551 *
1552 * @param new_form The form to check the safety of.
1553 * @param quiet Whether to prompt the player.
1554 * @return Whether it's okay to go ahead with the transformation.
1555 */
check_form_stat_safety(transformation new_form,bool quiet)1556 bool check_form_stat_safety(transformation new_form, bool quiet)
1557 {
1558 const int str_mod = get_form(new_form)->str_mod - get_form()->str_mod;
1559 const int dex_mod = get_form(new_form)->dex_mod - get_form()->dex_mod;
1560
1561 const bool bad_str = you.strength() > 0 && str_mod + you.strength() <= 0;
1562 const bool bad_dex = you.dex() > 0 && dex_mod + you.dex() <= 0;
1563 if (!bad_str && !bad_dex)
1564 return true;
1565 if (quiet)
1566 return false;
1567
1568 string prompt = make_stringf("%s will reduce your %s to zero. Continue?",
1569 new_form == transformation::none
1570 ? "Turning back"
1571 : "Transforming",
1572 bad_str ? "strength" : "dexterity");
1573 if (yesno(prompt.c_str(), false, 'n'))
1574 return true;
1575
1576 canned_msg(MSG_OK);
1577 return false;
1578 }
1579
_transform_duration(transformation which_trans,int pow)1580 static int _transform_duration(transformation which_trans, int pow)
1581 {
1582 return get_form(which_trans)->get_duration(pow);
1583 }
1584
1585 /**
1586 * Is the player alive enough to become the given form?
1587 *
1588 * All undead can enter shadow form; vampires also can enter batform, and, when
1589 * full, other forms (excepting lichform).
1590 *
1591 * @param which_trans The tranformation which the player is undergoing
1592 * (default you.form).
1593 * @param involuntary Whether the transformation is involuntary or not.
1594 * @return UFR_GOOD if the player is not blocked from entering the
1595 * given form by their undead race; UFR_TOO_ALIVE if the
1596 * player is too satiated as a vampire; UFR_TOO_DEAD if
1597 * the player is too dead (or too thirsty as a vampire).
1598 */
lifeless_prevents_form(transformation which_trans,bool involuntary)1599 undead_form_reason lifeless_prevents_form(transformation which_trans,
1600 bool involuntary)
1601 {
1602 if (!you.undead_state(false))
1603 return UFR_GOOD; // not undead!
1604
1605 if (which_trans == transformation::none)
1606 return UFR_GOOD; // everything can become itself
1607
1608 if (which_trans == transformation::shadow)
1609 return UFR_GOOD; // even the undead can use dith's shadow form
1610
1611 if (!you.has_mutation(MUT_VAMPIRISM))
1612 return UFR_TOO_DEAD; // ghouls & mummies can't become anything else
1613
1614 if (which_trans == transformation::lich)
1615 return UFR_TOO_DEAD; // vampires can never lichform
1616
1617 if (which_trans == transformation::bat) // can batform bloodless
1618 {
1619 if (involuntary)
1620 return UFR_TOO_DEAD; // but not as a forced polymorph effect
1621
1622 return !you.vampire_alive ? UFR_GOOD : UFR_TOO_ALIVE;
1623 }
1624
1625 // other forms can only be entered when alive
1626 return you.vampire_alive ? UFR_GOOD : UFR_TOO_DEAD;
1627 }
1628
1629 /**
1630 * Attempts to transform the player into the specified form.
1631 *
1632 * If the player is already in that form, attempt to refresh its duration and
1633 * power.
1634 *
1635 * @param pow Thw power of the transformation (equivalent to
1636 * spellpower of form spells)
1637 * @param which_trans The form which the player should become.
1638 * @param involuntary Checks for inscription warnings are skipped, and
1639 * failure is silent.
1640 * @param just_check A dry run; just check to see whether the player
1641 * *can* enter the given form, but don't actually
1642 * transform them.
1643 * @return If the player was transformed, or if they were
1644 * already in the given form, returns true.
1645 * Otherwise, false.
1646 * If just_check is set, returns true if the player
1647 * could enter the form (or is in it already) and
1648 * false otherwise.
1649 * N.b. that transform() can fail even when a
1650 * just_check run returns true; e.g. when Zin decides
1651 * to intervene. (That may be the only case.)
1652 */
transform(int pow,transformation which_trans,bool involuntary,bool just_check,string * fail_reason)1653 bool transform(int pow, transformation which_trans, bool involuntary,
1654 bool just_check, string *fail_reason)
1655 {
1656 const transformation previous_trans = you.form;
1657 const bool was_flying = you.airborne();
1658 bool success = true;
1659 string msg;
1660
1661 // Zin's protection.
1662 if (!just_check && have_passive(passive_t::resist_polymorph)
1663 && x_chance_in_y(you.piety, MAX_PIETY)
1664 && which_trans != transformation::none)
1665 {
1666 simple_god_message(" protects your body from unnatural transformation!");
1667 return false;
1668 }
1669
1670 if (!involuntary && crawl_state.is_god_acting())
1671 involuntary = true;
1672
1673 if (you.transform_uncancellable)
1674 {
1675 msg = "You are stuck in your current form!";
1676 success = false;
1677 }
1678 else if (!_transformation_is_safe(which_trans, env.grid(you.pos()), &msg))
1679 success = false;
1680
1681 if (!success)
1682 {
1683 // Message is not printed if we're updating fail_reason.
1684 if (fail_reason)
1685 *fail_reason = msg;
1686 else if (!involuntary)
1687 mpr(msg);
1688 return false;
1689 }
1690
1691 // This must occur before the untransform() and the undead_state() check.
1692 if (previous_trans == which_trans)
1693 {
1694 if (just_check)
1695 return true;
1696
1697 // update power
1698 if (which_trans != transformation::none)
1699 {
1700 you.props[TRANSFORM_POW_KEY] = pow;
1701 you.redraw_armour_class = true;
1702 // ^ could check more carefully for the exact cases, but I'm
1703 // worried about making the code too fragile
1704 }
1705
1706 int dur = _transform_duration(which_trans, pow);
1707 if (you.duration[DUR_TRANSFORMATION] < dur * BASELINE_DELAY)
1708 {
1709 mpr("You extend your transformation's duration.");
1710 you.duration[DUR_TRANSFORMATION] = dur * BASELINE_DELAY;
1711
1712 }
1713 else if (!involuntary && which_trans != transformation::none)
1714 mpr("You fail to extend your transformation any further.");
1715
1716 return true;
1717 }
1718
1719 // the undead cannot enter most forms.
1720 if (lifeless_prevents_form(which_trans, involuntary) == UFR_TOO_DEAD)
1721 {
1722 msg = "Your unliving flesh cannot be transformed in this way.";
1723 success = false;
1724 }
1725 else if (which_trans == transformation::lich
1726 && you.duration[DUR_DEATHS_DOOR])
1727 {
1728 msg = "You cannot become a lich while in death's door.";
1729 success = false;
1730 }
1731
1732 if (!just_check && previous_trans != transformation::none)
1733 untransform(true);
1734
1735 set<equipment_type> rem_stuff = _init_equipment_removal(which_trans);
1736
1737 // if going into lichform causes us to drop a holy weapon with consequences
1738 // for unwielding (e.g. contam), warn first.
1739 item_def nil_item;
1740 nil_item.link = -1;
1741 if (just_check && !involuntary
1742 && which_trans == transformation::lich && rem_stuff.count(EQ_WEAPON)
1743 && !check_old_item_warning(nil_item, OPER_WIELD, true))
1744 {
1745 canned_msg(MSG_OK);
1746 return false;
1747 }
1748
1749 if (which_trans == transformation::appendage)
1750 {
1751 // Need to set the appendages here for messaging
1752 for (mutation_type app : appendages)
1753 {
1754 if (physiology_mutation_conflict(app)
1755 || you.get_base_mutation_level(app) > 0)
1756 {
1757 continue;
1758 }
1759 you.props[APPENDAGE_KEY].get_vector().push_back(app);
1760 dprf("Setting appendage mutation %s.", mutation_name(app));
1761 }
1762
1763 if (you.props[APPENDAGE_KEY].get_vector().empty())
1764 {
1765 msg = "You have no appropriate body parts free.";
1766 success = false; // XXX: VERY dubious, since an untransform occurred
1767 }
1768
1769 if (just_check || !success)
1770 {
1771 you.props.erase(APPENDAGE_KEY);
1772 dprf("Erasing, just check");
1773 }
1774 dprf("Set appendages");
1775 }
1776
1777 if (!success)
1778 {
1779 // Message is not printed if we're updating fail_reason.
1780 if (fail_reason)
1781 *fail_reason = msg;
1782 else if (!involuntary)
1783 mpr(msg);
1784 return false;
1785 }
1786
1787 // If we're just pretending return now.
1788 if (just_check)
1789 return true;
1790
1791 // All checks done, transformation will take place now.
1792 you.redraw_evasion = true;
1793 you.redraw_armour_class = true;
1794 you.wield_change = true;
1795 quiver::set_needs_redraw();
1796
1797 if (form_changed_physiology(which_trans))
1798 merfolk_stop_swimming();
1799
1800 if (which_trans == transformation::storm)
1801 set_airform_power(pow);
1802
1803 // Give the transformation message.
1804 mpr(get_form(which_trans)->transform_message(previous_trans));
1805
1806 // Update your status.
1807 // Order matters here, take stuff off (and handle attendant HP and stat
1808 // changes) before adjusting the player to be transformed.
1809 _remove_equipment(rem_stuff, which_trans);
1810
1811 you.form = which_trans;
1812 you.set_duration(DUR_TRANSFORMATION, _transform_duration(which_trans, pow));
1813 update_player_symbol();
1814
1815 you.props[TRANSFORM_POW_KEY] = pow;
1816
1817 const int str_mod = get_form(which_trans)->str_mod;
1818 const int dex_mod = get_form(which_trans)->dex_mod;
1819
1820 if (str_mod)
1821 notify_stat_change(STAT_STR, str_mod, true);
1822
1823 if (dex_mod)
1824 notify_stat_change(STAT_DEX, dex_mod, true);
1825
1826 calc_hp(true, false);
1827
1828 if (you.digging && !form_keeps_mutations(which_trans))
1829 {
1830 mpr("Your mandibles meld away.");
1831 you.digging = false;
1832 }
1833
1834 // Extra effects
1835 switch (which_trans)
1836 {
1837 case transformation::statue:
1838 if (you.duration[DUR_ICY_ARMOUR])
1839 {
1840 mprf(MSGCH_DURATION, "Your new body cracks your icy armour.");
1841 you.duration[DUR_ICY_ARMOUR] = 0;
1842 }
1843 break;
1844
1845 case transformation::spider:
1846 leave_web();
1847 break;
1848
1849 case transformation::tree:
1850 mpr("Your roots penetrate the ground.");
1851 if (you.duration[DUR_TELEPORT])
1852 {
1853 you.duration[DUR_TELEPORT] = 0;
1854 mpr("You feel strangely stable.");
1855 }
1856 you.duration[DUR_FLIGHT] = 0;
1857 // break out of webs/nets as well
1858
1859 case transformation::dragon:
1860 if (you.attribute[ATTR_HELD])
1861 {
1862 trap_def *trap = trap_at(you.pos());
1863 if (trap && trap->type == TRAP_WEB)
1864 {
1865 mpr("You shred the web into pieces!");
1866 destroy_trap(you.pos());
1867 }
1868 int net = get_trapping_net(you.pos());
1869 if (net != NON_ITEM)
1870 {
1871 mpr("The net rips apart!");
1872 destroy_item(net);
1873 }
1874
1875 stop_being_held();
1876 }
1877 break;
1878
1879 case transformation::lich:
1880 if (you.duration[DUR_WEREBLOOD])
1881 {
1882 you.duration[DUR_WEREBLOOD] = 0;
1883 mpr("Your lifeless body cannot sustain the wereblood!");
1884 }
1885 you.redraw_status_lights = true;
1886 break;
1887
1888 case transformation::appendage:
1889 {
1890 auto& apps = you.props[APPENDAGE_KEY].get_vector();
1891 for (auto app : apps)
1892 {
1893 const mutation_type mut = static_cast<mutation_type>(app.get_int());
1894 you.mutation[mut] = _beastly_level(mut);
1895 }
1896 }
1897 break;
1898
1899 case transformation::shadow:
1900 drain_player(25, true, true);
1901 if (you.invisible())
1902 mpr("You fade into the shadows.");
1903 else
1904 mpr("You feel less conspicuous.");
1905 break;
1906
1907 default:
1908 break;
1909 }
1910
1911 // Stop constricting if we can no longer constrict. If any size-changing
1912 // transformations were to allow constriction, we would have to check
1913 // relative sizes as well. Likewise, if any transformations were to allow
1914 // normally non-constricting players to constrict, this would need to
1915 // be changed.
1916 if (!form_keeps_mutations(which_trans))
1917 you.stop_directly_constricting_all(false);
1918
1919 // Stop being constricted if we are now too large.
1920 if (you.is_directly_constricted())
1921 {
1922 actor* const constrictor = actor_by_mid(you.constricted_by);
1923 ASSERT(constrictor);
1924
1925 if (you.body_size(PSIZE_BODY) > constrictor->body_size(PSIZE_BODY))
1926 you.stop_being_constricted();
1927 }
1928
1929
1930 // If we are no longer living, end an effect that afflicts only the living
1931 if (you.duration[DUR_FLAYED] && !(you.holiness() & MH_NATURAL))
1932 {
1933 // Heal a little extra if we gained max hp from this transformation
1934 if (form_hp_mod() != 10)
1935 {
1936 int dam = you.props["flay_damage"].get_int();
1937 you.heal((dam * form_hp_mod() / 10) - dam);
1938 }
1939 heal_flayed_effect(&you);
1940 }
1941
1942 // This only has an effect if the transformation happens passively,
1943 // for example if Xom decides to transform you while you're busy
1944 // running around or butchering corpses.
1945 // If you're turned into a tree, you stop taking stairs.
1946 stop_delay(which_trans == transformation::tree);
1947
1948 if (crawl_state.which_god_acting() == GOD_XOM)
1949 you.transform_uncancellable = true;
1950
1951 // Land the player if we stopped flying.
1952 if (was_flying && !you.airborne())
1953 move_player_to_grid(you.pos(), false);
1954
1955 // Stop emergency flight if it's activated and this form can fly
1956 if (you.props[EMERGENCY_FLIGHT_KEY]
1957 && form_can_fly()
1958 && you.airborne())
1959 {
1960 you.props.erase(EMERGENCY_FLIGHT_KEY);
1961 }
1962
1963 // Update merfolk swimming for the form change.
1964 if (you.has_innate_mutation(MUT_MERTAIL))
1965 merfolk_check_swimming(false);
1966
1967 // Update skill boosts for the current state of equipment melds
1968 // Must happen before the HP check!
1969 ash_check_bondage();
1970
1971 if (you.hp <= 0)
1972 {
1973 ouch(0, KILLED_BY_FRAILTY, MID_NOBODY,
1974 make_stringf("gaining the %s transformation",
1975 transform_name(which_trans)).c_str());
1976 }
1977
1978 return true;
1979 }
1980
1981 /**
1982 * End the player's transformation and return them to their normal
1983 * form.
1984 * @param skip_move If true, skip any move that was in progress before
1985 * the transformation ended.
1986 */
untransform(bool skip_move)1987 void untransform(bool skip_move)
1988 {
1989 const bool was_flying = you.airborne();
1990
1991 // Must be unset first or else infinite loops might result. -- bwr
1992 const transformation old_form = you.form;
1993
1994 quiver::set_needs_redraw();
1995 you.redraw_evasion = true;
1996 you.redraw_armour_class = true;
1997 you.wield_change = true;
1998 if (!form_can_wield(old_form))
1999 you.received_weapon_warning = false;
2000 if (you.props.exists(TRANSFORM_POW_KEY))
2001 you.props.erase(TRANSFORM_POW_KEY);
2002 if (you.props.exists(HYDRA_FORM_HEADS_KEY))
2003 you.props.erase(HYDRA_FORM_HEADS_KEY);
2004 if (you.props.exists(AIRFORM_POWER_KEY))
2005 you.props.erase(AIRFORM_POWER_KEY);
2006
2007 // We may have to unmeld a couple of equipment types.
2008 set<equipment_type> melded = _init_equipment_removal(old_form);
2009
2010 you.form = transformation::none;
2011 you.duration[DUR_TRANSFORMATION] = 0;
2012 update_player_symbol();
2013
2014 if (old_form == transformation::appendage)
2015 {
2016 const auto& apps = you.props[APPENDAGE_KEY].get_vector();
2017 for (auto mut : apps)
2018 {
2019 const mutation_type app = static_cast<mutation_type>(mut.get_int());
2020 const int levels = you.get_base_mutation_level(app);
2021 // Preserve extra mutation levels acquired after transforming.
2022 const int extra = max(0, levels - you.get_innate_mutation_level(app)
2023 - _beastly_level(app));
2024 you.mutation[app] = you.get_innate_mutation_level(app) + extra;
2025
2026 // The mutation might have been removed already by a conflicting
2027 // demonspawn innate mutation; no message then.
2028 if (levels)
2029 {
2030 const char * const verb = you.has_mutation(app) ? "shrink"
2031 : "disappear";
2032 mprf(MSGCH_DURATION, "Your %s %s%s.",
2033 mutation_name(app), verb,
2034 app == MUT_TENTACLE_SPIKE ? "s" : "");
2035 }
2036 }
2037 you.props.erase(APPENDAGE_KEY);
2038 }
2039
2040 calc_hp(true, false);
2041
2042 const string message = get_form(old_form)->get_untransform_message();
2043 if (!message.empty())
2044 mprf(MSGCH_DURATION, "%s", message.c_str());
2045
2046 const int str_mod = get_form(old_form)->str_mod;
2047 const int dex_mod = get_form(old_form)->dex_mod;
2048
2049 if (str_mod)
2050 notify_stat_change(STAT_STR, -str_mod, true);
2051
2052 if (dex_mod)
2053 notify_stat_change(STAT_DEX, -dex_mod, true);
2054
2055 // If you're a mer in water, boots stay melded even after the form ends.
2056 if (you.fishtail)
2057 {
2058 melded.erase(EQ_BOOTS);
2059 const item_def* arm = you.slot_item(EQ_BODY_ARMOUR, true);
2060 if (arm && is_unrandom_artefact(*arm, UNRAND_LEAR))
2061 {
2062 // I hate you, King Lear.
2063 melded.erase(EQ_HELMET);
2064 melded.erase(EQ_GLOVES);
2065 melded.erase(EQ_BODY_ARMOUR);
2066 }
2067 }
2068 _unmeld_equipment(melded);
2069
2070 // Update skill boosts for the current state of equipment melds
2071 // Must happen before the HP check!
2072 ash_check_bondage();
2073
2074 if (!skip_move)
2075 {
2076 // Land the player if we stopped flying.
2077 if (is_feat_dangerous(env.grid(you.pos())))
2078 enable_emergency_flight();
2079 else if (was_flying && !you.airborne())
2080 move_player_to_grid(you.pos(), false);
2081
2082 // Update merfolk swimming for the form change.
2083 if (you.has_innate_mutation(MUT_MERTAIL))
2084 merfolk_check_swimming(false);
2085 }
2086
2087 #ifdef USE_TILE
2088 if (you.has_innate_mutation(MUT_MERTAIL))
2089 init_player_doll();
2090 #endif
2091
2092 // If nagas wear boots while transformed, they fall off again afterwards:
2093 // I don't believe this is currently possible, and if it is we
2094 // probably need something better to cover all possibilities. -bwr
2095
2096 // Removed barding check, no transformed creatures can wear barding
2097 // anyway.
2098 // *coughs* Ahem, blade hands... -- jpeg
2099 if (you.wear_barding())
2100 {
2101 const int arm = you.equip[EQ_BOOTS];
2102
2103 if (arm != -1 && you.inv[arm].sub_type == ARM_BOOTS)
2104 remove_one_equip(EQ_BOOTS);
2105 }
2106
2107 if (you.hp <= 0)
2108 {
2109 ouch(0, KILLED_BY_FRAILTY, MID_NOBODY,
2110 make_stringf("losing the %s form",
2111 transform_name(old_form)).c_str());
2112 }
2113
2114 // Stop being constricted if we are now too large.
2115 if (you.is_directly_constricted())
2116 {
2117 actor* const constrictor = actor_by_mid(you.constricted_by);
2118 if (you.body_size(PSIZE_BODY) > constrictor->body_size(PSIZE_BODY))
2119 you.stop_being_constricted();
2120 }
2121
2122 you.turn_is_over = true;
2123 if (you.transform_uncancellable)
2124 you.transform_uncancellable = false;
2125 }
2126
emergency_untransform()2127 void emergency_untransform()
2128 {
2129 mpr("You quickly transform back into your natural form.");
2130 untransform(true); // We're already entering the water.
2131
2132 if (you.has_innate_mutation(MUT_MERTAIL))
2133 merfolk_start_swimming(false);
2134 }
2135
2136 /**
2137 * Update whether a merfolk should be swimming.
2138 *
2139 * Idempotent, so can be called after position/transformation change without
2140 * redundantly checking conditions.
2141 *
2142 * @param stepped Whether the player is performing a normal walking move.
2143 */
merfolk_check_swimming(bool stepped)2144 void merfolk_check_swimming(bool stepped)
2145 {
2146 const dungeon_feature_type grid = env.grid(you.pos());
2147 if (you.ground_level()
2148 && feat_is_water(grid)
2149 && you.has_mutation(MUT_MERTAIL))
2150 {
2151 merfolk_start_swimming(stepped);
2152 }
2153 else
2154 merfolk_stop_swimming();
2155 }
2156
merfolk_start_swimming(bool stepped)2157 void merfolk_start_swimming(bool stepped)
2158 {
2159 if (you.fishtail)
2160 return;
2161
2162 if (stepped)
2163 mpr("Your legs become a tail as you enter the water.");
2164 else
2165 mpr("Your legs become a tail as you dive into the water.");
2166
2167 if (you.invisible())
2168 mpr("...but don't expect to remain undetected.");
2169
2170 you.fishtail = true;
2171 remove_one_equip(EQ_BOOTS);
2172 you.redraw_evasion = true;
2173
2174 ash_check_bondage();
2175
2176 #ifdef USE_TILE
2177 init_player_doll();
2178 #endif
2179 }
2180
merfolk_stop_swimming()2181 void merfolk_stop_swimming()
2182 {
2183 if (!you.fishtail)
2184 return;
2185 you.fishtail = false;
2186 unmeld_one_equip(EQ_BOOTS);
2187 you.redraw_evasion = true;
2188
2189 ash_check_bondage();
2190
2191 #ifdef USE_TILE
2192 init_player_doll();
2193 #endif
2194 }
2195
vampire_update_transformations()2196 void vampire_update_transformations()
2197 {
2198 const undead_form_reason form_reason = lifeless_prevents_form();
2199 if (form_reason != UFR_GOOD && you.duration[DUR_TRANSFORMATION])
2200 {
2201 print_stats();
2202 update_screen();
2203 mprf(MSGCH_WARN,
2204 "Your blood-%s body can't sustain your transformation.",
2205 form_reason == UFR_TOO_DEAD ? "deprived" : "filled");
2206 untransform();
2207 }
2208 }
2209
2210 // TODO: dataify? move to member functions?
form_base_movespeed(transformation tran)2211 int form_base_movespeed(transformation tran)
2212 {
2213 // statue form is handled as a multiplier in player_speed, not a movespeed.
2214 if (tran == transformation::bat)
2215 return 5; // but allowed minimum is six
2216 else if (tran == transformation::pig)
2217 return 7;
2218 else
2219 return 10;
2220 }
2221